Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32L151 Hardfault как найти причину ?
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
MiklPolikov
Стабильно попадаю в Hardfault.
Используется FreeRTOS
При раскидывание по коду метки xxx_error=1 ; xxx_error=2 .... Hardfault исчезает, но конкретного места это не выдаёт.

При попадании в Hardfault под отладкой:
- в Call Stuck Window пусто, один Hardfault
Регистры ядра
SCB - > CFSR=0x00000400
SCB - > HFSR=0x40000000
т.е стоят биты:
Bit 10 IMPRECISERR: Imprecise data bus error
When the processor sets this bit to 1, it does not write a fault address to the BFAR.
This is an asynchronous fault.
Bit 30 FORCED: Forced hard fault
Indicates a forced hard fault, generated by escalation of a fault with configurable priority that
cannot be handles, either because of priority or because it is disabled:
When this bit is set to 1, the hard fault handler must read the other fault

Вопрос: как искать причину такого глюка ?
Что вообще может быть причиной ?

Заранее спасибо !
ViKo
Искать так же, как в 500-х описанных ранее случаев.
1. Это не все регистры, отвечающие за ошибки.
2. Нужно из стека извлечь адрес команды, на которой произошел сбой.
MiklPolikov
Цитата(ViKo @ Mar 1 2016, 21:33) *
Искать так же, как в 500-х описанных ранее случаев.
1. Это не все регистры, отвечающие за ошибки.
2. Нужно из стека извлечь адрес команды, на которой произошел сбой.


