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

Исследование HardFault, вставка ассемблера

Хочу включить в проект на Keil исследование причины вылета в HardFault. Но в ассемблере никак не могу разобраться. Смысл я в общем понял в ассемблерном куске кода копируются данные регистров которые нужно проверить, а в Си функции уже их разбираемым.

Есть startupxxx.s файл, в нем есть описание этой функции по умолчанию и там стоит атрибут WEAK. Посмотрел он указывает на то, что эта функция может быть переопределена в другом месте и будет иметь приоритет. 

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

Подскажите как правильно прикрутить asm файл с функцией HardFault, чтоб в main.c описать функцию void HardFaultHandler(unsigned int* pStack){...}

;----------------------------------------------------------------------
;File : HardFaultHandler.S
;Purpose : HardFault exception handler for Keil assembler.
;-------- END-OF-HEADER ---------------------------------------------
;*/

 AREA OSKERNEL, CODE, READONLY, ALIGN=2
 PRESERVE8
 EXPORT HardFault_Handler

 IMPORT HardFault_Handler

 THUMB


HardFault_Handler

 ;// This version is for Cortex M0
 movs R0, #4
 mov R1, LR
 tst R0, R1 ;// Check EXC_RETURN in Link register bit 2.
 bne Uses_PSP
 mrs R0, MSP ;// Stacking was using MSP.
 b Pass_StackPtr

Uses_PSP

 mrs R0, PSP ;// Stacking was using PSP.

Pass_StackPtr

 ALIGN

 ldr R2,=HardFaultHandler
 bx R2 ;// Stack pointer passed through R0.


 END

;/****** End Of File *************************************************/

 

Или второй вариант. Пробую написать этот код в startup файле

; Dummy Exception Handlers (infinite loops which can be modified)

NMI_Handler     PROC
                EXPORT  NMI_Handler                    [WEAK]
                B       .
                ENDP
HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler              [WEAK]
;// This version is for Cortex M0
 movs R0, #4
 mov R1, LR
 tst R0, R1 ;// Check EXC_RETURN in Link register bit 2.
 bne Uses_PSP
 mrs R0, MSP ;// Stacking was using MSP.
 b Pass_StackPtr

Uses_PSP

 mrs R0, PSP ;// Stacking was using PSP.

Pass_StackPtr

 ALIGN

 ldr R2,=HardFaultHandler
 bx R2 ;// Stack pointer passed through R0.
					
                B       .
                ENDP
SVC_Handler     PROC
...

А в main.c прописываю

extern void HardFaultHandler(unsigned int* pStack);
void HardFaultHandler(unsigned int* pStack){
...	
}

Тогда компилятор ругается что в startup файле символ HardFaultHandler не определен. Может его нужно как то определить в startup.s а не в main.c

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


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

Прошу прощения, только создал сообщение и нашел ошибку. 

IMPORT HardFault_Handler

Брал из готового примера. Неудобно когда похожие названия.

В общем исправил, вроде все собралось, буду проверять.

EXPORT HardFault_Handler

IMPORT HardFaultHandler_с

...

ldr R2,=HardFaultHandler_с

И в main.c

extern void HardFaultHandler_с(unsigned int* pStack);
void HardFaultHandler_с(unsigned int* pStack){
	
}

 

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

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


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

Вот полный пример кода исследования HatdFault.

HardFaultHandler.s

AREA OSKERNEL, CODE, READONLY, ALIGN=2
 PRESERVE8
 EXPORT HardFault_Handler
 IMPORT HardFaultHandler_c
 THUMB

HardFault_Handler
 movs R0, #4
 mov R1, LR
 tst R0, R1 ;// Check EXC_RETURN in Link register bit 2.
 bne Uses_PSP
 mrs R0, MSP ;// Stacking was using MSP.
 b Pass_StackPtr

Uses_PSP
 mrs R0, PSP ;// Stacking was using PSP.

Pass_StackPtr
 ALIGN
 ldr R2,=HardFaultHandler_c
 bx R2 ;// Stack pointer passed through R0.

END

HardFaultHandler_c.c

