Перейти к содержанию
    

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

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

 

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

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

 

Изменено пользователем IgorKossak

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Насчет 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 и выхожу из исключения. Попадаю на вызвавшую исключение команду. Дальше уже головой.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Например я во FreeRTOSConfig добавил следующую строку

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

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

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

 

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...