|
Резервирование RSTACK для AVRMega, Нестабильная работа |
|
|
|
May 30 2013, 19:53
|

Группа: Участник
Сообщений: 12
Регистрация: 10-08-07
Из: Odessa
Пользователь №: 29 704

|
Здравствуйте. Компилятор: IAR AVR Контроллер: AVR ATMega128 + 64КБ внешней памяти Менеджер памяти: heap_3.c Описание проблемы: Прошивка представляет собой связку из нескольких слоев: ОС + Самописный фреймворк + Пользовательская программа. Специфика фреймворка и программы такова, что глубина вызовов может быть достаточно большой - приблизительно 20-30 вызовов в глубину. Вся эта связка в режиме симуляции под win32 работает нормально, но при прошивке контроллера начинаются проблемы - происходит циклическая перезагрузка, при том не всегда с самого начала. После очередного запуска программа может запуститься откуда-то с середины. Это все я контроллирую по трейсам в терминале. Вобщем искал я искал и нашел такую проблему: в конфигурационном файле FreeRTOSConfig.h есть макроопределение configCALL_STACK_SIZE, которое по умолчанию установлено в 20. Исследование исходников показало, что это 20 байт, которые ОС резервирует в стеке задачи под адреса возврата из функций. Так как у меня мега, то получается максимальная глубина всего 10 вызовов, а дальше RSTACK начинает перетирать уже сохраненные регистры и все прочее, от чего начинаются проблемы. Ну хорошо, увеличим размер этой области до, скажем, 128 байт (глубина до 64 вызовов), при этом всем общего размера стека хватает - я его устанавливаю с запасом, скажем 8 КБ. Результат: программа не работает. Глючит уже по другому, но с тем же результатом. Вобщем экспериментальным образом я нашел, что при размере 45 текущая программа работает стабильно, но всеравно при дальнейшем усложнении кода начинаются похожие проблемы. Вопрос: Как установить большой размер для стека возвратов? Очень надеюсь на вашу помощь. PS: Да, еще была проблема - вместе с этим постоянно срабатывал каллбэк vApplicationStackOverflowHook(), пока я не увеличил стандартные значения макросов configTIMER_QUEUE_LENGTH и configTIMER_TASK_STACK_DEPTH. После этого каллбэк срабатывал только после большого количества этих перезагрузок при глючащей системе. Теперь же, после небольшого допиливания программы (дописал несколько пустых классов-тасок и запустил их), опять начал срабатывать, но уже без таких феерических циклов перезагрузок как раньше (всего лишь одна): Вот пример трейсов, тут работа начинается с "Svc: LBKLogic started". Видно, что програма стартует нормально, но потом начинаются уже какие=-то глюки, после чего контроллер перезагружается (следующий "Svc: LBKLogic started") и дальше пока что все идет хорошо! (это до поры до времени) Код Svc: LBKLogic started <!> Fatal: FreeRTOS stack overflow (Task: "J¤JјJНJСJ$%ҐJ", Stack ptr: 4acd, Stack base: 4ad1) <!> Fatal: FreeRTOS stack overflow (Task: "J¤JјJНJСJ$%ҐJ", Stack ptr: 4a99, Stack base: bcf7) <!> Fatal: FreeRTOS stack overflow (Task: "J¤JјJНJСJ$%ҐJ", Stack ptr: 4a65, Stack base: bcf7) <!> Fatal: FreeRTOS stack overflow (Task: "J¤JјJНJСJ$%ҐJ", Stack ptr: 4a31, Stack base: bcf7) <!> Fatal: FreeRTOS stack overflow (Task: "J¤JјJНJСJ$%ҐJ", Stack ptr: 49fd, Stack base: bcf7) <!> Fatal: FreeRTOS stack overflow (Task: "J¤JјJНJСJ$%ҐJ", Stack ptr: 49c9, Stack base: bcf7) <!> Fatal: FreeRTOS stack overflow (Task: "J¤JјJНJСJ$%ҐJ", Stack ptr: 4995, Stack base: bcf7) <!> Fatal: FreeRTOS stack overflow (Task: "J¤JјJНJСJ$%6—6±1b0Л-µЗб"9дCлб"9дCлб"9дCлб"9дCлб"9дCлб"9дCлб"9дCлб"9дC%А&%i3"^›", Stack ptr: 4961, Stack base: bcf7) <!> Fatal: FreeRTOS stack overflow (Task: "J¤J6—6±1b0Л-µЗб"9дCлб"9дCлб"9дCлб"9дCлб"9дCлб"9дCлб"9дCлб"9дCлб"9дC%А&%i3"^›", Stack ptr: 492d, Stack base: bcf7) Svc: LBKLogic started Svc: Platform started Svc: HMILogic started Svc: BeepMaster started Svc: Controller started Nothing more to run PPS: Фрагмент текущей конфигурации из FreeRTOSConfig.h: Код #ifndef WIN32 # include <iom128.h> #endif
#define configCALL_STACK_SIZE 45 // 20 by default
#define configUSE_PREEMPTION 1 #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configCPU_CLOCK_HZ ( ( unsigned long ) 16000000 ) #define configTICK_RATE_HZ ( ( portTickType ) 1000 ) #define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 9 ) #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 85 + configCALL_STACK_SIZE ) // 85 by default #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 51200 ) ) #define configMAX_TASK_NAME_LEN ( 16 ) #ifdef DEBUG // ygurin #define configUSE_TRACE_FACILITY 1 #else #define configUSE_TRACE_FACILITY 0 #endif #define configUSE_16_BIT_TICKS 1 #define configIDLE_SHOULD_YIELD 1 #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) #define configTIMER_QUEUE_LENGTH 64 // 20 by default 64 #define configTIMER_TASK_STACK_DEPTH 92 // 64 by default 92
#define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
#define INCLUDE_vTaskPrioritySet 1 #define INCLUDE_uxTaskPriorityGet 1 #define INCLUDE_vTaskDelete 1 #define INCLUDE_vTaskCleanUpResources 0 #define INCLUDE_vTaskSuspend 1 #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1 А это MAP файл с сегментами, который сгенерировал компилятор: Имя Пространство Адрес Размер Тип Выравнивание NEAR_I DATA 00001100 - 00001309 20A Relative 0 NEAR_Z DATA 0000130A - 00001390 87 Relative 0 RSTACK DATA 00001391 - 00001790 400 Predefined 0 CSTACK DATA 00001791 - 00001B90 400 Predefined 0 NEAR_HEAP DATA 00001B91 - 0000E68A CAFA Predefined 0
|
|
|
|
|
 |
Ответов
|
Jun 2 2013, 08:31
|

Группа: Участник
Сообщений: 12
Регистрация: 10-08-07
Из: Odessa
Пользователь №: 29 704

|
desh, RAMPZ у меня не сохранялся, спасибо. Я сейчас добавил ваши изменения, а так же добавил строчку в функцию pxPortInitialiseStack: Код ... *pxTopOfStack = ( portSTACK_TYPE ) 0x30; /* R30 Z */ pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) 0x31; /* R31 */
pxTopOfStack--; // вот эти две *pxTopOfStack = ( portSTACK_TYPE ) 0x3B; /* RAMPZ */ pxTopOfStack--; *pxTopOfStack = portNO_CRITICAL_NESTING; /* Critical nesting is zero when the task starts. */ .. Программа запустилась, но сходу упала в stack overfow. Вот на всякий случай показыаю как выглядит участок фреймворка, который собственно и запускает таски: До старта операциооной системы вызываются эти функции. Все эти классы являются наследниками класса CServiceBase и пока что не содержат интересного кода: static_cast<void>(CPBeepMasterService::run()); static_cast<void>(CPControllerService::run()); static_cast<void>(CPPlatformService::run()); static_cast<void>(CPHMILogicService::run()); static_cast<void>(CPAuxADCService::run());  В аттаче прикреплены файлы, описанные в диаграмме PS: Дам ссылку на эту тему в теме про __interrupt
Сообщение отредактировал Aeore - Jun 2 2013, 08:32
|
|
|
|
|
Jun 2 2013, 09:33
|
Частый гость
 
