реклама на сайте
подробности

 
 
> Cortex M3, PendSV и переключение контекста
alt3857
сообщение Jun 8 2011, 11:13
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 94
Регистрация: 21-04-10
Пользователь №: 56 794



Привет!
В Cortex-M3 есть прерывание PendSV, в чем его основная цель? В доках нашел "PendSV is an interrupt-driven request for system-level service. In an OS environment, use PendSV for context switching when no other exception is active". Т.е. как я понял оно нужно (рекомендовано ARM-ом) для выполнения переключения контекста операционной системой. Но в операционке все равно задействован SysTick Timer и его прерывание для проверки необходимости переключения на каждый тик, почему контекст нельзя переключать в нем, зачем дополнительно нужно PendSV?
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
brag
сообщение Jun 14 2011, 21:16
Сообщение #2


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



конкретный пример вотъ. код вроде простой и понятный...

собственно переключение. приоритет самый низкий
Код
F_NAKED void ePendSV(void){
    register U32 rpsp asm("r3");
    asm volatile(" mrs %0,PSP; stmdb %0!,{r4-r11,lr}" :"=r"(rpsp));
    pRunTcb->psp=rpsp;
    pRunTcb=pReadyTcb;
    rpsp=pRunTcb->psp;
    asm volatile(" ldmia %0!,{r4-r11,lr}; msr PSP,%0; bx lr" :"+r"(rpsp));
}

naked и асм.вставки тк gcc тупой не умеет юзать ldm/stm. а кусок сишного кода тк леньки мне и синтакс gas - бей головой дуба :D писать не удобно
также тут исключен код, перегружающий MPU регионы, нету у STM32F1 MPU. на NXP моя ось еще и защищенная wink.gif

постановка задачи,готовой к выполнению в очередь. используется внутри практически всех системных функций (CreateThread,OpenMutex итд). приоритет этих функций всегда выше или равен PendSV.
Код
void tcbEnqueueReady(t_bragOsTcb *tcb){
    U32 prio;
    prio=tcb->priority;
    cdllEnqueue(&readyQueue[prio],&tcb->queueNode);
    readyPrioMsk|=1<<(31-prio);
    if(prio<pReadyTcb->priority){
        pReadyTcb=tcb;
        PendSVset();
    }
}


Системные функции могут вызыватся только:
1. из SVC, в данном случаи приоритет выше, чем у PendSV. сделаете иначе - попадете на оооочень неприятные грабли! лень расписывать(много невсемпонятного текста) почему, но скажу пару ключевых слов: Приоритет, Стек, Tail-chainning. Если интересно - порисуйте диаграмки последовательности выполнения и все станет понятно.
2. из Systick. приоритет равен PendSV
Ессно выше приведенный код получается автоматически защищен от race-conditions.

Удаление задачи из очереди. Здесь PendSVset выполняется всегда, тк так сложилось, что у меня эта функция удаляет из очереди только ту задачу, которая в данный момент выполняется. но с ее помощью можно удалить любую задачу из очереди, при этом можно сделать проверку, чтобы даром не выполнять пустое переключение контекста,не влияющее на ход работы системы.
Код
void tcbDequeueReady(t_bragOsTcb *tcb){
    U32 prio;
    cdllRemove(&tcb->queueNode);
    prio=tcb->priority;
    if(cdllIsEmpty(&readyQueue[prio]))readyPrioMsk&=~(1<<(31-prio));
    pReadyTcb=getNextReadyTcb();
    PendSVset();
}


cdllХххх - работа с обычным двусвязным списком.
getNextReadyTcb - достает из головы этого самого списка(у меня их 32,на каждый тредовый приоритет свой список,выбирается не пустой список самого высокого приоритета) адрес tcb
PendSVset используется только в этих двух функциях, ну и еще при инициализации системы, чтобы переключится на первый тред.

ну и самый сок, добавление запроса в lock-free очередь. может использоватся любым прерыванием с любым приоритетом.
Код
int SrqEnqueue(U32 a0,U32 a1,U32 svc){
    register U32 r0 asm("r0");
    register U32 r1 asm("r1");
    U32 tail,newtail;
    
   // lockless enqueue
    do{
        asm volatile("ldrex %0,%1" :"=r"(tail) :"m"(srqQueue.tail));
        newtail=(tail+1)%MAX_SRQ_QUEUE_ITEMS;
        if(newtail==srqQueue.head)return ERR_QUEUE_FULL;
        asm volatile("strex %0,%2,%1" :"=&r"(r),"=m"(srqQueue.tail) :"r"(newtail));
    }while(r);
    
   // write data
    r0=a0;r1=a1;
    asm volatile("stmia %3,{%0,%1,%2}" : :"r"(r0),"r"(r1),"r"(svc),"r"(&srqQueue.buf[tail]) :"memory");
    PendSTset();
    return 0;
}

MAX_SRQ_QUEUE_ITEMS кратно степени двойки - % заменяется компиллером на обычный AND.
PendSTset - гыгы sm.gif там выгрузка этой очереди, и системный таймер там же. не хотелось нагружать маленький красивенький pendsv всякой ерундой, пусть pendsv будет именно pendsv и не более wink.gif
Код
void eSystick(void){
.....    блаблалбла-декларация....

    SrqDequeueRun();
    if(!IsSystick())return;

.....      блаблабла--системный таймер........

IsSystick - это действительно таймер тикнул?

выгрузка из очереди. wait-free. выполняется только из eSystick. здесь все просто,никаких хитростей.
Код
void SrqDequeueRun(void){
    register U32 r0 asm("r0");
    register U32 r1 asm("r1");
    U32 a0,a1,svc;
    t_srqItem *data;
    U32 head;
    
    head=srqQueue.head;
    if(head==srqQueue.tail)return;
    
    while(head!=srqQueue.tail){
        data=&srqQueue.buf[head];
        head=(head+1)%MAX_SRQ_QUEUE_ITEMS;
        asm volatile("ldmia %3,{%0,%1,%2}" :"=r"(r0),"=r"(r1),"=r"(svc) :"r"(data));
        a0=r0;a1=r1;
        /*if(svc>=sizeof(svcTable)/sizeof(t_Callback))*/
        a0=((int(*)(U32,U32))svcTable[svc])(a0,a1);
    }
    srqQueue.head=head;
}


на RVCT все обходится почти без асма с тем же результатом, он ldm/stm нормально генерит. Только алгоритмический код у него немного тормознее выходит (базового кода моей оси это не касается), или это я просто привык писать под gcc,выработалось чутье его алгоритмов оптимизации sm.gif)

Мютексы простые, без наследования приоритетов. Мне это не нужно. и производительность в +
Семафоры есть простые и с таймаутом - примитивы только set,signal,wait,wait+timeout
тред можно только создать и убить с другого треда. сам тред может себя остановить на некоторое время или выгрузится. также его могут убить обработчики fault-ов через ту же lock-free srq.
Ну и в принципе все.
Никаких критических секций, никаких циклов поиска итп.
KIS - keep it simple wink.gif
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 23rd July 2025 - 10:53
Рейтинг@Mail.ru


Страница сгенерированна за 0.01383 секунд с 7
ELECTRONIX ©2004-2016