|
|
  |
Прошу помощи с STM32F051, Периодическое сваливание в HardFault |
|
|
|
Aug 9 2014, 19:21
|
Местный
  
Группа: Участник
Сообщений: 244
Регистрация: 29-02-08
Пользователь №: 35 503

|
Цитата(jcxz @ Aug 10 2014, 00:50)  Тогда эта модификация стека произошла в вашем обработчике HardFault. Вы же вроде пытаетесь привести результат стекинга на входе в HardFault? Вот как раз такого результата быть не может, как я вам выше уже показал. Скорей всего Вы неправильно определили положение верхушки стека прерванной программы. Осознавая недостаток собственной компетенции обработчик взял из Definitive Guide CODE // Hard Fault handler in C, with stack frame location and LR value // extracted from the assembly wrapper as input parameters void HardFault_Handler(unsigned int * hardfault_args, unsigned lr_value) { static volatile unsigned int stacked_r0; static volatile unsigned int stacked_r1; static volatile unsigned int stacked_r2; static volatile unsigned int stacked_r3; static volatile unsigned int stacked_r12; static volatile unsigned int stacked_lr; static volatile unsigned int stacked_pc; static volatile unsigned int stacked_psr; stacked_r0 = ((unsigned long) hardfault_args[0]); stacked_r1 = ((unsigned long) hardfault_args[1]); stacked_r2 = ((unsigned long) hardfault_args[2]); stacked_r3 = ((unsigned long) hardfault_args[3]); stacked_r12 = ((unsigned long) hardfault_args[4]); stacked_lr = ((unsigned long) hardfault_args[5]); stacked_pc = ((unsigned long) hardfault_args[6]); stacked_psr = ((unsigned long) hardfault_args[7]); printf ("[Hard fault handler]\n"); printf ("R0 = %x\n", stacked_r0); printf ("R1 = %x\n", stacked_r1); printf ("R2 = %x\n", stacked_r2); printf ("R3 = %x\n", stacked_r3); printf ("R12 = %x\n", stacked_r12); printf ("Stacked LR = %x\n", stacked_lr); printf ("Stacked PC = %x\n", stacked_pc); printf ("Stacked PSR = %x\n", stacked_psr); printf ("Current LR = %x\n", lr_value); while(1); // endless loop
|
|
|
|
|
Aug 10 2014, 12:21
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(nanorobot @ Aug 9 2014, 22:47)  Точка - chSemSignal(&semAdc) - использование сервиса RTOS Nil(ChibiOs) от Jiovanni di Sirio. Гляньте, выровнена ли переменная/структура (и ее поля) semAdc: для M0 это критично. Если M3 скушает структуру типа: __packed { U8 a; void *p; }, и не подавится (то есть, когда указатель p явно по нечетному адресу), то в M0 попытка обратиться через *p вызывает hard fault. На это я наткнулся, когда переносил библиотеку с M3 на M0. Т.к. структура у меня должна была оставаться __packed, пришлось перетасовать поля, чтобы указатели были по четным адресам.
|
|
|
|
|
Aug 10 2014, 15:14
|
Местный
  
Группа: Участник
Сообщений: 244
Регистрация: 29-02-08
Пользователь №: 35 503