Группа: Свой
Сообщений: 113
Регистрация: 25-10-07
Из: Краснодар
Пользователь №: 31 725

|
Цитата(Aeore @ Jun 2 2013, 12:31)  а так же добавил строчку в функцию pxPortInitialiseStack: Все правильно. Забыл про нее. Что мешает вам запустить и отладить задачи по очереди? Похоже архитектура приложения позволяет это сделать. Что у вас происходит при переполнении стека? У вас отрабатывает ловушка переполнения стека FreeRTOS? Поставте в ней бесконечный цикл. При попадании изучите содержимое стека и pxCurrentTCB. На время отладки отключите сторожевой таймер. В чем смысл использования фреймворка? На разных платформах вы используете разные операционки? Обратите внимание на scmRTOS. Она изначально на плюсах. Какое у вас значение configMINIMAL_STACK_SIZE? Увеличте его. Оно влияет на размер стека задачи IDLE. В IDLE переполнение стека могут вызывать прерывания.
Сообщение отредактировал desh - Jun 2 2013, 10:02
|
|
|
|
|
Jun 3 2013, 18:15
|

Группа: Участник
Сообщений: 12
Регистрация: 10-08-07
Из: Odessa
Пользователь №: 29 704

|
Цитата(desh @ Jun 2 2013, 12:33)  Что мешает вам запустить и отладить задачи по очереди? Похоже архитектура приложения позволяет это сделать. Мешает неопределенное поведение системы. На работоспособность влияют совершенно несвязанные изменения. Вот к примеру : Стартует первая таска и тут же валится все по переполнению стека: CODE Svc: LBKLogic started <!> Fatal: FreeRTOS stack overflow (Task: "ОJжJцJыJ$%6ПJ", Stack ptr: 4af6, Stack base: 4afb) <!> Fatal: FreeRTOS stack overflow (Task: "ОJжJцJыJ$%6ПJ", Stack ptr: 4ac1, Stack base: 4ae6) <!> Fatal: FreeRTOS stack overflow (Task: "ОJжJцJыJ$%6ПJ", Stack ptr: 4a8c, Stack base: 4ae6) <!> Fatal: FreeRTOS stack overflow (Task: "ОJжJцJыJ$%6ПJ", Stack ptr: 4a57, Stack base: 4ae6) <!> Fatal: FreeRTOS stack overflow (Task: "ОJжJцJыJ$%6ПJ", Stack ptr: 4a22, Stack base: 4ae6) <!> Fatal: FreeRTOS stack overflow (Task: "ОJжJцJыJ$%6ПJ", Stack ptr: 49ed, Stack base: 4ae6) <!> Fatal: FreeRTOS stack overflow (Task: "ОJжJцJыJ$%6ПJ", Stack ptr: 49b8, Stack base: 4ae6) <!> Fatal: FreeRTOS stack overflow (Task: "ОJжJцJыJ$%67A7[2 1u._ ^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ&j&»&3"^›", Stack ptr: 4983, Stack base: 4ae6) <!> Fatal: FreeRTOS stack overflow (Task: "ОJ7A7[2 1u._ ^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ&j&»&3"^›", Stack ptr: 494e, Stack base: 4ae6) <!>
А теперь внимание! Добавляем проверочный код в эту таску (который ничего не делает и ни с чем не связан) и вуалля - все начинает работать хорошо: CODE void o(string s) { TRACE(const_cast<char*>(s.c_str())); }
void m(string s) { o(s); }
void l(string s) { m(s); }
void k(string s) { l(s); }
void g(string s) { k(s); }
void f(string s) { g(s); }
void e(string s) { f(s); }
void d(string s) { e(s); }
void c(string s) { d(s); }
void b(string s) { c(s); }
void a(string s) { b(s); }
// -------------------------------------------------------------------------- void CPLBKLogicService::taskStart( void* const pContext ) // -------------------------------------------------------------------------- { uint32_t q[500]; q[300] = 5; if (q[300] == 5) { a("affected!"); } TRACE( "Svc: LBKLogic started" ); }
И вот что полияло на результат? O_o Цитата(desh @ Jun 2 2013, 12:33)  Что у вас происходит при переполнении стека? У вас отрабатывает ловушка переполнения стека FreeRTOS? да Цитата(desh @ Jun 2 2013, 12:33)  Поставте в ней бесконечный цикл. Цикл есть. Перезагружается всеравно. Возможно из-за преемптивного планировщика Цитата(desh @ Jun 2 2013, 12:33)  При попадании изучите содержимое стека и pxCurrentTCB. Попробую, правда сильно внутринности ОС я пока что не изучал Цитата(desh @ Jun 2 2013, 12:33)  На время отладки отключите сторожевой таймер. Таймер не включен Цитата(desh @ Jun 2 2013, 12:33)  В чем смысл использования фреймворка? На разных платформах вы используете разные операционки? Обратите внимание на scmRTOS. Она изначально на плюсах. Идея фреймворка - предоставить расширенное и удобное, полностью асинхронное event-driven окружение для разработки ПО. FreeRTOS используется в качестве ядра и так же дает дополнительные плюшки в виде возможности поднимать независимые потоки. На scmRTOS я смотрел и даже использовал, но его возможности ограниченны по сравнению с FreeRTOS, к примеру там невозможно удалить таску. Цитата(desh @ Jun 2 2013, 12:33)  Какое у вас значение configMINIMAL_STACK_SIZE? Увеличте его. Оно влияет на размер стека задачи IDLE. В IDLE переполнение стека могут вызывать прерывания. Я написал так: #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 85 + configCALL_STACK_SIZE ) Самм IDLE я пока что не использую, прерывания так же - лишь один таймер работает для функционированния вытесняющего планировщика
|
|
|
|
|
Jun 6 2013, 08:33
|
Участник

Группа: Свой
Сообщений: 46
Регистрация: 23-09-04
Пользователь №: 709

|
Цитата(Aeore @ Jun 3 2013, 21:15)  А теперь внимание! Добавляем проверочный код в эту таску (который ничего не делает и ни с чем не связан) и вуалля - все начинает работать хорошо: CODE void o(string s) { TRACE(const_cast<char*>(s.c_str())); }
void m(string s) { o(s); }
void l(string s) { m(s); }
void k(string s) { l(s); }
void g(string s) { k(s); }
void f(string s) { g(s); }
void e(string s) { f(s); }
void d(string s) { e(s); }
void c(string s) { d(s); }
void b(string s) { c(s); }
void a(string s) { b(s); }
// -------------------------------------------------------------------------- void CPLBKLogicService::taskStart( void* const pContext ) // -------------------------------------------------------------------------- { uint32_t q[500]; q[300] = 5; if (q[300] == 5) { a("affected!"); } TRACE( "Svc: LBKLogic started" ); }
А проверяли использование стека сомой таской? Сколько выделяете стека на таск xTaskCreate(task, (signed char *)"task", ??? , 0,tskIDLE_PRIORITY + 2, NULL); ? Как я писал локалные переменные ложаться в стек задачи а у Вас локальная переменная во uint32_t q[500];. Попробуйте динамически выделить память, либо сделать глобальную переменную и посмотреть как себя ведет. А что возвращает uxTaskGetStackHighWaterMark( xTaskHandle xTask ); во вложеных функциях ?
|
|
|
|
|
Jun 12 2013, 20:09
|

Группа: Участник
Сообщений: 12
Регистрация: 10-08-07
Из: Odessa
Пользователь №: 29 704

|
Цитата(framer @ Jun 6 2013, 11:33)  А проверяли использование стека сомой таской? Сколько выделяете стека на таск xTaskCreate(task, (signed char *)"task", ??? , 0,tskIDLE_PRIORITY + 2, NULL); ? Как я писал локалные переменные ложаться в стек задачи а у Вас локальная переменная во uint32_t q[500];. Попробуйте динамически выделить память, либо сделать глобальную переменную и посмотреть как себя ведет. А что возвращает uxTaskGetStackHighWaterMark( xTaskHandle xTask ); во вложеных функциях ? Извиняюсь за то что долго не писал. Стека под каждую задачу выделяется с очень больши запасом. Вот только что застабил и перенес проект на WIN32 и тут появились такие новости с uxTaskGetStackHighWaterMark: На данный момент есть такие таски: CPLBKLogicService: 1024 CPPlatformService: 2048 CPHMILogicService: 2048 CPControllerService: 4096 Цифры это размер стеков этих задач. taskStart - это то место, где они запускаются. Вот кусок трейсов с платформы avr (цифры это результат работы функции uxTaskGetStackHighWaterMark в различных местах): CODE P45G Broadband Radio Controller 2013, YGurin ---------------------------------------- [SS]: LBKLogic SHW CPLBKLogicService::taskStart 54 [SS]: Platform [SS]: HMI SHW CPHMILogicService::taskStart 54 SHW CPPlatformService::taskStart 54 [SS]: BeepMaster [SS]: Controller SHW CPControllerService::taskStart 52 SHW CPControllerService::onQueueCommandActioned 7 SHW CPStrategyPOSTCommand::start 246 SHW CPControllerService::onQueueCommandActioned 246 SHW CPControllerService::onQueueCommandActioned 236 SHW CPControllerService::onQueueCommandActioned 234 Nothing more to run
А вот то же самое, но с WIN32. Как видно, на avr uxTaskGetStackHighWaterMark() возвращает всего ничего, а на win32 все нормально:  Т.е. все очень сильно зависит от платформы. Это уже что-то.
Сообщение отредактировал Aeore - Jun 12 2013, 20:09
|
|
|
|
|
Jun 17 2013, 06:11
|
Участник

Группа: Свой
Сообщений: 46
Регистрация: 23-09-04
Пользователь №: 709

|
Цитата(Aeore @ Jun 16 2013, 23:59)  Как он может зависеть от платформы, если я сам указываю размеры стеков? Ну а как обяснить показатели использования стека uxTaskGetStackHighWaterMark под Win32? Цитата(Aeore @ Jun 13 2013, 00:09)  А вот то же самое, но с WIN32. Как видно, на avr uxTaskGetStackHighWaterMark() возвращает всего ничего, а на win32 все нормально:  Т.е. все очень сильно зависит от платформы. Это уже что-то. Заняло по 5 блоков(слов) и все. Видно, что стек в задачах не используется. Все зависит от того как перенесено на WIN32. Под win если посмотреть то таски симулитуютя использованием thread. Там нет переключения контекста с изменением указателей стека. Осуществляется это остановкой текущего thread и запуском следующего (можно посмотреть исходники в prvProcessSimulatedInterrupts ). В таком случае локальные перемнные не распологаються в стеке задачи FreeRtos, а используються механизмы win32. Поэтому отладка стека эфективна на конкретной платформе.
|
|
|
|
Сообщений в этой теме
Aeore Резервирование RSTACK для AVRMega May 30 2013, 19:53 desh Возможно Ваша проблемма не в FreeRTOS, а в приклад... May 31 2013, 19:13 Aeore Переполнение буфера, очевидно, происходит, но по н... Jun 1 2013, 21:25 desh Да не спешите Вы. Там от 323 до 128 один регистр с... Jun 1 2013, 21:50 framer А может еще зависит от размера стека для конкретно... Jun 2 2013, 06:17     framer Цитата(Aeore @ Jun 13 2013, 00:09) CODE
[... Jun 14 2013, 12:06 _Артём_ Цитата(Aeore @ Jun 2 2013, 11:31) Програм... Jun 2 2013, 12:16 desh Так. ЧуднО у вас все.
ЦитатаЦикл есть. Перезагруж... Jun 3 2013, 20:01 Aeore Цитата(desh @ Jun 3 2013, 23:01) Запретит... Jun 5 2013, 18:54 desh ЦитатаПробовал. Симулятор вел себя не вполне адекв... Jun 7 2013, 13:42 desh У вас как на АВР-е определен базовый тип portBASE_... Jun 14 2013, 06:52 Aeore Цитата(desh @ Jun 14 2013, 09:52) У вас к... Jun 16 2013, 20:59 Aeore Да, это так. Я недавно перевел систему из преемпти... Jun 25 2013, 08:11
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|