|
|||||||
Отлов причины ошибки HardFault в Миландр
Время создания: 21.08.2014 08:34
Текстовые метки: Миландр, Milandr, контроллер, ошибка, hardfault, поймать, отлов, проверка
Раздел: Linux, компиляция, C/C++ - ARM - Milandr
Запись: xintrea/mytetra_db_harpokrat/master/base/1408595670dcnub6ox6y/text.html на raw.githubusercontent.com
|
|||||||
|
|||||||
На основе документации: http://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html Стек в момент HardFault содержит состояние регистров ядра ARM. Код ниже показывает, как считать эти регистры в переменные С. После этого можно посмотреть значения этих переменных в отладчике (так же как и других переменных). Сначала, небольшая ассемблерная функция которая определяет, какой стек использовался в момент возникновения ошибки. Как только это будет сделано, ассемблерный код обработчика ошибок передает указатель на стек в функцию C, называемую prvGetRegistersFromStack(). Ниже показан обработчик ошибок, использующий синтаксис GCC. Обратите внимание, что функция объявлена как незашифрованная, поэтому она не содержит никакого кода, сгенерированного компилятором (например, нет кода пролога для ввода функции). /* The prototype shows it is a naked function - in effect this is just an assembly function. */ static void HardFault_Handler( void ) __attribute__( ( naked ) ); /* The fault handler implementation calls a function called prvGetRegistersFromStack(). */ static void HardFault_Handler(void) { __asm volatile ( " tst lr, #4 \n" " ite eq \n" " mrseq r0, msp \n" " mrsne r0, psp \n" " ldr r1, [r0, #24] \n" " ldr r2, handler2_address_const \n" " bx r2 \n" " handler2_address_const: .word prvGetRegistersFromStack \n" ); } Ниже показана реализация функции prvGetRegistersFromStack(). Функция prvGetRegistersFromStack() копирует значения регистров из стека в переменные C, а затем выполняет цикл. Имена переменных указывают на значение регистра, которое они содержат. Другие регистры не изменились с момента возникновения ошибки, и их можно просмотреть непосредственно в окне регистра процессора отладчика. void prvGetRegistersFromStack( uint32_t *pulFaultStackAddress ) { /* These are volatile to try and prevent the compiler/linker optimising them away as the variables never actually get used. If the debugger won't show the values of the variables, make them global my moving their declaration outside of this function. */ volatile uint32_t r0; volatile uint32_t r1; volatile uint32_t r2; volatile uint32_t r3; volatile uint32_t r12; volatile uint32_t lr; /* Link register. */ volatile uint32_t pc; /* Program counter. */ volatile uint32_t psr;/* Program status register. */ r0 = pulFaultStackAddress[ 0 ]; r1 = pulFaultStackAddress[ 1 ]; r2 = pulFaultStackAddress[ 2 ]; r3 = pulFaultStackAddress[ 3 ]; r12 = pulFaultStackAddress[ 4 ]; lr = pulFaultStackAddress[ 5 ]; pc = pulFaultStackAddress[ 6 ]; psr = pulFaultStackAddress[ 7 ]; /* When the following line is hit, the variables contain the register values. */ for( ;; ); } Использование значений регистров Первым интересующим нас регистром является программный счетчик pc. В приведенном выше коде переменная pc содержит значение программного счетчика. pc содержит адрес команды, которая выполнялась при возникновении ошибки в железе Hard Fault (или другой ошибки). Для поиска инструкции по адресу, указанному в переменной pc...:
Знание команды, которая выполнялась в момент возникновения ошибки, позволяет вам узнать, какие другие значения регистров также представляют интерес. Например, если команда использовала значение R7 в качестве адреса, то необходимо знать значение регистра R7. Далее, изучение ассемблерного кода в паре с кодом на C, который сгенерировал ассемблерный код, покажет, что на самом деле содержит R7 (например, это может быть значение переменной). |
|||||||
Так же в этом разделе:
|
|||||||
|
|||||||
|