Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: FreeRtos проблемы с очередями
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > FreeRTOS
yanvasiij
Доброго времени суток!

Я не уверен, где конкретно ошибся, но возможно ошибка общего характера и кто-нибудь чего подскажет. Вообщем реализовал функцию, которая посылает запрос на модем и дожидается ответа некоторое время. Сделал это посредством очереди:
CODE
/**
* @brief Отправить строку и дождаться ответа от модема
*
* @param string строка, которую отправляем
* @param dataLen длинна отправляемой строки
* @param answer указатель на строку куда положить ответ
* @param answerLen длинна полученного ответа
* @param timeToWait Время в тиках, указывающее сколько времени ждать ответа от модуля
*/

void bgs2SendString (uint8_t *string, uint32_t dataLen, uint8_t *answer, uint32_t *answerLen, uint32_t timeToWait)
{
uint8_t ch;
*answerLen = 0;
uint32_t len=0;

/**
* Здесь отправляемая строка улетает на модем через уарт
*/
for (uint32_t i = 0; i < dataLen; i++)
{
bgs2Putchar (string[i]);
}
/**
* Здесь дожидаюсь ответа от модема. Если после последнего символа в течении timeToWait не пришел следующий символ,
* то принимаю решение, что строка с ответом полностью получена.
*/
while ( pdTRUE == xQueueReceive( uartRxData, &ch, timeToWait) )
{
putchar(ch);
answer[len] = ch;
len++;
}
/**
* На всякий случай сбрасываю очередь, на тот случай, если вдруг чего осталось в очереди. Хотя по идее такого произойти не должно.
*/
xQueueReset(uartRxData);
*answerLen = len;
}

