Пишу на STM32 под freeRTOS. Наткнулся на проблему с критическими секциями. Появилась задачка маршрутизации для радиомодуля, имеются датчики, мы их обрабатываем, далее(при определенных условиях) 1)формируем сообщение и добавляем его в очередь, 2)из этой очереди забираем сообщения и транслируем их в сеть. Также есть входящие сообщения, который мы либо обрабатываем, либо 3)ретранслируем - путем добавления в туже очередь. Казалось бы, все довольно просто с точки зрения потоков:
xTaskCreate (GetRFRX, (const char * const)"Прием", configMINIMAL_STACK_SIZE * 3, (void*)this, tskIDLE_PRIORITY+2, &(xTaskGetRF)); //поток приема в эфире
xTaskCreate (GetQueueItem, (const char * const)"Очередь", configMINIMAL_STACK_SIZE * 3, (void*)this, tskIDLE_PRIORITY+1, &(xTaskQueue));//поток обслуживания очереди
xTaskCreate (HardwareTIM3, (const char * const)"Датчик", configMINIMAL_STACK_SIZE * 3, (void*)this, tskIDLE_PRIORITY+0, &(UsbTaskHandle)); //обработка датчиков
Сразу скажу, что стек подбирал эмпирически, более того, кучу проверяю везде где можно. В функции переполнения не вылетает. Приоритеты ставил разные - от этого меняется лишь ситуация с deadlock`ми. Начал синхронизировать все "расшаренные" ресурсы, хотя их немного, но система периодически стала вылетать:
1) HardFault - все на память пока свалил
2) В дедлоки (я так думаю, дабы все вроде как работает только Idle после останова, но все же работает)
3) В текстах самой freeRTOS:
/* *** NOTE ***********************************************************
If you find your application is crashing here then likely causes are
listed below. In addition see http://www.freertos.org/FAQHelp.html for
more tips, and ensure configASSERT() is defined!
http://www.freerto …0110.html#configASSERT
1) Stack overflow -
see http://www.freerto …overflow-checking.html
2) Incorrect interrupt priority assignment, especially on Cortex-M
parts where numerically high priority values denote low actual
interrupt priorities, which can seem counter intuitive. See
http://www.freerto …RTOS-Cortex-M3-M4.html and the definition
of configMAX_SYSCALL_INTERRUPT_PRIORITY on
http://www.freertos.org/a00110.html
3) Calling an API function from within a critical section or when
the scheduler is suspended, or calling an API function that does
not end in "FromISR" from an interrupt.
4) Using a queue or semaphore before it has been initialised or
before the scheduler has been started (are interrupts firing
before vTaskStartScheduler() has been called?).
**********************************************************************/
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
{
__asm("nop");
/* There is nothing to do here, just iterating to the wanted
insertion position. */
}
Вываливается из мест , где идет какое либо обращение к объектам синхронизации, но чаще всего к очереди:
xQueueReceive( A->RecQHandle, &w, portMAX_DELAY );
Причем частенько , сама RTOS часто в этих случаях(при работе с объектами синхр-ии) использует taskENTER_CRITICAL(),taskEXIT_CRITICAL()
Первые две ошибки думаю решаемы, начал с третьей, дабы для меня она самая неясная, начал проверять работу критических секций, как мне показалось, что они не работают, написал простое приложение, которое запускает 2 потока для проверки критической секциии, и обалдел... :
//создание 2х потоков
xTaskCreate (tLED1, (const char * const)"Прием1", configMINIMAL_STACK_SIZE , NULL, tskIDLE_PRIORITY+0,0);
xTaskCreate (tLED2, (const char * const)"Прием2", configMINIMAL_STACK_SIZE , NULL, tskIDLE_PRIORITY+0, 0);
..............................
static void tLED1(void *pvParameter)
{
for(;;){
// taskENTER_CRITICAL();
vPortEnterCritical();
// Tooggllee(LED4,4000000000);
qwassss = 0;
for(int i =1;i<=1000000;i++){
qwassss= qwassss+1;// qwas = i*i*i*i*i*i/qwas/qwas/qwas;
}
Tooggllee(LED4,1);//мигнуть с задержкой *задержка циклом, без HAL_Delay или vTaskDelay
// taskEXIT_CRITICAL();
vPortExitCritical();
taskYIELD();
}
}
static void tLED2(void *pvParameter)
{
for(;;){
//Tooggllee(LED4,5000);
vPortEnterCritical();
for(int i =1;i<=100;i++){
qwassss= qwassss-1;// qwas = i*i*i*i*i*i/qwas/qwas/qwas;
}
Tooggllee(LED4,1); //мигнуть с задержкой *задержка циклом, без HAL_Delay или vTaskDelay
vPortExitCritical();
taskYIELD();
}
}
В общем смысл проверки какой - есть 2 потока, один в цикле увеличивает переменную от 1 до 1000000, другой уменьшает ее в цикле на 100.
если мы зашли в КС первого потока, то второй поток блокирован, и не уменьшит ее, перед выходом проверяем переменную и должны увидеть 1000000.
Результаты мне вообще непонятны, если приоритет у потоков 0, то КС что есть, что нет ее. Если , например приоритеты 2,3,4 и до максимального, то все ок.
Если же один более приоритетный поток vLED2(приоритет к примеру 3), то он спокойно себе прерывает поток vLED1(приоритет 2), который в данный момент считает переменную до 1000000, находясь в КС
Про КС вроде помнил все, прочитал про КС в фриРТОСЕ, где черным по белому пишут, что до выхода из КС не переключаются контексты задач.
Я вот думаю что то тут простое, что я не дочитал или пропустил, ведь если не работают КС, то у самой же РТОС будут проблемы, дабы она везде ими "засвечена".
Подскажите, в чем может быть проблема? Заранее благодарен!