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

 
 
 
Reply to this topicStart new topic
> Переключение контекста
juvf
сообщение Dec 14 2013, 19:53
Сообщение #1


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

Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045



Порт FreeRTOS для stm32 IAR. Обнаружил зависание одной самой приоритетной задачи. Статус READY, но на неё переключения нет.

Оставил одну задачу в проекте с приоритетом 3. запускаю в дебаге.... задача в блокированном состоянии, ждет байт в очереди.

в прерывании выдаю посылаю байт в очередь.

Код
void USART1_IRQHandler(void)
{
    static uint8_t byte;
    static portBASE_TYPE xHigherPriorityTaskWoken;
    xHigherPriorityTaskWoken = pdFALSE;
    if(USART1_SR_bit.RXNE == 1)
    { //прерывание по приему
        byte = USART1_DR; //флаг прерывания сбрасывается при чтении регистра USART1_DR
        xQueueSendToBackFromISR(uart485Queue, &byte, &xHigherPriorityTaskWoken);
    }
    //portEND_SWITCHING_ISR(xHigherPriorityTaskWoken == pdTRUE );
}


До первого входа в прерывание задача в блокированном состоянии. После выдачи байта в очередь xQueueSendToBackFromISR(uart485Queue...) задача сразу переходит в состояние READY. Если в конце прерывания вызвать принудительное переключение контекста, то переключение происходит. Если не вызывать, то теоретически, переключение контекста должно произойти во время системного тика, но переключения не происходит. Всегда крутится задача IDLE, а моя задача находится в состоянии готовности и не выполняется. Посмотрел исходник обработчика системного тика - там только переключение на задачи, которые задержаны функциями delay. А где вызов планировщика и проверка приоритетных задач на готовность? Где переключение контекста?
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Dec 14 2013, 21:10
Сообщение #2


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



А зачем же вы закомментировали portEND_SWITCHING_ISR?
Я не знаток FreeRTOS, но, по-моему, именно этот макрос взводит флажок вызова прерывания перепланировки.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
juvf
сообщение Dec 15 2013, 04:12
Сообщение #3


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

Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045



Цитата(AHTOXA @ Dec 15 2013, 02:10) *
А зачем же вы закомментировали portEND_SWITCHING_ISR?

portEND_SWITCHING_ISR - это принудительное переключение контекста. без него должно переключится в конце системного тика
Эскизы прикрепленных изображений
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
juvf
сообщение Dec 15 2013, 09:55
Сообщение #4


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

Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045



Посмотрел исходники 7.6.0 для несколькоих платформ - нет в обработчике прерывания системного таймера вызова планировщика.
Вот так выглядит обработчик для Cortex-M3 ( port.c )
Код
void xPortSysTickHandler( void )
{
    /* The SysTick runs at the lowest interrupt priority, so when this interrupt
    executes all interrupts must be unmasked.  There is therefore no need to
    save and then restore the interrupt mask value as its value is already
    known. */
    ( void ) portSET_INTERRUPT_MASK_FROM_ISR();
    {
        /* Increment the RTOS tick. */
        if( xTaskIncrementTick() != pdFALSE )
        {
            /* A context switch is required.  Context switching is performed in
            the PendSV interrupt.  Pend the PendSV interrupt. */
            portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
        }
    }
    portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 );
}


А вот как выглядит тот же обработчик в версии 7.2.0
Код
void xPortSysTickHandler( void )
{
unsigned long ulDummy;

    /* If using preemption, also force a context switch. */
    #if configUSE_PREEMPTION == 1
        *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
    #endif

    ulDummy = portSET_INTERRUPT_MASK_FROM_ISR();
    {
        vTaskIncrementTick();
    }
    portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy );
}

