Jump to content

    
Sign in to follow this  
MiklPolikov

STM32L151 Hardfault как найти причину ?

Recommended Posts

Стабильно попадаю в 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

 

Вопрос: как искать причину такого глюка ?

Что вообще может быть причиной ?

 

Заранее спасибо !

Share this post


Link to post
Share on other sites

Искать так же, как в 500-х описанных ранее случаев.

1. Это не все регистры, отвечающие за ошибки.

2. Нужно из стека извлечь адрес команды, на которой произошел сбой.

 

Edited by IgorKossak

Share this post


Link to post
Share on other sites
Искать так же, как в 500-х описанных ранее случаев.

1. Это не все регистры, отвечающие за ошибки.

2. Нужно из стека извлечь адрес команды, на которой произошел сбой.

 

Есть ещё регистр адреса- но в нём нет значения, т.к. не выставлен соответствующий бит.

Как из стека извлечь адрес ?

Share this post


Link to post
Share on other sites
Есть ещё регистр адреса- но в нём нет значения, т.к. не выставлен соответствующий бит.

Как из стека извлечь адрес ?

Насчет 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 .
}

Share this post


Link to post
Share on other sites

Я нашел для себя примитивное решение:

void HardFault_Handler(void)
{
    volatile int i = 0;
    while(!i)
       ;
}

Обнаружив прграмму в этом цикле переключаюсь в режим дизассемблера, изменяю значение i на 1 и выхожу из исключения. Попадаю на вызвавшую исключение команду. Дальше уже головой.

Share this post


Link to post
Share on other sites

Скажем так. Есть 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();                            // Начать сначала
}

Share this post


Link to post
Share on other sites
Стабильно попадаю в 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

Edited by romas2010

Share this post


Link to post
Share on other sites
Второй - непредсказуемый вылет в произвольном месте. Как правило, причина - неверный размер стека. Либо при работе с буферами неверно рассчитан его размер. То есть, в месте, где реально происходит ошибка, вылета нет, там просто портятся данные. А вылет происходит там где вы пытаетесь воспользоваться уже испорченными данными.

 

Вот этого не понимаю. Почему место "произвольное" ? Оно ведь всё равно должно быть конкретное, при какой-то конкретной операции ?

Share this post


Link to post
Share on other sites
Я нашел для себя примитивное решение:

void HardFault_Handler(void)
{
    volatile int i = 0;
    while(!i)
      ;
}

Обнаружив прграмму в этом цикле переключаюсь в режим дизассемблера, изменяю значение i на 1 и выхожу из исключения. Попадаю на вызвавшую исключение команду. Дальше уже головой.

А без переменной, просто задать while (true)? (Т.е. команду B .) А потом, зайдя под отладчиком, передвинуть счетчик команд на следующую команду, return (BX).

Share this post


Link to post
Share on other sites
Вот этого не понимаю. Почему место "произвольное" ? Оно ведь всё равно должно быть конкретное, при какой-то конкретной операции ?

Например в одной задаче вы заполняете буфер локальный. размер выбран неверно, либо просто ошибка. Вы вылазите за пределы локального стека и портите стек второй задачи.

При переключении на задачу с запорченным стеком у вас будут непредсказуемые события. Может запустится неизвестно что неизвестно откуда. В конечном итоге произойдёт крах проги с вылетом по Hard Fault. Только смотреть там будет нечего. Так как ошибка произошла совершенно не в этом месте.

Что тут не понятного?

Share this post


Link to post
Share on other sites
А без переменной, просто задать while (true)? (Т.е. команду B .) А потом, зайдя под отладчиком, передвинуть счетчик команд на следующую команду, return (BX).
Я использую достаточно умные компиляторы, они не ставят BX после бесконечного цикла.

 

Share this post


Link to post
Share on other sites
Я использую достаточно умные компиляторы, они не ставят BX после бесконечного цикла.

 

Я тоже так делаю, только делаю условный цикл и в отладчике меняю условие для выхода :)

А еще трассировку делаю. Создаю массив структур. Массив размером 2^Х. В интересных точках записываю данные в поля структуры и передвигаю индекс. Индекс движется по кругу. Статическая переменная индекс показывает место начала и конца.

Этот способ я сам придумал, но в одном проекте видел как делали трассировку при помощи логического анализатора. В интересных местах в свободные порты писали интересующие значения, а анализатором их захватывали.

Share this post


Link to post
Share on other sites
Вопрос: как искать причину такого глюка ?

Что вообще может быть причиной ?

Я бы начал с проверки корректности указания приоритетов прерываний.

Помню давным давно тут обсуждали. В варианте FreeRTOS из коробки не хватало одной волшебной строчки.

Share this post


Link to post
Share on other sites
Например я во FreeRTOSConfig добавил следующую строку

// для отладки. слежение за задачей

#define traceTASK_SWITCHED_IN() *(uint32_t*)0x40002868 = pxCurrentTCB->uxTCBNumber

(не обращайте внимание на прямой адрес. В программе у меня Вы этого больше нигде не увидите. Просто если добавляешь в исходники FreeRTOS заголовочные файлы, то там конфликты - я пытался этого избегать.)

 

SasaVitebsk, спасибо ! Отслеживать последнюю задачу в vTaskSwitchContext отличный метод !

Только я не смог понять что такое "номер задачи"

Поэтому в том же месте сохраняю её имя pxCurrentTCB->pcTaskName

Share this post


Link to post
Share on other sites
Только я не смог понять что такое "номер задачи"

Я просто в IAR работаю. Там есть плагин для FreeRTOS. Номер задачи, это её номер запуска по сути. Я вижу список задач и их параметры, например, адреса стека задачи.

Это даёт мне возможность просмотреть память в нужном месте. То есть увидеть насколько правильно я распределил память. Ну и вообще.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this