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

 
 
 
Reply to this topicStart new topic
> Переключение задачи по прерыванию.
juvf
сообщение Dec 1 2011, 08:51
Сообщение #1


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

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



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

есть фоновая задача, мигает лампочкой. есть более приоритетная задача для работы с 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() блокирует прерванную задачу?

Как правильно сделать так, чтоб при выходе из обработчика прерывания управление передавалось не прерванной задаче, а задаче готовой к выполнению с самым большим приоритетом?
Go to the top of the page
 
+Quote Post
sysel
сообщение Dec 1 2011, 12:36
Сообщение #2


Знающий
****

Группа: Свой
Сообщений: 601
Регистрация: 3-07-07
Пользователь №: 28 852



Цитата(juvf @ Dec 1 2011, 12:51) *
Что за функция vTaskSwitchContext()? Как правильно ею пользоваться? Почему taskYIELD() блокирует прерванную задачу?
Как правильно сделать так, чтоб при выходе из обработчика прерывания управление передавалось не прерванной задаче, а задаче готовой к выполнению с самым большим приоритетом?

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

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

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

P.S. Что за процессор у Вас? Какой порт ФрииРТОС используете?
Go to the top of the page
 
+Quote Post
juvf
сообщение Dec 2 2011, 02:19
Сообщение #3


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

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



Цитата(sysel @ Dec 1 2011, 17:36) *
Что за процессор у Вас? Какой порт ФрииРТОС используете?

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().
Go to the top of the page
 
+Quote Post
sysel
сообщение Dec 2 2011, 04:50
Сообщение #4


Знающий
****

Группа: Свой
Сообщений: 601
Регистрация: 3-07-07
Пользователь №: 28 852



Цитата(juvf @ Dec 2 2011, 06:19) *
Nios II, порт ...\FreeRTOS\Source\portable\GCC\NiosII

С этим портом не работал, точно не скажу.
Цитата(juvf @ Dec 2 2011, 06:19) *
Хотя наверно элегантнее будет проверять так
Код
...
xQueueSendFromISR(uart232Queue, &byte, &xHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken == pdTRUE);
...

Это наиболее правильный метод.
Цитата(juvf @ Dec 2 2011, 06:19) *
Наверно для некоторых платформ нельзя. В статьях КиТ по фрииртос (№7 стр 26) сказано про переключение контекста в прерываниях....

Это зависит от того, как организованы прерывания на конкретной платформе (разрешение вложенности, поддерживаются ли софтовые прерывания, сохраняется ли контекст задачи перед вызовом обработчика или нет и т.д.)
IMHO, полезно бы было ФриРТОС-овцам во всех портах реализовать макрос "portEND_SWITCHING_ISR", а уже внутри вызывать либо ТаскСвитч либо ТаскЙолд, дабы народ не путать.
Почитайте эту статью про внутреннее устройство FreeRTOS. Начинаешь лучше понимать суть проблем, когда знаешь как оно внутри работает.
Go to the top of the page
 
+Quote Post
juvf
сообщение Dec 2 2011, 06:47
Сообщение #5


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

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



Цитата(sysel @ Dec 2 2011, 10:50) *
полезно бы было ФриРТОС-овцам во всех портах реализовать макрос "portEND_SWITCHING_ISR", а уже внутри вызывать либо ТаскСвитч либо ТаскЙолд, дабы народ не путать.
+1. Я вообще удивлён, что этого не сделано до сих пор.
Go to the top of the page
 
+Quote Post

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

 


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


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