В новой версии переключение контекста происходит только на задачи, которые задержанны всякими делаями. В новом xTaskIncrementTick() не нашол я перебор всех задач ипроверку их на готовгность. Только перебор задержанных задач. Толи это бага, толи это новая фича и больше нет вытесняющей многозадачности ((
Go to the top of the page
 
+Quote Post
Lagman
сообщение Dec 15 2013, 12:48
Сообщение #5


Знающий
****

Группа: Свой
Сообщений: 875
Регистрация: 28-10-05
Пользователь №: 10 245



покажите как вы создаете задачу (с какими параметрами) и саму задачу.
И еще уровни приоритета прерываний. (configKERNEL_INTERRUPT_PRIORITY , configMAX_SYSCALL_INTERRUPT_PRIORITY)
Go to the top of the page
 
+Quote Post
juvf
сообщение Dec 15 2013, 14:28
Сообщение #6


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

Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045



Цитата(Lagman @ Dec 15 2013, 17:48) *
покажите как вы создаете задачу (с какими параметрами) и саму задачу.
И еще уровни приоритета прерываний. (configKERNEL_INTERRUPT_PRIORITY , configMAX_SYSCALL_INTERRUPT_PRIORITY)

Код
#define configUSE_PREEMPTION        1
#define configUSE_IDLE_HOOK            0
#define configUSE_TICK_HOOK            0
#define configCPU_CLOCK_HZ            ( ( unsigned long ) 22148100 )    
#define configTICK_RATE_HZ            ( ( portTickType ) 1000 )
#define configMAX_PRIORITIES        ( ( unsigned portBASE_TYPE ) 5 )
#define configMINIMAL_STACK_SIZE    ( ( unsigned short ) 80 )
#define configTOTAL_HEAP_SIZE        ( ( size_t ) 3500 )
#define configMAX_TASK_NAME_LEN        ( 16 )
#define configUSE_TRACE_FACILITY    0
#define configUSE_16_BIT_TICKS        0
#define configIDLE_SHOULD_YIELD        1

#define configUSE_MUTEXES            1
#define configCHECK_FOR_STACK_OVERFLOW        1

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES         0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */

#define INCLUDE_vTaskPrioritySet        0
#define INCLUDE_uxTaskPriorityGet        0
#define INCLUDE_vTaskDelete                0
#define INCLUDE_vTaskCleanUpResources    0
#define INCLUDE_vTaskSuspend            0
#define INCLUDE_vTaskDelayUntil            1
#define INCLUDE_vTaskDelay                1
#define INCLUDE_uxTaskGetStackHighWaterMark 1

/* This is the raw value as per the Cortex-M3 NVIC.  Values can be 255
(lowest) to 0 (1?) (highest). */
#define configKERNEL_INTERRUPT_PRIORITY         255
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY     191 /* equivalent to 0xb0, or priority 11. */


/* This is the value being used as per the ST library which permits 16
priority values, 0 to 15.  This must correspond to the
configKERNEL_INTERRUPT_PRIORITY setting.  Here 15 corresponds to the lowest
NVIC value of 255. */
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY    15


Код
int main()
{
    systemInit();
    portBASE_TYPE pTask;
    pTask = xTaskCreate(uartTask, (const signed char* )"uartTask", 130, 0, 3, 0);
    if(pTask == pdPASS )
        vTaskStartScheduler();
    return 0;
}


Обработчик прерывание см выше void USART1_IRQHandler(void).

Код
void uartTask(void *parametr)
{
    static uint16_t countRx;
    uint8_t byte;
    for(;;)
    {
        xQueueReceive(uart485Queue, &byte, portMAX_DELAY);
        countRx = 0;
        rxBuffer[countRx] = byte;
        if(rxBuffer[countRx++] == '#')
        {
            //Обработчик приема.
        }
        vTaskDelay(1);
    }

}


Задача блокируется га xQueueReceive(uart485Queue, &byte, portMAX_DELAY); После прихода байта из прерывания в очередь отправляется байт. Задача переходить с сотояние готовности. Но если не сделать принудительного переключения в прерывании, то задача больше ни когда не получит управления.

Пересобрал проект на фриртос 7.2.0 - всё заработало. До версии 7.4 включително должно работать. в 7.5 - уже не будет.

вот пример обработчика системного тика для АтМеги в 7.2.0
Код
vPortYieldFromTick:
    portSAVE_CONTEXT; Save the context of the current task.
    call vTaskIncrementTick; Call the timer tick function.
    call vTaskSwitchContext; Call the scheduler.
    portRESTORE_CONTEXT; Restore the context of whichever task the ...
    ret                ; ... scheduler decided should run.

а вот тот же порт, только в 7.6.0
Код
vPortYieldFromTick:
    portSAVE_CONTEXT; Save the context of the current task.
    call xTaskIncrementTick; Call the timer tick function.
    tst r16
    breq SkipTaskSwitch
    call vTaskSwitchContext; Call the scheduler.
SkipTaskSwitch:
    portRESTORE_CONTEXT; Restore the context of whichever task the ...
    ret                ; ... scheduler decided should run.

Видно, то в 7.6 вызывается xTaskIncrementTick, потом делается витвление. В 7.2 ни каких ветвлений. Жесткий вызов vTaskSwitchContext
Go to the top of the page
 
+Quote Post
Lagman
сообщение Dec 15 2013, 15:01
Сообщение #7


Знающий
****

Группа: Свой
Сообщений: 875
Регистрация: 28-10-05
Пользователь №: 10 245



Не увидел где очередь создается!

Приоритет вашего прерывания USART1_IRQHandler должен быть меньше configMAX_SYSCALL_INTERRUPT_PRIORITY, насколько я знаю в cortex m3 число должно быть больше. Какой приоритет (в ядре cortex m3) у прерывания USART1_IRQHandler ?
Вот на эту часть обратите внимание
Код
/* This is the raw value as per the Cortex-M3 NVIC.  Values can be 255
(lowest) to 0 (1?) (highest). */
#define configKERNEL_INTERRUPT_PRIORITY         255
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY     191 /* equivalent to 0xb0, or priority 11. */


/* This is the value being used as per the ST library which permits 16
priority values, 0 to 15.  This must correspond to the
configKERNEL_INTERRUPT_PRIORITY setting.  Here 15 corresponds to the lowest
NVIC value of 255. */
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY    15

http://microsin.net/programming/ARM/freertos-part3.html
Go to the top of the page
 
+Quote Post
juvf
сообщение Dec 15 2013, 15:26
Сообщение #8


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

Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045



Цитата
Какой приоритет (в ядре cortex m3) у прерывания USART1_IRQHandler ?
44 dec

Цитата
Не увидел где очередь создается!

Код
...
xQueueHandle uart485Queue;
...
uart485Queue = xQueueCreate( 10, sizeof(char));


И всё таки..... где в фриртос 7.6.0 вызов планировщика в прерывании системого таймера?
Go to the top of the page
 
+Quote Post
Lagman
сообщение Dec 16 2013, 14:43
Сообщение #9


Знающий
****

Группа: Свой
Сообщений: 875
Регистрация: 28-10-05
Пользователь №: 10 245



http://www.freertos.org/RTOS-Cortex-M3-M4.html
Цитата(juvf @ Dec 15 2013, 19:26) *
И всё таки..... где в фриртос 7.6.0 вызов планировщика в прерывании системого таймера?

Код
void xPortSysTickHandler( void )
{
    /* The SysTick runs at the lowest interrupt priority, so when this interrupt
    executes all interrupts must be unmasked.  There is therefore no need to
    save and then restore the interrupt mask value as its value is already
    known. */
    ( void ) portSET_INTERRUPT_MASK_FROM_ISR();
    {
        /* Increment the RTOS tick. */
        if( xTaskIncrementTick() != pdFALSE )
        {
            /* A context switch is required.  Context switching is performed in
            the PendSV interrupt.  Pend the PendSV interrupt. */
            portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
        }
    }
    portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 );
}

xPortPendSVHandler
Код
xPortPendSVHandler:
    mrs r0, psp                        
    ldr    r3, =pxCurrentTCB            /* Get the location of the current TCB. */
    ldr    r2, [r3]                        

    stmdb r0!, {r4-r11}                /* Save the remaining registers. */
    str r0, [r2]                    /* Save the new top of stack into the first member of the TCB. */

    stmdb sp!, {r3, r14}
    mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
    msr basepri, r0
    bl vTaskSwitchContext            
    mov r0, #0
    msr basepri, r0
    ldmia sp!, {r3, r14}

    ldr r1, [r3]                    
    ldr r0, [r1]                    /* The first item in pxCurrentTCB is the task top of stack. */
    ldmia r0!, {r4-r11}                /* Pop the registers. */
    msr psp, r0                        
    bx r14

PendSV
Я ARM не знаю, но вам эти слова должны быть понятны.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 7th July 2025 - 09:51
Рейтинг@Mail.ru


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