Есть ещё регистр адреса- но в нём нет значения, т.к. не выставлен соответствующий бит.
Как из стека извлечь адрес ?
ViKo
Цитата(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 .
}
Сергей Борщ
Я нашел для себя примитивное решение:
Код
void HardFault_Handler(void)
{
    volatile int i = 0;
    while(!i)
       ;
}
Обнаружив прграмму в этом цикле переключаюсь в режим дизассемблера, изменяю значение i на 1 и выхожу из исключения. Попадаю на вызвавшую исключение команду. Дальше уже головой.
SasaVitebsk
Скажем так. Есть 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();                            // Начать сначала
}
romas2010
Цитата(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
MiklPolikov
Цитата(SasaVitebsk @ Mar 2 2016, 09:55) *
Второй - непредсказуемый вылет в произвольном месте. Как правило, причина - неверный размер стека. Либо при работе с буферами неверно рассчитан его размер. То есть, в месте, где реально происходит ошибка, вылета нет, там просто портятся данные. А вылет происходит там где вы пытаетесь воспользоваться уже испорченными данными.


Вот этого не понимаю. Почему место "произвольное" ? Оно ведь всё равно должно быть конкретное, при какой-то конкретной операции ?
ViKo
Цитата(Сергей Борщ @ Mar 2 2016, 01:46) *
Я нашел для себя примитивное решение:
Код
void HardFault_Handler(void)
{
    volatile int i = 0;
    while(!i)
      ;
}
Обнаружив прграмму в этом цикле переключаюсь в режим дизассемблера, изменяю значение i на 1 и выхожу из исключения. Попадаю на вызвавшую исключение команду. Дальше уже головой.

А без переменной, просто задать while (true)? (Т.е. команду B .) А потом, зайдя под отладчиком, передвинуть счетчик команд на следующую команду, return (BX).
SasaVitebsk
Цитата(MiklPolikov @ Mar 3 2016, 10:46) *
Вот этого не понимаю. Почему место "произвольное" ? Оно ведь всё равно должно быть конкретное, при какой-то конкретной операции ?

Например в одной задаче вы заполняете буфер локальный. размер выбран неверно, либо просто ошибка. Вы вылазите за пределы локального стека и портите стек второй задачи.
При переключении на задачу с запорченным стеком у вас будут непредсказуемые события. Может запустится неизвестно что неизвестно откуда. В конечном итоге произойдёт крах проги с вылетом по Hard Fault. Только смотреть там будет нечего. Так как ошибка произошла совершенно не в этом месте.
Что тут не понятного?
Сергей Борщ
Цитата(ViKo @ Mar 3 2016, 12:35) *
А без переменной, просто задать while (true)? (Т.е. команду B .) А потом, зайдя под отладчиком, передвинуть счетчик команд на следующую команду, return (BX).
Я использую достаточно умные компиляторы, они не ставят BX после бесконечного цикла.
Tarbal
Цитата(Сергей Борщ @ Mar 3 2016, 15:12) *
Я использую достаточно умные компиляторы, они не ставят BX после бесконечного цикла.


Я тоже так делаю, только делаю условный цикл и в отладчике меняю условие для выхода sm.gif
А еще трассировку делаю. Создаю массив структур. Массив размером 2^Х. В интересных точках записываю данные в поля структуры и передвигаю индекс. Индекс движется по кругу. Статическая переменная индекс показывает место начала и конца.
Этот способ я сам придумал, но в одном проекте видел как делали трассировку при помощи логического анализатора. В интересных местах в свободные порты писали интересующие значения, а анализатором их захватывали.
adnega
Цитата(MiklPolikov @ Mar 1 2016, 21:01) *
Вопрос: как искать причину такого глюка ?
Что вообще может быть причиной ?

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


SasaVitebsk, спасибо ! Отслеживать последнюю задачу в vTaskSwitchContext отличный метод !
Только я не смог понять что такое "номер задачи"
Поэтому в том же месте сохраняю её имя pxCurrentTCB->pcTaskName
SasaVitebsk
Цитата(MiklPolikov @ Mar 7 2016, 11:11) *
Только я не смог понять что такое "номер задачи"

Я просто в IAR работаю. Там есть плагин для FreeRTOS. Номер задачи, это её номер запуска по сути. Я вижу список задач и их параметры, например, адреса стека задачи.
Это даёт мне возможность просмотреть память в нужном месте. То есть увидеть насколько правильно я распределил память. Ну и вообще.
x893
Для FreeRTOS использовал Percepio - полезная программа оказалась
jcxz
Цитата(Сергей Борщ @ Mar 2 2016, 04:46) *
Обнаружив прграмму в этом цикле переключаюсь в режим дизассемблера, изменяю значение i на 1 и выхожу из исключения. Попадаю на вызвавшую исключение команду. Дальше уже головой.

Раз получено "Imprecise data bus error", значит попадёте скорей всего не на вызвавшую исключение команду, а где-то немного после неё.
Надо просмотреть ближайшие предыдущие десяток команд с обращением к памяти от этого места - где-то скорей всего есть обращение к несуществующей памяти.
adnega
Цитата(jcxz @ Mar 10 2016, 13:16) *
Раз получено "Imprecise data bus error"

У меня такое на FreeRTOS было из-за неправильных приоритетов.
Не все функции ОС могут быть выполнены в прерываниях с высоким приоритетом.
Из-за этого нарушалось целостность объектов, а это как следствие приводило в том числе и к "Imprecise data bus error".
scifi
Цитата(jcxz @ Mar 10 2016, 13:16) *
Раз получено "Imprecise data bus error", значит попадёте скорей всего не на вызвавшую исключение команду, а где-то немного после неё.

Вот тут товарищ советует отключить кеширование записи в память, и тогда imprecise превратится в precise, а регистры будут указывать точно на ту инструкцию, которая виновата. Если ревизия проца не слишком старая и позволяет это сделать, конечно. Какая ревизия у STM32L151 - не знаю.
ViKo
Цитата(Сергей Борщ @ Mar 3 2016, 15:12) *
Я использую достаточно умные компиляторы, они не ставят BX после бесконечного цикла.

Тогда так:
Код
__asm void HardFault_Handler(void)
{
  B .
  BX LR
}

Гениально просто? rolleyes.gif
Сергей Борщ
Цитата(ViKo @ Mar 22 2016, 13:22) *
Гениально просто? rolleyes.gif
Но зачем?
ViKo
Цитата(Сергей Борщ @ Mar 22 2016, 14:26) *
Но зачем?

Затем, что так проще, чем манипулировать i. Меньше команд. Меньше мышедвижений, клавиатуру давить совсем не нужно. В отладчике "Установить программный счетчик сюда", и все.
Сергей Борщ
Цитата(ViKo @ Mar 22 2016, 13:38) *
Затем, что так проще, чем манипулировать i. Меньше команд. Меньше мышедвижений, клавиатуру давить совсем не нужно. В отладчике "Установить программный счетчик сюда", и все.
Я тоже могу в отладчике "установить программный счетчик сюда" и все. 2 или 6 команд используются в этом месте - меня не волнует абсолютно. В отладочной версии куча диагностики, которая занимает на несколько порядков больше места. Так что никаких объективных причин использовать тут встроенный ассемблер я не вижу. Ваше желание впихнуть ассемблер куда попало мне известно, я этим не страдаю.
ViKo
Я редко использую ассемблер. В данном случае я довел вашу идею до совершенства. Мне нравится, полагаю, и не только мне понравится. 4 байта!
Зачем спорите? Можете пользоваться своей функцией, никто руки же не выкручивает.
P.S. Вы же статейку приводили, где одного байта не хватило. rolleyes.gif
scifi
Цитата(ViKo @ Mar 22 2016, 15:24) *
4 байта!
Подсчёт байтов - это болезнь! 1111493779.gif
Цитата(ViKo @ Mar 22 2016, 15:24) *
4 байта!P.S. Вы же статейку приводили, где одного байта не хватило. rolleyes.gif
Притягивание аргумента за уши - это не болезнь, но тоже нехорошо laughing.gif
ViKo
Цитата(scifi @ Mar 22 2016, 16:07) *
Подсчёт байтов - это болезнь!
Притягивание аргумента за уши - это не болезнь, но тоже нехорошо

От вас, scifi, не ожидал. biggrin.gif
Это не болезнь, а хобби.
Какой-такой аргумент? Разве мне нужно что-то доказывать? Просто принес подарок. santa2.gif
Сергей Борщ
Да, пожалуй, я погорячился. Приношу извинения.
scifi
Цитата(ViKo @ Mar 22 2016, 16:26) *
Это не болезнь, а хобби.

Хобби не возбраняется, прошу пардону biggrin.gif
ViKo
Ишь, прямо эпидемия извинений. beer.gif
У предложенного обработчика есть еще одно достоинство - он не портит регистры. Кроме тех, что уже испорчены самим исключением - PC, SP, LR. Не надо лезть в стек, они и так на виду.
Сергей Борщ
Цитата(ViKo @ Mar 22 2016, 18:10) *
У предложенного обработчика есть еще одно достоинство - он не портит регистры.
А смысл в значениях этих регистров пока мы не знаем, откуда попали в исключение? В момент выхода по BX содержимое испорченных регистров будет автоматически восстановлено из стека.
ViKo
Цитата(Сергей Борщ @ Mar 22 2016, 19:16) *
А смысл в значениях этих регистров пока мы не знаем, откуда попали в исключение? В момент выхода по BX содержимое испорченных регистров будет автоматически восстановлено из стека.

Да, правильно. Но тут они всегда те же. Мне они пока что ни разу и не понадобились.
Кстати, в стеке-то не все сохраняются, и восстанавливаются они же не все. Понятно, в обработчике можно было использовать те, что сохраняются-восстанавливаются. А вдруг не хватит?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.