juvf 17 1 декабря, 2011 Опубликовано 1 декабря, 2011 · Жалоба Как переключаться на другую задачу после прерывания? есть фоновая задача, мигает лампочкой. есть более приоритетная задача для работы с 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() блокирует прерванную задачу? Как правильно сделать так, чтоб при выходе из обработчика прерывания управление передавалось не прерванной задаче, а задаче готовой к выполнению с самым большим приоритетом? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sysel 0 1 декабря, 2011 Опубликовано 1 декабря, 2011 · Жалоба Что за функция vTaskSwitchContext()? Как правильно ею пользоваться? Почему taskYIELD() блокирует прерванную задачу? Как правильно сделать так, чтоб при выходе из обработчика прерывания управление передавалось не прерванной задаче, а задаче готовой к выполнению с самым большим приоритетом? taskYIELD можно вызывать только в потоках. В прерываниях нельзя. vTaskSwitchContext() - на основе данных о потоках (приоритеты, блокировки) вычисляет какой поток надо запустить и помещает указатель на него в pxCurrentTCB. В зависимости от порта ФрииРТОС, вызов vTaskSwitchContext() в обработчике прерывания тоже может быть не корректен. Вызов его осуществляется на уровне абстракции от железа (port.c и portasm.asm), там где скрещивается ФрииРТОС с конкретным железом. посмотрите в файле portmacro.h , там должен быть макрос типа "portEND_SWITCHING_ISR", вот его и вызывайте. P.S. Что за процессор у Вас? Какой порт ФрииРТОС используете? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
juvf 17 2 декабря, 2011 Опубликовано 2 декабря, 2011 · Жалоба Что за процессор у Вас? Какой порт ФрииРТОС используете? 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(). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sysel 0 2 декабря, 2011 Опубликовано 2 декабря, 2011 · Жалоба Nios II, порт ...\FreeRTOS\Source\portable\GCC\NiosII С этим портом не работал, точно не скажу. Хотя наверно элегантнее будет проверять так ... xQueueSendFromISR(uart232Queue, &byte, &xHigherPriorityTaskWoken); portEND_SWITCHING_ISR(xHigherPriorityTaskWoken == pdTRUE); ... Это наиболее правильный метод. Наверно для некоторых платформ нельзя. В статьях КиТ по фрииртос (№7 стр 26) сказано про переключение контекста в прерываниях.... Это зависит от того, как организованы прерывания на конкретной платформе (разрешение вложенности, поддерживаются ли софтовые прерывания, сохраняется ли контекст задачи перед вызовом обработчика или нет и т.д.) IMHO, полезно бы было ФриРТОС-овцам во всех портах реализовать макрос "portEND_SWITCHING_ISR", а уже внутри вызывать либо ТаскСвитч либо ТаскЙолд, дабы народ не путать. Почитайте эту статью про внутреннее устройство FreeRTOS. Начинаешь лучше понимать суть проблем, когда знаешь как оно внутри работает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
juvf 17 2 декабря, 2011 Опубликовано 2 декабря, 2011 · Жалоба полезно бы было ФриРТОС-овцам во всех портах реализовать макрос "portEND_SWITCHING_ISR", а уже внутри вызывать либо ТаскСвитч либо ТаскЙолд, дабы народ не путать.+1. Я вообще удивлён, что этого не сделано до сих пор. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться