maxntf 0 27 октября, 2018 Опубликовано 27 октября, 2018 · Жалоба Хочу включить в проект на 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
maxntf 0 27 октября, 2018 Опубликовано 27 октября, 2018 (изменено) · Жалоба Прошу прощения, только создал сообщение и нашел ошибку. IMPORT HardFault_Handler Брал из готового примера. Неудобно когда похожие названия. В общем исправил, вроде все собралось, буду проверять. EXPORT HardFault_Handler IMPORT HardFaultHandler_с ... ldr R2,=HardFaultHandler_с И в main.c extern void HardFaultHandler_с(unsigned int* pStack); void HardFaultHandler_с(unsigned int* pStack){ } Изменено 27 октября, 2018 пользователем maxntf Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
maxntf 0 27 октября, 2018 Опубликовано 27 октября, 2018 · Жалоба Вот полный пример кода исследования 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. Где то ошибка в функции, как узнать причину? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 27 октября, 2018 Опубликовано 27 октября, 2018 · Жалоба Так отладчик и сам показывает HF регистры. Главное - определить адрес программы, откуда улетели. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
maxntf 0 27 октября, 2018 Опубликовано 27 октября, 2018 · Жалоба Регистр LR? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 27 октября, 2018 Опубликовано 27 октября, 2018 · Жалоба Покажу мой обработчик. :) /*!***************************************************************************** @brief Simple HardFault Handler @details В пошаговом режиме переставить программный счетчик на BX и шагнуть @note PC будет содержать команду, следующую за вызвавшей сбой */ __asm void HardFault_Handler(void) { B . BX LR } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 63 27 октября, 2018 Опубликовано 27 октября, 2018 · Жалоба 23 minutes ago, ViKo said: Покажу мой обработчик. :) Ага, он будет особенно полезен для удаленной диагностики, или когда у МК задействовано 20 из 20 выводов, например. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 27 октября, 2018 Опубликовано 27 октября, 2018 · Жалоба 10 минут назад, aaarrr сказал: Ага, он будет особенно полезен для удаленной диагностики, или когда у МК задействовано 20 из 20 выводов, например. Для имитации сбоя от удаленного пользователя у меня на столе стоит такой же прибор. И у топикстартера тоже не видно передачи наружу отладочной информации. А "МК 20 из 20" обязательно предполагает наличие внешнего интерфейса, хотя бы для удаленной диагностики? А если не вмещается? В остальном - согласен с вами. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 63 27 октября, 2018 Опубликовано 27 октября, 2018 · Жалоба 6 minutes ago, ViKo said: Для имитации сбоя от удаленного пользователя у меня на столе стоит такой же прибор. Возможно, поможет воспроизвести ситуацию от удаленного пользователя, но не поможет, если у удаленного прибора непосредственного пользователя не предусмотрено. 6 minutes ago, ViKo said: А "МК 20 из 20" обязательно предполагает наличие внешнего интерфейса, хотя бы для удаленной диагностики? А если не вмещается? Если есть возможность так или иначе зафиксировать сам факт сбоя, то можно и во флеш данные о последней ошибке сохранять. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 27 октября, 2018 Опубликовано 27 октября, 2018 · Жалоба У моих приборов пользователи есть, обычно сидят напротив и втыкают в происходящее. 8 минут назад, aaarrr сказал: Если есть возможность так или иначе зафиксировать сам факт сбоя, то можно и во флеш данные о последней ошибке сохранять. А потом что с ней (флэш-памятью) делать? Особенно удаленно и без интерфейса. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 27 октября, 2018 Опубликовано 27 октября, 2018 · Жалоба Еще меня заставляет задуматься следующее. Допустим, получил дистанционно всю информацию о сбое. Надо же знать, какая версия программы записана в приборе. И держать в полной готовности все версии программы, чтобы достоверно находить адрес сбоя. Не слишком ли? Хорошо, если приборы и обновляются автоматически до последней версии. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 63 27 октября, 2018 Опубликовано 27 октября, 2018 · Жалоба 1 hour ago, ViKo said: У моих приборов пользователи есть, обычно сидят напротив и втыкают в происходящее. Даже квалифицированный пользователь не всегда сможет внятно описать проблему и метод её воспроизведения. Он же не тестировщик. 1 hour ago, ViKo said: А потом что с ней (флэш-памятью) делать? Особенно удаленно и без интерфейса. Прочитать, когда на оленях назад привезут. Лучше иметь хоть какой-то источник информации, чем совсем никакого. 1 hour ago, ViKo said: Еще меня заставляет задуматься следующее. Допустим, получил дистанционно всю информацию о сбое. Надо же знать, какая версия программы записана в приборе. И держать в полной готовности все версии программы, чтобы достоверно находить адрес сбоя. Не слишком ли? Хорошо, если приборы и обновляются автоматически до последней версии. На то есть системы контроля версий. Но даже и без них как минимум безответственно выпускать релиз и не сохранять архив. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 27 октября, 2018 Опубликовано 27 октября, 2018 · Жалоба 4 минуты назад, aaarrr сказал: Даже квалифицированный пользователь не всегда сможет внятно описать проблему и метод её воспроизведения. Он же не тестировщик. Прочитать, когда на оленях назад привезут. Лучше иметь хоть какой-то источник информации, чем совсем никакого. На то есть системы контроля версий. Но даже и без них как минимум безответственно выпускать релиз и не сохранять архив. Если человек не может внятно описать, какая последовательность действий привела к ошибке (а такое бывает), то сам процессор тем более не сохранит в лог, какие сигналы приходили, какие органы управления использовались, какие режимы задавались, по какому боку его хлопали. Получить прибор с зафиксированным глюком не будет быстрее, чем сымитировать его. Особенно, учитывая сказанное выше. Систему контроля версий использую. Всплывают тонкости, когда добавляешь-убираешь файл из проекта. Приходится руками править проект, сначала в одну сторону, потом обратно. Неприятное действо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 183 27 октября, 2018 Опубликовано 27 октября, 2018 · Жалоба 3 часа назад, ViKo сказал: Так отладчик и сам показывает HF регистры. Главное - определить адрес программы, откуда улетели. Очень часто это не даёт ровным счётом ничего. Ну увидите Вы что улетели изнутри функции printf или memcpy - что это даст? Нужны все регистры + кадр стека. А также содержимое-расшифровка регистров HF. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 27 октября, 2018 Опубликовано 27 октября, 2018 · Жалоба 3 минуты назад, jcxz сказал: Очень часто это не даёт ровным счётом ничего. Ну увидите Вы что улетели изнутри функции printf или memcpy - что это даст? Нужны все регистры + кадр стека. А также содержимое-расшифровка регистров HF. Так я же зависаю в обработчике. Все регистры, все ошибки на своем месте. И в отладчике вижу их всех. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться