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

Исключение Hard Fault на Cortex-M3

Здравствуйте!

Прошу помочь разобраться.
Процессор STM32F100R8, компилятор GCC.

Периодически возникает исключение Hard Fault.
В обработчике считал следующие регистры:

HFSR=x40000000
CFSR=x00008200

Читаю описание и понять ничего не могу... В чем может быть проблема?

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


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

Там на стеке должны еще некоторые регистры лежать. Очень помогает сохраненные значения LR и PC.

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


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

Накосячил в коде. Если ошибка возникает периодически, то, как правило, что-то в роде обращения по неинициализованному указателю (произвольное значение указателя), либо выход за пределы адресов реализованной памяти. Если развернута RTOS, может портиться содержимое стека задачи или стека вызовов. 

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


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

On 8/12/2024 at 8:59 PM, adnega said:

Там на стеке должны еще некоторые регистры лежать. Очень помогает сохраненные значения LR и PC.

Считать в обработчике по адресу из MSP?

On 8/12/2024 at 9:03 PM, Arlleex said:

Под отладчиком для начала стоило бы хотя бы посмотреть стек вызовов.

Конкретизируйте, пожалуйста. Что я могу увидеть в стеке вызовов?

On 8/12/2024 at 9:18 PM, EdgeAligned said:

Накосячил в коде. Если ошибка возникает периодически,

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

On 8/12/2024 at 9:18 PM, EdgeAligned said:

как правило, что-то в роде обращения по неинициализованному указателю (произвольное значение указателя), либо выход за пределы адресов реализованной памяти.

Уже глаза сломал в код смотреть... упростил и отключил все по максимуму...

On 8/12/2024 at 9:18 PM, EdgeAligned said:

Если развернута RTOS, может портиться содержимое стека задачи или стека вызовов.

РТОСа нет. Прототреды использую.

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


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

Если работаете в TrueStudio или CubeIDE, в них есть утилита Fault Analyzer, которая выводит всю информацию о HardFault, в том числе адрес инструкции, которая его вызвала.

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


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

On 8/12/2024 at 9:58 PM, Priest_89 said:

Если работаете в TrueStudio или CubeIDE, в них есть утилита Fault Analyzer, которая выводит всю информацию о HardFault, в том числе адрес инструкции, которая его вызвала.

Нет. У меня в чистом виде GCC и другая IDE.

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


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

56 минут назад, koluna сказал:

Конкретизируйте, пожалуйста. Что я могу увидеть в стеке вызовов?

Я к тому, что начинать надо с простейшего, а анализ стека вызовов во многих случаях позволяет успешно локализовать баг, даже без анализа регистров HF.

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

3 часа назад, koluna сказал:

Здравствуйте!

Прошу помочь разобраться.
Процессор STM32F100R8, компилятор GCC.

Периодически возникает исключение Hard Fault.
В обработчике считал следующие регистры:

HFSR=x40000000
CFSR=x00008200

Читаю описание и понять ничего не могу... В чем может быть проблема?

Считайте BFAR и в нем будет адрес инструкции, которая вызвала ошибку. Из активного стека нужно вычленить аргументы (регистры), по ним уже и смотреть, откуда туда могло попасть то, что попало и вызвало эскалацию до HF.

BusFault - как правило, либо пытаетесь "лезть" по адресу, по которому лезть нельзя (например, адрес несуществующей или неактивной периферии).

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


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

1 час назад, koluna сказал:

Считать в обработчике по адресу из MSP?

Типа такого:

Обработчик:

HardFaultException:
	mov		r0, sp
	push	{lr}
	bl		print_fault
	pop		{pc}

Си-функция:

void print_fault(sFAULT	*fault)
{
	static int cnt = 0;
	if(cnt < 5)
	{
		con_str("FAULT:\n\r");
		con_str("r0   = "); con_dword(fault->r0); con_str(", ");
		con_str("r1   = "); con_dword(fault->r1); con_str(", ");
		con_str("r2   = "); con_dword(fault->r2); con_str(", ");
		con_str("r3   = "); con_dword(fault->r3); con_str("\n\r");
		con_str("r12  = "); con_dword(fault->r12); con_str(", ");
		con_str("lr   = "); con_dword(fault->lr); con_str(", ");
		con_str("pc   = "); con_dword(fault->pc); con_str(", ");
		con_str("xpsr = "); con_dword(fault->xpsr);	con_str("\n\r");
		con_start();
		cnt++;
	}
}

typedef struct sFAULT
{
	uint32_t	r0;
	uint32_t	r1;
	uint32_t	r2;
	uint32_t	r3;
	uint32_t	r12;
	uint32_t	lr;
	uint32_t	pc;
	uint32_t	xpsr;
} sFAULT;
 

 

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


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

Подцепил отладчик... пытаюсь понять что там и как...

(gdb) backtrace 
#0  HardFault_Handler () at ./src/main.c:116
#1  <signal handler called>
#2  0x08001682 in exchTXEHandler () at ./src/libs/exchange/exchange.c:341
#3  <signal handler called>
#4  dbgout (level=level@entry=7, format=0x80017c7 <EXCH_process+266> "H\377\367\004\370\262#+\200\252\347\201N") at ./src/libs/dbg/dbg.c:19
#5  0x080017c6 in waitForRequest (exchRes=0x20000f20 <exchRes.7247>, pt=0x20000f2c <ptChild.7246>) at ./src/libs/exchange/exchange.c:175
#6  EXCH_process (pt=0x20001fec) at ./src/libs/exchange/exchange.c:461
#7  0xf4f377fc in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

Это стек вызовов...

Настораживает последняя строчка.

Не понимаю, что такое <signal handler called>

On 8/12/2024 at 10:36 PM, Arlleex said:

Считайте BFAR и в нем будет адрес инструкции, которая вызвала ошибку.

Да, счтал давно:
 

[HardFault_Handler()] BFAR=x20002000

Да, это Bus Fault, я уже понял. И адрес RAM. В просессоре 8 кБ, как раз на конец указывает, только вот что это значит...

On 8/12/2024 at 10:36 PM, Arlleex said:

BusFault - как правило, либо пытаетесь "лезть" по адресу, по которому лезть нельзя (например, адрес несуществующей или неактивной периферии).

Да там элементарный код в нескольких функциях, я ума не приложу что там не так пошло...

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


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

Кста, у меня бага была на GD-проце. По идее, ядро после перезагрузки должно стек проинициализировать (первое слово) и управление передать (второе слово). У меня почему-то стек не инициализировался ядром - пришлось ручками задавать. Тоже вспотел - минимальнейший проект не работал)

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


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

8 часов назад, koluna сказал:

Да там элементарный код в нескольких функциях, я ума не приложу что там не так пошло...

Если ошибка непостоянная, а проявляется временами, то она не будет видна явно в коде. 

10 часов назад, koluna сказал:

Прототреды использую

Что-то тут с потоками накосячил. Убери эти недопотоки и проверь код без них.

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


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

On 8/13/2024 at 12:28 AM, Arlleex said:

Дык может стоит выложить код, если не секретный?

Не секретный. Можно выложить. Проблема в том, что проверить полноценно не удастся: там два устройства, второе устройство обменивается по USART с глючащим устройством...

On 8/13/2024 at 2:32 AM, adnega said:

Кста, у меня бага была на GD-проце. По идее, ядро после перезагрузки должно стек проинициализировать (первое слово) и управление передать (второе слово). У меня почему-то стек не инициализировался ядром - пришлось ручками задавать. Тоже вспотел - минимальнейший проект не работал)

У меня скрипт линкера и стартап из scmRTOS.

В ОЗУ, вроде, нормально все влезает. Посмотрел по map-файлу.
Указатель на стек формируется в скрипте линкера, в стартапе вместе с таблицей подгружается.

typedef void(*const intfunc)(void);

__attribute__ ((section(".isr_vector")))
intfunc g_pfnVectors[] =
{
	/* Core interrupt vectors */
(intfunc)((unsigned long)&_estack),
	Reset_Handler,
	NMI_Handler,

Прошелся по функциям - нигде нет огромных переменных и, соответственно, переполнения стека.

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


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

--- Ты чего тут по полу ползаешь?
--- Да я вон там ключи потерял, ищу...
--- Так и ищи там, где потерял
--- Так здесь светлее же!

Напишите обработчик прерывания  void HardFault_Handler(void){ while(1) ; } и поставьте на нем брейкпоинт, запустите отладку. При остановке посмотрите отладочную инфу с указанием адреса инструкции, вызвавшей "тяжелый сбой". Откройте листинг кода и по адресу найдите, какая инструкция и к чему (какому куску кода) она принадлежит. Далее будет видно.

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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