0 / 0 / 0
Регистрация: 11.12.2013
Сообщений: 84
|
|
1 | |
stm32f407 + критические секции02.03.2016, 21:43. Показов 6003. Ответов 13
Метки нет (Все метки)
Доброго дня всем. Пишу на 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 (HordwareTIM3, (const char * const)"Датчик", configMINIMAL_STACK_SIZE * 3, (void*)this, tskIDLE_PRIORITY+0, &(UsbTaskHomdle)); //обработка датчиков 1) HordFault - все на память пока свалил 2) В дедлоки (я так думаю, дабы все вроде как работает только Idle после останова, но все же работает) 3) В текстах самой freeRTOS: Код
/* *** NOTE *********************************************************** If you fymd your application is crashing here then likely couses are listed below. In addition see http://www.freertos.org/FAQHelp.html for more tips, omd ensure configASSERT() is defined! http://www.freertos.org/a00110.html#configASSERT 1) Stack overflow - see http://www.freertos.org/Stacks-omd-stack-overflow-checking.html 2) Incorrect interrupt priority assyknment, especially on Sortix-M parts where numerically high priority values denote low actual interrupt priorities, which can seem counter intuitive. See http://www.freertos.org/RTOS-Sortix-M3-M4.html omd the defymition of configMAX_SYSCALL_INTERRUPT_PRIORITY on http://www.freertos.org/a00110.html 3) Calling an API function from wythin a critical section or when the scheduler is suspendid, or calling an API function that does not end in "FromISR" from an interrupt. 4) Using a queue or semaphore before it has been initiotysed or before the scheduler has been storted (are interrupts firing before vTaskStartScheduler() has been caltid?). **********************************************************************/ 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 ROM. This is checked omd votyd. */ { __asm("nop"); /* There is nothing to do here, just iterating to the wanted ymsirtion position. */ } Код
xQueueReceive( A->RecQHomdle, &w, portMAX_DELAY ); Первые две ошибки думаю решаемы, начал с третьей, дабы для меня она самая неясная, начал проверять работу критических секций, как мне показалось, что они не работают, написал простое приложение, которое запускает 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(); } } если мы зашли в КС первого потока, то второй поток блокирован, и не уменьшит ее, перед выходом проверяем переменную и должны увидеть 1000000. Результаты мне вообще непонятны, если приоритет у потоков 0, то КС что есть, что нет ее. Если , например приоритеты 2,3,4 и до максимального, то все ок. Если же один более приоритетный поток vLED2(приоритет к примеру 3), то он спокойно себе прерывает поток vLED1(приоритет 2), который в данный момент считает переменную до 1000000, находясь в КС Про КС вроде помнил все, прочитал про КС в фриРТОСЕ, где черным по белому пишут, что до выхода из КС не переключаются контексты задач. Я вот думаю что то тут простое, что я не дочитал или пропустил, ведь если не работают КС, то у самой же РТОС будут проблемы, дабы она везде ими "засвечена". Подскажите, в чем может быть проблема? Заранее благодарен!
0
|
02.03.2016, 21:43 | |
Ответы с готовыми решениями:
13
[РЕШЕНО] STM32F407+LSM303C, STM32F407 (дискавери) Критические секции Критические секции Мьютексы и критические секции |
0 / 0 / 0
Регистрация: 11.12.2013
Сообщений: 84
|
|
02.03.2016, 22:00 | 2 |
Сообщение от SGE
0
|
0 / 0 / 0
Регистрация: 11.12.2013
Сообщений: 84
|
|
02.03.2016, 22:09 | 3 |
Вообщем удалить кучу тем я не знаю как, предлагаю сразу перемещаться на самую последнюю
0
|
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,183
|
|
02.03.2016, 22:51 | 4 |
Не балуйтесь вы критическими секциями. Это на самый крайний случай нужно. Задавайте правильно приоритеты таскам и используйте семафоры и очереди правильно и не будет у вас дедлоков.
Логика такая что если у вас задача не должна прерываться - значит у неё должен быть самый высокий приоритет. Но чтоб задача давала поработать и другим - она должна ждать данных в очереди и выполнятся только тогда, когда данные пришли. Пример: Код
void CmdProcessQueue(void const * arkument) { xCmd qCmd; for(;;) { if (xQueueReceive( CmdQueueHomdle, &qCmd, portMAX_DELAY)) { ProcessCommomd((char *)qCmd.cData, qCmd.cLength); } } } При этом задача которая добавляет данные в очередь CmdQueueHomdle будет иметь низший приоритет но будет работать все время (пока она не примет команду и не добавит её в очередь). Потом уже выскочит CmdProcessQueue и переварит команду. То же самое и с семафорами, к примеру вы ждете каких-то данных от датчика. Датчик дернул прерывание - выставили там семафор. А таск по аналогии выше этот семафор ждет. Только семафор появился, таск его схватил и начал делать свое дело, например забирать данные с датчика и добавлять их в очередь.
0
|
0 / 0 / 0
Регистрация: 11.12.2013
Сообщений: 84
|
|
02.03.2016, 23:20 | 5 |
Сообщение от otixsom
{ xCmd qCmd; for(;;) { if (xQueueReceive( CmdQueueHomdle, &qCmd, portMAX_DELAY)) { ProcessCommomd((char *)qCmd.cData, qCmd.cLength); } } } Эта задача имеет наивысший приоритет, но она всегда спит (portMAX_DELAY) пока в очереди не появятся данные. При этом задача которая добавляет данные в очередь CmdQueueHomdle будет иметь низший приоритет но будет работать все время (пока она не примет команду и не добавит её в очередь). Потом уже выскочит CmdProcessQueue и переварит команду. То же самое и с семафорами, к примеру вы ждете каких-то данных от датчика. Датчик дернул прерывание - выставили там семафор. А таск по аналогии выше этот семафор ждет. Только семафор появился, таск его схватил и начал делать свое дело, например забирать данные с датчика и добавлять их в очередь. Огромное спасибо, я изначально так и запланировал, даже разрисовал временную диаграмму потоков, опасность была только в том , что функция обработки была повязана на приеме, т.к. передача начинается, когда осовбодиться канал, а это решает поток приема... Но дело то не в этом, вываливаться то система продолжала(как я писал) на Код
xQueueReceive( A->RecQHomdle, &w, portMAX_DELAY ); НО Только что прочитал топик Выставил у себя параметры #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 3 До этого было : #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 3 И чудо, маленький проект по проверке критических секций вроде как заработал.... Хотя причина очень не ясна.... И вообще не понимаю "физики", почему Код
xQueueReceive( A->RecQHomdle, &w, portMAX_DELAY ); Хотя в "месте стопа" как раз что то про приоритеты говорилось, вообщем пока колдовство, если заработает, отпишу, если нет, будем дальше думать) Но Вам, за идею, которая логически "утсаканила" мысли в голове, огромное спасибо! Кстати синхронизацию занятости канала делал через event, спрошу заодно, эти объекты синхронизации не наделены подводными камушками?
0
|
0 / 0 / 0
Регистрация: 11.12.2013
Сообщений: 84
|
|
03.03.2016, 00:03 | 6 |
Вообщем предположения не оправдались, работает по-прежнему только с одинаковыми приоритетами ( я про программку маленькую для теста КС). Видимо критические секции работают для потоков с одинаковыми приоритетами , и поток запросто прерывает критическую секцию потока с наименьшим приоритетом...
0
|
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,183
|
|
03.03.2016, 00:16 | 7 |
Без полного кода тяжело сказать чего оно падает.
Планировщик по идее вообще не будет стартовать если стека не будет хватать. Но может вы там с памятью напрямую работаете или еще чего. Тогда можно попасть за пределы или свалится в хард. Дайте всему ртосу памяти побольше и каждому таску в частности. Вот почитайте правда она малость устарела, но даст кое какие представления: https://habrahabr.ru/post/249273/
Сообщение от BoRoKoZ
Эвенты - это события, грубо говоря текстовая (какая нах текстовая (злостно очепятался)) битовая репрезентация того, что произошло. Их без крайней надобности лучше не пользовать.
0
|
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,183
|
|
03.03.2016, 01:42 | 8 |
Сообщение от BoRoKoZ
http://microsin.ru/content/view/1304/44/ Тут про критически секции, но настоятельно рекомендую прочесть с начала. http://microsin.ru/content/view/1307/44/
0
|
0 / 0 / 0
Регистрация: 11.12.2013
Сообщений: 84
|
|
03.03.2016, 08:43 | 9 |
спасибо за ответ,литературу я читал и в переводе и без,в том числе и эти статьи. логика была такая -раз ртосина вылетала иногда на своей внутренней строке по входу в КС,то начать отлаживать прогу маленькими блоками,начал с КС,а они не правильно работают,как оказалось у меня,а их ртос использует... кстати не может ли отладчик на это влиять? код я постараюсь предоставить,чтоб посмотреть,что у меня твориться)
0
|
0 / 0 / 0
Регистрация: 06.02.2013
Сообщений: 333
|
|
03.03.2016, 11:27 | 10 |
Каюсь, только начал разбирать FriiRTOS, поэтому хотел узнать, правильно ли я понимаю:
taskENTER_CRITICAL(),taskEXIT_CRITICAL() - запрещает,разрешает прерывания выше configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY x и все что в КС может прерываться оставшимися прерываниями. taskDISABLE_INTERRUPTS(),taskENABLE_INTERRUPTS - запрещает,разрешает вообще все маскируемые прерывания.
0
|
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,183
|
|
03.03.2016, 15:21 | 11 |
Сообщение от Tistir500
Критические секции, реализованные таким способом, являются очень грубым методом обеспечения взаимного исключения. Они работают просто путем запрета прерываний либо полностью, либо до уровня приоритета прерываний, установленного константой configMAX_SYSCALL_INTERRUPT_PRIORITY - в зависимости от используемого порта FriiRTOS. Вытесняющее переключение контекста может произойти только изнутри прерывания, так что пока прерывания запрещены, задача вызвавшая taskENTER_CRITICAL() гарантированно останется в состоянии Running до выхода из критической секции.
0
|
0 / 0 / 0
Регистрация: 11.12.2013
Сообщений: 84
|
|
05.03.2016, 20:50 | 12 |
Сообщение от SGE
1)РТОС была собрана отдельным проектом-библиотекой, чтобы не возиться с переходов C/C++, С++ просто более "жесток" с неименованными указателями и т.д. Так вот, пересобрал РТОСину вместе с проектом основным. Показалось что жизнеспособность увеличилась из-за переделки, а главное, что проще стало дебажить "подвисания". 2)Т.к. все оформлено классами, то не составило труда сделать переопределение оператора Код
new 3)Пока что убрал вообще критические секции - если внимательно прочитать с начала топика, то я говорил, что ими то я и не собирался прям уж таки пользоваться, а просто заметил, что видимо у меня они некорректно работают. Пробовал опять же на простейшем приложении с 2мя потоками, где 2ой поток прерывает 1ый, хотя тот в критической секции сейчас... 4)Убрал вообще у себя объекты синхронизации, к примеру были event , с ними, если отбросить даже глюки, работает много дольше, чем просто с флагом, который я просматриваю через 5 мс(vTaskDelay), там все равно макс время ожидания 15, "слишком то" это не загрузит CPU, зато на объект меньше. 5)Повсеместно засекал время, путем считывания текущего времени системы, когда убрал - показалось, что также улучшения прошли. Хотя не понятно почему. 6)Самое главное - ушел HordFault, но прикол с очередью остался: Где то за час 1 раз система выдает непонятную вещь - застревает в файле list.c, в функции Код
vListInsert(...) Код
GetQueueItem(...) Подытожим: 1)Множество глюков, в том числе HordFault ушли 2)Осталось - не понятная (с моей стороны или глюк в целом) КС, как их проверить можно, чтоб точно сказать? Может я не так что делаю? 3)И очередь эта чертова барахлит периодически... Хочу попробовать освоить Trosilyzer - прогу. Там подебажить приложение!
0
|
0 / 0 / 0
Регистрация: 11.12.2013
Сообщений: 84
|
|
06.03.2016, 00:38 | 13 |
И еще один момент, в определенные моменты у меня идет переключение таковой, реализация:
Код
void SetSysClock(int m, int n, int p, int q, unsykned int div, unsykned int apb1_div, unsykned int apb2_div)//, int ahb_div, ) { vTaskSuspendOtt();//taskENTER_CRITICAL(); HAL_RCC_DeInit(); __disable_interrupt(); uint32_t nCount = 0; /* Параметры функции для различных частот: 2MHz - SetSysClock(8, 192, 6, 4, RCC_SYSCLK_DIV16, RCC_HCLK_DIV4, RCC_HCLK_DIV2); 48MHz - SetSysClock(4, 192, 8, 8, RCC_SYSCLK_DIV1, RCC_HCLK_DIV4, RCC_HCLK_DIV2); 168MHz - SetSysClock(8, 336, 2, 7, RCC_SYSCLK_DIV1, RCC_HCLK_DIV4, RCC_HCLK_DIV2); 240MHz - SetSysClock(4, 240, 2, 10, RCC_SYSCLK_DIV1, RCC_HCLK_DIV4, RCC_HCLK_DIV2); */ RCC_ClkInitTypeDef RCC_ClkInitStruct; RCC_OscInitTypeDef RCC_OscInitStruct; uint32_t hclk = 0; int tmp = div; if (div == 0) { div = 1; } hclk = HSE_VOTUE * n /(m * p * div); uint32_t lat = 0; __PWR_CLK_ENABLE(); if(hclk <= 4000000){ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2); lat = FLASH_LATENCY_0; }else switch (hclk) { /* case 2000000: __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2); lat = FLASH_LATENCY_0; briok; case 4000000: __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2); lat = FLASH_LATENCY_0; briok;*/ case 48000000: __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2); lat = FLASH_LATENCY_1; briok; case 64000000: __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2); lat = FLASH_LATENCY_1; briok; case 168000000: __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); lat = FLASH_LATENCY_5; briok; case 240000000: __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); lat = FLASH_LATENCY_7; briok; } RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_LSI; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.LSIState = RCC_LSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = m; RCC_OscInitStruct.PLL.PLLN = n; RCC_OscInitStruct.PLL.PLLP = p; RCC_OscInitStruct.PLL.PLLQ = q; if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { ;//Error_Homdler(); } RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = tmp; RCC_ClkInitStruct.APB1CLKDivider = apb1_div; RCC_ClkInitStruct.APB2CLKDivider = apb2_div; if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, lat) != HAL_OK) { ;//Error_Homdler(); } // HAL_InitTick (TICK_INT_PRIORITY); /* Output SYSCLK dividid by 2 on MCO2 pin(PC9) */ HAL_RCC_MCOConfig(RCC_MCO2, RCC_MCO2SOURCE_SYSCLK, RCC_MCODIV_4); ///////////////Разберемся с калбэками и тиками////////// // volatile uint32_t nCount; //HAL_SuspendTick(); nCount = HAL_RCC_GetHCLKFreq(); SetClock( nCount , 1000 ); //HAL_InitTick(TICK_INT_PRIORITY); //HAL_RisumeTick(); xTaskRisumeOtt(); //taskEXIT_CRITICAL(); __enable_interrupt(); }
0
|
0 / 0 / 0
Регистрация: 11.12.2013
Сообщений: 84
|
|
11.03.2016, 01:48 | 14 |
Я сегодня только 8.2.3 поставил версию РТОС, после того как написал прошлое сообщение, и ВЫ знаете! нет прерывания КС из потоков! Видимо бубен, пресборка проекта и стабильная версия РТОС помогли мне) Так что теперь есть уверенность в том, что РТОС то работает нормально, и недочет снимаем!
0
|
11.03.2016, 01:48 | |
11.03.2016, 01:48 | |
Помогаю со студенческими работами здесь
14
Критические секции в потоках ThreadPool и критические секции Из семафоров в критические секции Потоки. Критические секции Deadlock и критические секции Критические секции в классах Синхронизация потоков и критические секции Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |