Jump to content

    

Переключение задачи по прерыванию.

Как переключаться на другую задачу после прерывания?

 

есть фоновая задача, мигает лампочкой. есть более приоритетная задача для работы с UART. Задача для уарта ждет появления байта в очереди

 

void taskRS232(void *pvParameters)
{
    alt_u8 byte;
    for(;;)
    {
        xQueueReceive(uart232Queue, &byte, portMAX_DELAY);
        handler232();
    }
    vTaskDelete( NULL );
}

 

посылаю в устройство байт. попадаю в прерывание по приему. в конце прерывания проверяю нет ли более приоритетной задачи чем прерванная и если есть то переключаю контекст

 

void UartPC::uartInt(void *context)//прерывание по RS-232 от bawdc
{
    static alt_u8 byte;
    static portBASE_TYPE xHigherPriorityTaskWoken;
    xHigherPriorityTaskWoken = pdFALSE;
    alt_u16 status = IORD_ALTERA_AVALON_UART_STATUS(UART_BASE);
    if(status & ALTERA_AVALON_UART_STATUS_RRDY_MSK)
    {//прерывание по приему
        byte = IORD_ALTERA_AVALON_UART_RXDATA(UART_BASE);
        xQueueSendFromISR(uart232Queue, &byte, &xHigherPriorityTaskWoken);
    }
    if(xHigherPriorityTaskWoken == pdTRUE)
        taskYIELD();
}

 

задача ожидавшая появление в очереди uart232Queue байта разблокируется и начинает работать. После обработки ожидает следующий байт в очереди. Почему то попав в ожидание xQueueReceive(uart232Queue, &byte, portMAX_DELAY) после taskYIELD() управление задаче по миганию лампочки не передается. выполняется пустая задача. мигание лампочки в состоянии блокировки.

 

Убрал из обработчика прерывания переключение контекста taskYIELD();. Всё заработало, но медленно. видно что после прерывания задача уарта не сразу получает управление, наверно по тикам. Дальше стал ковырять исходники и нашел vTaskSwitchContext(). Вставил в конце обработчика прерывания vTaskSwitchContext() вместо taskYIELD() - всё заработало как надо. переключение происходит сразу по выходу из обработчика-прерывания.

 

Что за функция vTaskSwitchContext()? Как правильно ею пользоваться? Почему taskYIELD() блокирует прерванную задачу?

 

Как правильно сделать так, чтоб при выходе из обработчика прерывания управление передавалось не прерванной задаче, а задаче готовой к выполнению с самым большим приоритетом?

Share this post


Link to post
Share on other sites
Что за функция vTaskSwitchContext()? Как правильно ею пользоваться? Почему taskYIELD() блокирует прерванную задачу?

Как правильно сделать так, чтоб при выходе из обработчика прерывания управление передавалось не прерванной задаче, а задаче готовой к выполнению с самым большим приоритетом?

taskYIELD можно вызывать только в потоках. В прерываниях нельзя.

 

vTaskSwitchContext() - на основе данных о потоках (приоритеты, блокировки) вычисляет какой поток надо запустить и помещает указатель на него в pxCurrentTCB.

В зависимости от порта ФрииРТОС, вызов vTaskSwitchContext() в обработчике прерывания тоже может быть не корректен. Вызов его осуществляется на уровне абстракции от железа (port.c и portasm.asm), там где скрещивается ФрииРТОС с конкретным железом.

 

посмотрите в файле portmacro.h , там должен быть макрос типа "portEND_SWITCHING_ISR", вот его и вызывайте.

 

P.S. Что за процессор у Вас? Какой порт ФрииРТОС используете?

Share this post


Link to post
Share on other sites
Что за процессор у Вас? Какой порт ФрииРТОС используете?

Nios II, порт ...\FreeRTOS\Source\portable\GCC\NiosII

 

посмотрите в файле portmacro.h , там должен быть макрос типа "portEND_SWITCHING_ISR", вот его и вызывайте.

Ага, спасибо..... нашел вот что:

extern void vTaskSwitchContext( void );
#define portYIELD()                                    asm volatile ( "trap" );
#define portEND_SWITCHING_ISR( xSwitchRequired )     if( xSwitchRequired )     vTaskSwitchContext()

Только что за xSwitchRequired? В принцепе в моем случае я уже проверил что переключение требуется и можно смело вызывать напрямую vTaskSwitchContext(). Хотя наверно элегантнее будет проверять так

void UartPC::uartInt(void *context)//прерывание по RS-232 от bawdc
{
    static alt_u8 byte;
    static portBASE_TYPE xHigherPriorityTaskWoken;
    xHigherPriorityTaskWoken = pdFALSE;
    alt_u16 status = IORD_ALTERA_AVALON_UART_STATUS(UART_BASE);
    if(status & ALTERA_AVALON_UART_STATUS_RRDY_MSK)
    {//прерывание по приему
        byte = IORD_ALTERA_AVALON_UART_RXDATA(UART_BASE);
        xQueueSendFromISR(uart232Queue, &byte, &xHigherPriorityTaskWoken);
    }
   portEND_SWITCHING_ISR(xHigherPriorityTaskWoken == pdTRUE);
}

 

ps

taskYIELD можно вызывать только в потоках. В прерываниях нельзя.

Наверно для некоторых платформ нельзя. В статьях КиТ по фрииртос (№7 стр 26) сказано про переключение контекста в прерываниях....

Для принудительного переключения кон-

текста служит API-макрос portSWITCH_

CONTEXT(). Однако для других платформ

имя макроса будет иным, например, для ми-

кроконтроллеров AVR это будет taskYIELD(),

для ARM7 — portYIELD_FROM_ISR().

Share this post


Link to post
Share on other sites
Nios II, порт ...\FreeRTOS\Source\portable\GCC\NiosII

С этим портом не работал, точно не скажу.

Хотя наверно элегантнее будет проверять так

...
xQueueSendFromISR(uart232Queue, &byte, &xHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken == pdTRUE);
...

Это наиболее правильный метод.

Наверно для некоторых платформ нельзя. В статьях КиТ по фрииртос (№7 стр 26) сказано про переключение контекста в прерываниях....

Это зависит от того, как организованы прерывания на конкретной платформе (разрешение вложенности, поддерживаются ли софтовые прерывания, сохраняется ли контекст задачи перед вызовом обработчика или нет и т.д.)

IMHO, полезно бы было ФриРТОС-овцам во всех портах реализовать макрос "portEND_SWITCHING_ISR", а уже внутри вызывать либо ТаскСвитч либо ТаскЙолд, дабы народ не путать.

Почитайте эту статью про внутреннее устройство FreeRTOS. Начинаешь лучше понимать суть проблем, когда знаешь как оно внутри работает.

Share this post


Link to post
Share on other sites
полезно бы было ФриРТОС-овцам во всех портах реализовать макрос "portEND_SWITCHING_ISR", а уже внутри вызывать либо ТаскСвитч либо ТаскЙолд, дабы народ не путать.
+1. Я вообще удивлён, что этого не сделано до сих пор.

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this