/**
* @brief Обработчик прерываний, из которого данные попадают в очередь uartRxData
*/
void bgs2UartIrqHandler (void)
{
portBASE_TYPE xHigerPriorityTaskWoken;
#if UART_NUM==0
uint32_t interruptStatus = LPC_UART0->IIR & 0x0E;
#elif UART_NUM==1
uint32_t interruptStatus = LPC_UART1->IIR & 0x0E;
#endif
if (interruptStatus == 0x04)
{
#if UART_NUM==0
uint8_t ch = LPC_UART0->RBR;
#elif UART_NUM==1
uint8_t ch = LPC_UART1->RBR;
#endif

xQueueSendToBackFromISR ( uartRxData, &ch, &xHigerPriorityTaskWoken);

}

/** @brief инициализация железа и очереди */
void bgs2InitUartPort (void)
{
#if USE_FREERTOS==1
uartRxData = xQueueCreate (200, 1);
#endif
#if UART_NUM==0
/* Power Up the UART0 controller. */
LPC_SC->PCONP |= (1 << 3);
/* Configure UART0 pins */
LPC_IOCON->P0_2 = (1 << 9)| 1;
LPC_IOCON->P0_3 = (1 << 9)| 1;
/* Init UART0 */
LPC_UART0->LCR = 0x83;
LPC_UART0->DLL = 24;
LPC_UART0->DLM = 0;
LPC_UART0->FDR = 229;
LPC_UART0->LCR = 0x03;
LPC_UART0->IER |= (1<<0);
NVIC_EnableIRQ(UART0_IRQn);
NVIC_SetPriority(UART0_IRQn, 196);

#elif UART_NUM==1
/* Power Up the UART1 controller. */
LPC_SC->PCONP |= (1 << 4);
/* Configure UART1 pins */
LPC_IOCON->P0_15 = (1<<0)|(0<<1)|(0<<2);
LPC_IOCON->P0_16 = (1<<0)|(0<<1)|(0<<2);
/* Init UART1 */
LPC_UART1->LCR = 0x83;
LPC_UART1->DLL = 24;
LPC_UART1->DLM = 0;
LPC_UART1->FDR = 229;
LPC_UART1->LCR = 0x03;
LPC_UART1->IER |= (1<<0);
NVIC_EnableIRQ(UART1_IRQn);
NVIC_SetPriority(UART1_IRQn, 196);

#endif
}


Все работает, я наблюдаю оживленную беседу между модемом и микроконтроллером в том алгоритме, который и нужен. Но иногда, по непонятной для меня причине, задача (именно одна задача, все остальные задачи работают), занимающаяся "беседой" с модемом "застревает" навсегда на строчке while ( pdTRUE == xQueueReceive( uartRxData, &ch, timeToWait) ) (значение timeToWait = 200 - посмотрел в дебаге). Почему она там залипает мне совершенно непонятно, ведь период ожидания не равен portMAX_DELAY. Задача как будто блокируется, но при этом функция vTaskList показывает, что задача не блокирована (статус == READY) и стека у нее более чем достаточно. Конечно я мог ошибиться где то совсем в другом месте. Но если вдруг это что-то общее, буду признателен за помощь. Ну что это может быть, у меня уже просто нет никаких идей, хоть в петлю лезь! Нравоучения и критика на тему "индуский код" приветствуются sm.gif.

p.s.: Забыл упомянуть: приоритет у задачи занимающейся общением с модемом самый высокий, так что такого, что ее вытеснили быть не может.
Sekat
Цитата(yanvasiij @ Apr 15 2014, 11:57) *
...
p.s.: Забыл упомянуть: приоритет у задачи занимающейся общением с модемом самый высокий, так что такого, что ее вытеснили быть не может.

Посмотрите еще раз внимательно на приоритет обработчика вашего прерывания. По ртосовским правилам он не может быть выше ртосовского, или не используйте вызовы ртосовских функций в этом прерывании - например отдачу семафора.
yanvasiij
Цитата(Sekat @ Apr 15 2014, 14:33) *
Посмотрите еще раз внимательно на приоритет обработчика вашего прерывания. По ртосовским правилам он не может быть выше ртосовского, или не используйте вызовы ртосовских функций в этом прерывании - например отдачу семафора.


Приоритет моего прерывания:
Код
    NVIC_SetPriority(UART0_IRQn, 196);

Ртосовские прерывания ( из файля FreeRtosConfig.h):
Код
#define configKERNEL_INTERRUPT_PRIORITY         255
#define configMAX_SYSCALL_INTERRUPT_PRIORITY     191 /* equivalent to 0xb0, or priority 11. */


Если я правильно понимаю там небольшая путаница в нумерациях: у FreeRtos приоритет тем выше, чем выше его цифра, а у CortexM3 наоборот. Получается, если приоритет у ртосовского прерывания стоит 191 (как у меня), то мне нужно сделать приоритет 192 и более, чтобы все работало. Я так и сделал (у меня 196). Верно?
Lagman
Может в функции bgs2Putchar() что то не то.
Код
    for (uint32_t i = 0; i < dataLen; i++)
{
bgs2Putchar (string[i]);
}
yanvasiij
Цитата(Lagman @ Apr 15 2014, 15:51) *
Может в функции bgs2Putchar() что то не то.
Код
    for (uint32_t i = 0; i < dataLen; i++)
{
bgs2Putchar (string[i]);
}


Код в bgs2Putchar() в студию!
Код
/**
* @brief Отправка одного символа
*
* @param ch символ
*/
void bgs2Putchar (uint8_t ch)
{
#if UART_NUM==0
    while (!(LPC_UART0->LSR & 0x20));
    LPC_UART0->THR = ch;
#elif UART_NUM==1
    while (!(LPC_UART1->LSR & 0x20));
    LPC_UART1->THR = ch;
#endif
}
Lagman
Я писал как в примерах на сайте т.е. добавлял в конце прерывания переключение "portYIELD_FROM_ISR( xHigherPriorityTaskWoken );" после xQueueSendToBackFromISR, но у меня процессор другой и соответсвенно порт ОС. Вот тут есть информация http://microsin.ru/content/view/1306/44/ Еще можно проверить что в таких случая возвращает xQueueSendToBackFromISR, если errQUEUE_FULL - то данные не были отправлены в очередь, так как очередь уже полна.
wolfram
Цитата(yanvasiij @ Apr 15 2014, 16:50) *
Приоритет моего прерывания:
Код
    NVIC_SetPriority(UART0_IRQn, 196);

Я так и сделал (у меня 196). Верно?

Не верно. Нужно например так
Код
    NVIC_SetPriority(UART0_IRQn, 12);

посмотрите внимательно на код функции NVIC_SetPriority
yanvasiij
Цитата(wolfram @ Apr 16 2014, 07:44) *
Не верно. Нужно например так
Код
    NVIC_SetPriority(UART0_IRQn, 12);

посмотрите внимательно на код функции NVIC_SetPriority


Ох! То есть нужно сделать меньше чем значение configMAX_SYSCALL_INTERRUPT_PRIORITY?!!
wolfram
Цитата(yanvasiij @ Apr 16 2014, 13:34) *
Ох! То есть нужно сделать меньше чем значение configMAX_SYSCALL_INTERRUPT_PRIORITY?!!

Да нет же. Нужно сделать приритет больше этой величины
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority 11. */
но при этом меньше чем 2^(__NVIC_PRIO_BITS). У LPC вроде реализовано 5 бит приоритетов. То есть приоритет должен быть меньше 32
yanvasiij
Цитата(wolfram @ Apr 16 2014, 14:26) *
Да нет же. Нужно сделать приритет больше этой величины
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority 11. */
но при этом меньше чем 2^(__NVIC_PRIO_BITS). У LPC вроде реализовано 5 бит приоритетов. То есть приоритет должен быть меньше 32

Всё понял! Спасибо Вам, растолковали!
juvf
Цитата(yanvasiij @ Apr 15 2014, 14:50) *
Приоритет моего прерывания:
Код
    NVIC_SetPriority(UART0_IRQn, 196);

Ртосовские прерывания ( из файля FreeRtosConfig.h):
Код
#define configKERNEL_INTERRUPT_PRIORITY         255
#define configMAX_SYSCALL_INTERRUPT_PRIORITY     191 /* equivalent to 0xb0, or priority 11. */


Если я правильно понимаю там небольшая путаница в нумерациях: у FreeRtos приоритет тем выше, чем выше его цифра, а у CortexM3 наоборот. Получается, если приоритет у ртосовского прерывания стоит 191 (как у меня), то мне нужно сделать приоритет 192 и более, чтобы все работало. Я так и сделал (у меня 196). Верно?

неверно. 191 - эквивалент 11. т.е. для вашего прерывания нужно установить от 15 до 11 включительно. Если выше 11, т.е. от 10 до 0 - то нельзя в обработчике использовать API.

а вообще, при начальном написании программы нужно включить в файле FreeRTOSConfig.h макрос

#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }

тогда ээээ.... по мойму при прерывании будет проверяться правильность назначений приоритетов прерываний (и не только, также проверяется правильность приоритетов задач), в случае ошибки вы остановитесь в этой проверке. в дебаге можно будет посмотреть что не так.
после проверки конфигурации ос, если ни где не было ассертов, то этот макрос нужно закомитить, чтобы в рабочем проекте он не отъедал процесорное время.
yanvasiij
Цитата(juvf @ Apr 18 2014, 15:34) *
неверно. 191 - эквивалент 11. т.е. для вашего прерывания нужно установить от 15 до 11 включительно. Если выше 11, т.е. от 10 до 0 - то нельзя в обработчике использовать API.

а вообще, при начальном написании программы нужно включить в файле FreeRTOSConfig.h макрос

#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }

тогда ээээ.... по мойму при прерывании будет проверяться правильность назначений приоритетов прерываний (и не только, также проверяется правильность приоритетов задач), в случае ошибки вы остановитесь в этой проверке. в дебаге можно будет посмотреть что не так.
после проверки конфигурации ос, если ни где не было ассертов, то этот макрос нужно закомитить, чтобы в рабочем проекте он не отъедал процесорное время.


Спасибо Вам большое!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.