// System Handler Control and State Register
#define SYSHND_CTRL (*(volatile unsigned int*) (0xE000ED24u))
// Memory Management Fault Status Register
#define NVIC_MFSR (*(volatile unsigned char*) (0xE000ED28u))
// Bus Fault Status Register
#define NVIC_BFSR (*(volatile unsigned char*) (0xE000ED29u))
// Usage Fault Status Register
#define NVIC_UFSR (*(volatile unsigned short*)(0xE000ED2Au))
// Hard Fault Status Register
#define NVIC_HFSR (*(volatile unsigned int*) (0xE000ED2Cu))
// Debug Fault Status Register
#define NVIC_DFSR (*(volatile unsigned int*) (0xE000ED30u))
// Bus Fault Manage Address Register
#define NVIC_BFAR (*(volatile unsigned int*) (0xE000ED38u))
// Auxiliary Fault Status Register
#define NVIC_AFSR (*(volatile unsigned int*) (0xE000ED3Cu))

static volatile unsigned int _Continue; // Set this variable to 1 to run further
static struct {
 struct {
 volatile unsigned int r0; // Register R0
 volatile unsigned int r1; // Register R1
 volatile unsigned int r2; // Register R2
 volatile unsigned int r3; // Register R3
 volatile unsigned int r12; // Register R12
 volatile unsigned int lr; // Link register
 volatile unsigned int pc; // Program counter
 union {
 volatile unsigned int byte;
 struct {
 unsigned int IPSR : 8; // Interrupt Program Status register (IPSR)
 unsigned int EPSR : 19; // Execution Program Status register (EPSR)
 unsigned int APSR : 5; // Application Program Status register (APSR)
 } bits;
 } psr; // Program status register.
 } SavedRegs;
 union {
 volatile unsigned int byte;
 struct {
 unsigned int MEMFAULTACT : 1; // Read as 1 if memory management fault
 // is active
 unsigned int BUSFAULTACT : 1; // Read as 1 if bus fault exception is active
 unsigned int UnusedBits1 : 1;
 unsigned int USGFAULTACT : 1; // Read as 1 if usage fault exception
 // is active
 unsigned int UnusedBits2 : 3;
 unsigned int SVCALLACT : 1; // Read as 1 if SVC exception is active
 unsigned int MONITORACT : 1; // Read as 1 if debug monitor exception
 // is active
 unsigned int UnusedBits3 : 1;
 unsigned int PENDSVACT : 1; // Read as 1 if PendSV exception is active
 unsigned int SYSTICKACT : 1; // Read as 1 if SYSTICK exception is active
 unsigned int USGFAULTPENDED : 1; // Usage fault pended; usage fault started
 // but was replaced by a higher-priority
 // exception
 unsigned int MEMFAULTPENDED : 1; // Memory management fault pended; memory
 // management fault started but was
 // replaced by a higher-priority exception
 unsigned int BUSFAULTPENDED : 1; // Bus fault pended; bus fault handler was
 // started but was replaced by a
 // higher-priority exception
 unsigned int SVCALLPENDED : 1; // SVC pended; SVC was started but was
 // replaced by a higher-priority exception
 unsigned int MEMFAULTENA : 1; // Memory management fault handler enable
 unsigned int BUSFAULTENA : 1; // Bus fault handler enable
 unsigned int USGFAULTENA : 1; // Usage fault handler enable
 } bits;
 } syshndctrl; // System Handler Control and State
 // Register (0xE000ED24)
 union {
 volatile unsigned char byte;
 struct {
 unsigned char IACCVIOL : 1; // Instruction access violation
 unsigned char DACCVIOL : 1; // Data access violation
 unsigned char UnusedBits : 1;
 unsigned char MUNSTKERR : 1; // Unstacking error
 unsigned char MSTKERR : 1; // Stacking error
 unsigned char UnusedBits2 : 2;
 unsigned char MMARVALID : 1; // Indicates the MMAR is valid
 } bits;
 } mfsr; // Memory Management Fault Status
 // Register (0xE000ED28)
 union {
 volatile unsigned int byte;
 struct {
 unsigned int IBUSERR : 1; // Instruction access violation
 unsigned int PRECISERR : 1; // Precise data access violation
 unsigned int IMPREISERR : 1; // Imprecise data access violation
 unsigned int UNSTKERR : 1; // Unstacking error
 unsigned int STKERR : 1; // Stacking error
 unsigned int UnusedBits : 2;
 unsigned int BFARVALID : 1; // Indicates BFAR is valid
 } bits;
 } bfsr; // Bus Fault Status Register (0xE000ED29)
 volatile unsigned int bfar; // Bus Fault Manage Address Register
 // (0xE000ED38)
 union {
 volatile unsigned short byte;
 struct {
 unsigned short UNDEFINSTR : 1; // Attempts to execute an undefined
 // instruction
 unsigned short INVSTATE : 1; // Attempts to switch to an invalid state
 // (e.g., ARM)
 unsigned short INVPC : 1; // Attempts to do an exception with a bad
 // value in the EXC_RETURN number
 unsigned short NOCP : 1; // Attempts to execute a coprocessor
 // instruction
 unsigned short UnusedBits : 4;
 unsigned short UNALIGNED : 1; // Indicates that an unaligned access fault
 // has taken place
 unsigned short DIVBYZERO : 1; // Indicates a divide by zero has taken
 // place (can be set only if DIV_0_TRP
 // is set)
 } bits;
 } ufsr; // Usage Fault Status Register (0xE000ED2A)
 union {
 volatile unsigned int byte;
 struct {
 unsigned int UnusedBits : 1;
 unsigned int VECTBL : 1; // Indicates hard fault is caused by failed
 // vector fetch
 unsigned int UnusedBits2 : 28;
 unsigned int FORCED : 1; // Indicates hard fault is taken because of
 // bus fault/memory management fault/usage
 // fault
 unsigned int DEBUGEVT : 1; // Indicates hard fault is triggered by
 // debug event
 } bits;
 } hfsr; // Hard Fault Status Register (0xE000ED2C)
 union {
 volatile unsigned int byte;
 struct {
 unsigned int HALTED : 1; // Halt requested in NVIC
 unsigned int BKPT : 1; // BKPT instruction executed
 unsigned int DWTTRAP : 1; // DWT match occurred
 unsigned int VCATCH : 1; // Vector fetch occurred
 unsigned int EXTERNAL : 1; // EDBGRQ signal asserted
 } bits;
 } dfsr; // Debug Fault Status Register (0xE000ED30)
 volatile unsigned int afsr; // Auxiliary Fault Status Register
 // (0xE000ED3C) Vendor controlled (optional)
} HardFaultRegs;