|
Цитата(KnightIgor @ Aug 10 2014, 18:21)  Гляньте, выровнена ли переменная/структура (и ее поля) semAdc: для M0 это критично. Если M3 скушает структуру типа: __packed { U8 a; void *p; }, и не подавится (то есть, когда указатель p явно по нечетному адресу), то в M0 попытка обратиться через *p вызывает hard fault. На это я наткнулся, когда переносил библиотеку с M3 на M0. Т.к. структура у меня должна была оставаться __packed, пришлось перетасовать поля, чтобы указатели были по четным адресам. данная инструкция выполняется сотни раз в секунду а HF случается раз в часы. т.е. дело видимо не в не в выравнивании, а в стечении неких обстоятельств. Проблему решил, правда, не "в лоб" а обходным маневром - отказался от использования семафора, и вот уже более полусуток проблема не проявляет себя. Хотя желание разобраться в сути проблемы до конца есть.
|
|
|
|
|
Aug 10 2014, 16:49
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(Сергей Борщ @ Aug 10 2014, 16:57)  Если структура __packed, то выравнивание полей значения не имеет - компилятор собирает каждое поле побайтово. У меня указатель был расположен после U8. В то время как вся структура была размещена с выравниванием 4, поле указателя имело адрес 4*n+1. Инструкция LDR R0, [Rx,#5] вешала систему. Фактически структура была что-то типа: void * U8 void * .. Я сделал void * void * U8 .. после чего все заработало. P.S. KEIL 5.x
Сообщение отредактировал KnightIgor - Aug 10 2014, 16:50
|
|
|
|
|
Aug 11 2014, 08:43
|

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

|
Цитата(KnightIgor @ Aug 10 2014, 19:49)  У меня указатель был расположен после U8. В то время как вся структура была размещена с выравниванием 4, поле указателя имело адрес 4*n+1. Инструкция LDR R0, [Rx,#5] вешала систему. Полагаю, вы чего-то недоговариваете. Если структура была обявлена без квалификатора packed, то компиляор был обязан выровнять указатель на его размер, т.е. на 4 байта, пропустив перед ним необходимое количество байтов. Если структура объявлена с packed, то компилятор пропускать байты не будет, но если процессор не умеет невыровненный доступ (как в случае с Cortex-M0) - компилятор обязан каждое многобайтовое поле считать побайтно и собрать целиком уже в регистрах. То есть он не имел права использовать в этом месте LDR R0, [Rx,#5]. Значит это либо ошибка компилятора (что маловероятно), либо вы использовали явное приведение типа, приведя (void *) к чему-то другому, но забыв packed в приводимом типе. Попробуйте воспроизвести ситуацию еще раз, попытаемся докопаться до причины.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Aug 11 2014, 09:59
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
вроде как-то уже такое обсуждали, но так и не смогли придумать примера когда это произойдет, однако уже 2 свидетельство косяка по этой причине... Интересно правда поглядеть какой код все таки рушит такие доступы. я вот только такой пример знаю Код char Array[8]; int *P = (int *)&Array[2]; *p = 10; в некоторых процах такой маневр приводил к замене не 2, 3, 4, 5 байтов, а все равно к замене 0, 1, 2, 3. Допускаю что такой же ход в кортексе М0 должен взывать падение, я прав?
|
|
|
|
|
Aug 12 2014, 10:08
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(Сергей Борщ @ Aug 11 2014, 10:43)  Полагаю, вы чего-то недоговариваете. Попробуйте воспроизвести ситуацию еще раз, попытаемся докопаться до причины. Я попытался откатить код. Слетает. Конечно, не в момент заполнения структуры как таковой: в некую процедуру передается указатель на поле структуры типа (void *), а внутри есть инструкция: LDR R0, [R0, #0], при этом R0 = 0x20000035, т.к. R0 это и есть входной параметр процедуры и указывает на поле типа (void *), которая размещена после поля U8, почему и такой нечетный адрес. Эта инструкция загрузки с нечетного адреса и вызывает исключение в -M0, в то время как -M3 все кушает без проблем.
|
|
|
|
|
Aug 12 2014, 12:33
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(Сергей Борщ @ Aug 12 2014, 13:39)  Так вот это оно и есть. Против лома компилятор бессилен. Попробуйте передавать указатель типа (void * __packed), если компилятор такое позволяет. Я переразместил поля структуры, чтобы было выровнено. Была такая возможность. Конечно, у компилятора против лома нет приема, но и передать в процедуру в качестве параметра поле структуры тоже легитимно. Надеюсь, что для топикстартера описаное мной поведение может помочь найти подобные навороты.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|