|
STM32L151 Hardfault как найти причину ? |
|
|
|
Mar 1 2016, 19:25
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(MiklPolikov @ Mar 1 2016, 21:37)  Есть ещё регистр адреса- но в нём нет значения, т.к. не выставлен соответствующий бит. Как из стека извлечь адрес ? Насчет L151 конкретно не знаю, но обычно регистров больше. Из стека адрес - много раз показывали. Лучше в книжку Джозефа Ю заглянуть, там будет расписано и программа дана. И здесь поиском по форуму тоже. Есть два регистра стека, какой-то из них использован, к значению этого стека прибавить 24... Код __asm void HardFault_Handler(void) { TST LR, #4 ITE EQ MRSEQ R0, MSP ; Main Stack was used, put MSP in R0 MRSNE R0, PSP ; Process Stack was used, put PSP in R0 LDR R0, [R0, #24] ; Get stacked PC from stack B . }
|
|
|
|
|
Mar 1 2016, 22:46
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Я нашел для себя примитивное решение: Код void HardFault_Handler(void) { volatile int i = 0; while(!i) ; } Обнаружив прграмму в этом цикле переключаюсь в режим дизассемблера, изменяю значение i на 1 и выхожу из исключения. Попадаю на вызвавшую исключение команду. Дальше уже головой.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Mar 2 2016, 06:55
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Скажем так. Есть 2 вида вылета. Первый происходит закономерно в одном и том же месте. Как правило это либо обращение по не выровненному адресу или обращение по несуществующему адресу. То есть неверный расчёт указателя при работе с указателями. Такой вылет найти просто. Вам надо найти место где он происходит (например способом предложенным Сергей Борщ). Потом поставить точку останова пораньше и пройти по шагам, анализируя работу. Второй - непредсказуемый вылет в произвольном месте. Как правило, причина - неверный размер стека. Либо при работе с буферами неверно рассчитан его размер. То есть, в месте, где реально происходит ошибка, вылета нет, там просто портятся данные. А вылет происходит там где вы пытаетесь воспользоваться уже испорченными данными. Тут рекомендуется: 1. Существенно увеличить размеры стека для разных задач. Пробовать останавливать и контролировать реальные размеры стеков. 2. Попытаться локализовать задачу где происходит вылет. Или место. Посмотреть какую-то статистику. --- Например я во FreeRTOSConfig добавил следующую строку // для отладки. слежение за задачей #define traceTASK_SWITCHED_IN() *(uint32_t*)0x40002868 = pxCurrentTCB->uxTCBNumber (не обращайте внимание на прямой адрес. В программе у меня Вы этого больше нигде не увидите. Просто если добавляешь в исходники FreeRTOS заголовочные файлы, то там конфликты - я пытался этого избегать.) На самом деле это следующее // Номер задачи, которая последней выполнялась перед вылетом по ошибке #define NBRTASKFAULT RTC->BKP6R Сама traceTASK_SWITCHED_IN вызывается во FreeRTOS в vTaskSwitchContext Далее Код void HardFault_Handler(void) { StatusTM3->nbrTskFlt = NBRTASKFAULT & 0x1f; // записать номер вылетевшей программы StatusTM3->fHardFault = TRUE; // установить признак DelayMs(TIM_SMALLWAIT,100); // Задержка NVIC_SystemReset(); // Начать сначала }
|
|
|
|
|
Mar 2 2016, 19:13
|
Участник

Группа: Участник
Сообщений: 63
Регистрация: 25-11-11
Пользователь №: 68 515

|
Цитата(MiklPolikov @ Mar 1 2016, 21:01)  Стабильно попадаю в Hardfault. Используется FreeRTOS При раскидывание по коду метки xxx_error=1 ; xxx_error=2 .... Hardfault исчезает, но конкретного места это не выдаёт.
При попадании в Hardfault под отладкой: - в Call Stuck Window пусто, один Hardfault ...... Заранее спасибо ! Обычно такое происходит если -невыровненые данные,когда команды ldm/stm - pop{...,pc} где по смещению места регистра возврата в стеке почему-то левое значение,что-то гадит стек(особенно актуально для RTOS)..помогает увеличение зазмера стека задачи,но на самотек не пускать все равно..кстати,это самая гадкая ситуация-ведь регистр РС может находиться в диапазоне адресов вашей же программы и ваша же программа еще продолжает таки какое-то время работать и обеспечит вам напряженный день и бессонную ночь.... - смотрите также значение регистров r0-r3 они сохраняются при прерывании и иногда используются компилятором(keil) для хранения указателей,возможно обращение за гранью памяти..разберитесь,почему они вдруг указывают на левый адрес,что-то с алгоритмом вашим не так да,весьма хорошую тему предложил Сергей Борщ...по крайней мере можно попытаться локализовать место возникновения..но и keil тоже продвинутая среда-окно CALL STACK->курсор мыши на функцию+правая кнопка->show caller code
Сообщение отредактировал romas2010 - Mar 2 2016, 19:29
|
|
|
|
|
Mar 3 2016, 10:35
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(Сергей Борщ @ Mar 2 2016, 01:46)  Я нашел для себя примитивное решение: Код void HardFault_Handler(void) { volatile int i = 0; while(!i) ; } Обнаружив прграмму в этом цикле переключаюсь в режим дизассемблера, изменяю значение i на 1 и выхожу из исключения. Попадаю на вызвавшую исключение команду. Дальше уже головой. А без переменной, просто задать while (true)? (Т.е. команду B .) А потом, зайдя под отладчиком, передвинуть счетчик команд на следующую команду, return (BX).
|
|
|
|
|
Mar 7 2016, 08:11
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Цитата(SasaVitebsk @ Mar 2 2016, 09:55)  Например я во FreeRTOSConfig добавил следующую строку // для отладки. слежение за задачей #define traceTASK_SWITCHED_IN() *(uint32_t*)0x40002868 = pxCurrentTCB->uxTCBNumber (не обращайте внимание на прямой адрес. В программе у меня Вы этого больше нигде не увидите. Просто если добавляешь в исходники FreeRTOS заголовочные файлы, то там конфликты - я пытался этого избегать.) SasaVitebsk, спасибо ! Отслеживать последнюю задачу в vTaskSwitchContext отличный метод ! Только я не смог понять что такое "номер задачи" Поэтому в том же месте сохраняю её имя pxCurrentTCB->pcTaskName
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|