void HardFaultHandler_c(unsigned int* pStack);
void HardFaultHandler_c(unsigned int* pStack) {

if (NVIC_HFSR & (1uL << 31)) {
 NVIC_HFSR |= (1uL << 31); // Reset Hard Fault status
 *(pStack + 6u) += 2u; // PC is located on stack at SP + 24 bytes;
 // increment PC by 2 to skip break instruction.
 return; // Return to interrupted application
}
 //
 // Read NVIC registers
 //
 HardFaultRegs.syshndctrl.byte = SYSHND_CTRL; // System Handler Control and
 // State Register
 HardFaultRegs.mfsr.byte = NVIC_MFSR; // Memory Fault Status Register
 HardFaultRegs.bfsr.byte = NVIC_BFSR; // Bus Fault Status Register
 HardFaultRegs.bfar = NVIC_BFAR; // Bus Fault Manage Address Register
 HardFaultRegs.ufsr.byte = NVIC_UFSR; // Usage Fault Status Register
 HardFaultRegs.hfsr.byte = NVIC_HFSR; // Hard Fault Status Register
 HardFaultRegs.dfsr.byte = NVIC_DFSR; // Debug Fault Status Register
 HardFaultRegs.afsr = NVIC_AFSR; // Auxiliary Fault Status Register
 //
 // Halt execution
 // If NVIC registers indicate readable memory, change the variable value
 // to != 0 to continue execution.
 //
 _Continue = 0u;
 while (_Continue == 0u);
 //
 // Read saved registers from the stack
 //
 HardFaultRegs.SavedRegs.r0 = pStack[0]; // Register R0
 HardFaultRegs.SavedRegs.r1 = pStack[1]; // Register R1
 HardFaultRegs.SavedRegs.r2 = pStack[2]; // Register R2
 HardFaultRegs.SavedRegs.r3 = pStack[3]; // Register R3
 HardFaultRegs.SavedRegs.r12 = pStack[4]; // Register R12
 HardFaultRegs.SavedRegs.lr = pStack[5]; // Link register LR
 HardFaultRegs.SavedRegs.pc = pStack[6]; // Program counter PC
 HardFaultRegs.SavedRegs.psr.byte = pStack[7]; // Program status word PSR
 //
 // Halt execution
 // To step out of the HardFaultHandler, change the variable value to != 0.
 //
 _Continue = 0u;
 while (_Continue == 0u) {
 }
}

В общем после вылета в HardFault в режиме отладки проверяю структуру HardFaultRegs и там все значения 0. Где то ошибка в функции, как узнать причину?

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


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

Так отладчик и сам показывает HF регистры. Главное - определить адрес программы, откуда улетели.

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


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

Покажу мой обработчик. :)

/*!*****************************************************************************
  @brief	Simple HardFault Handler
  @details	В пошаговом режиме переставить программный счетчик на BX и шагнуть
  @note		PC будет содержать команду, следующую за вызвавшей сбой
  */
__asm void HardFault_Handler(void)
{
	B .
	BX LR
}

 

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


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

23 minutes ago, ViKo said:

Покажу мой обработчик. :)

Ага, он будет особенно полезен для удаленной диагностики, или когда у МК задействовано 20 из 20 выводов, например.

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


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

10 минут назад, aaarrr сказал:

Ага, он будет особенно полезен для удаленной диагностики, или когда у МК задействовано 20 из 20 выводов, например.

Для имитации сбоя от удаленного пользователя у меня на столе стоит такой же прибор.

И у топикстартера тоже не видно передачи наружу отладочной информации.

А "МК 20 из 20" обязательно предполагает наличие внешнего интерфейса, хотя бы для удаленной диагностики? А если не вмещается?

В остальном - согласен с вами. :)

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


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

6 minutes ago, ViKo said:

Для имитации сбоя от удаленного пользователя у меня на столе стоит такой же прибор.

Возможно, поможет воспроизвести ситуацию от удаленного пользователя, но не поможет, если у удаленного прибора непосредственного пользователя не предусмотрено.

 

6 minutes ago, ViKo said:

А "МК 20 из 20" обязательно предполагает наличие внешнего интерфейса, хотя бы для удаленной диагностики? А если не вмещается?

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

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


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

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

8 минут назад, aaarrr сказал:

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

А потом что с ней (флэш-памятью) делать? Особенно удаленно и без интерфейса.

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


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

Еще меня заставляет задуматься следующее. Допустим, получил дистанционно всю информацию о сбое. Надо же знать, какая версия программы записана в приборе. И держать в полной готовности все версии программы, чтобы достоверно находить адрес сбоя. Не слишком ли? Хорошо, если приборы и обновляются автоматически до последней версии.

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


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

1 hour ago, ViKo said:

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

Даже квалифицированный пользователь не всегда сможет внятно описать проблему и метод её воспроизведения. Он же не тестировщик.

 

1 hour ago, ViKo said:

А потом что с ней (флэш-памятью) делать? Особенно удаленно и без интерфейса.

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

 

1 hour ago, ViKo said:

Еще меня заставляет задуматься следующее. Допустим, получил дистанционно всю информацию о сбое. Надо же знать, какая версия программы записана в приборе. И держать в полной готовности все версии программы, чтобы достоверно находить адрес сбоя. Не слишком ли? Хорошо, если приборы и обновляются автоматически до последней версии.

На то есть системы контроля версий. Но даже и без них как минимум безответственно выпускать релиз и не сохранять архив.

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


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

4 минуты назад, aaarrr сказал:

Даже квалифицированный пользователь не всегда сможет внятно описать проблему и метод её воспроизведения. Он же не тестировщик.

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

На то есть системы контроля версий. Но даже и без них как минимум безответственно выпускать релиз и не сохранять архив.

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

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

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

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


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

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

Так отладчик и сам показывает HF регистры. Главное - определить адрес программы, откуда улетели.

Очень часто это не даёт ровным счётом ничего. Ну увидите Вы что улетели изнутри функции printf или memcpy - что это даст?

Нужны все регистры + кадр стека. А также содержимое-расшифровка регистров HF.

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


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

3 минуты назад, jcxz сказал:

Очень часто это не даёт ровным счётом ничего. Ну увидите Вы что улетели изнутри функции printf или memcpy - что это даст?

Нужны все регистры + кадр стека. А также содержимое-расшифровка регистров HF.

Так я же зависаю в обработчике. Все регистры, все ошибки на своем месте. И в отладчике вижу их всех.

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


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

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

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

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

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

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

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

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

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

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