

maxntf
Участник-
Posts
112 -
Joined
-
Last visited
-
Исследование HardFault, вставка ассемблера
maxntf replied to maxntf's topic in ARM, 32bit
У меня при таких действиях происходит следующее: Первый брекпоинт на 'B .' PC = текущему адресу, LR = 0xFFFFFFF1 Переставляю указатель на BX LR, делаю шаг в отладчике и получаю PC = 0х000010BC, LR = 0x00000F03. Это вообще похоже на системную память. Что я делаю не так? -
Исследование HardFault, вставка ассемблера
maxntf replied to maxntf's topic in ARM, 32bit
Регистр LR? -
Исследование HardFault, вставка ассемблера
maxntf replied to maxntf's topic in ARM, 32bit
Вот полный пример кода исследования 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. Где то ошибка в функции, как узнать причину? -
Исследование HardFault, вставка ассемблера
maxntf replied to maxntf's topic in ARM, 32bit
Прошу прощения, только создал сообщение и нашел ошибку. IMPORT HardFault_Handler Брал из готового примера. Неудобно когда похожие названия. В общем исправил, вроде все собралось, буду проверять. EXPORT HardFault_Handler IMPORT HardFaultHandler_с ... ldr R2,=HardFaultHandler_с И в main.c extern void HardFaultHandler_с(unsigned int* pStack); void HardFaultHandler_с(unsigned int* pStack){ } -
Исследование HardFault, вставка ассемблера
maxntf posted a topic in ARM, 32bit
Хочу включить в проект на 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 -
Спасибо! То, что нужно. FUNC void Setup (void) { SP = _RDWORD(0x08005000); // Setup Stack Pointer PC = _RDWORD(0x08005004); // Setup Program Counter XPSR = 0x01000000; // Set Thumb bit } Setup(); LOAD %L INCREMENTAL nocode // load debug info without performing reset FUNC void OnResetExec(void) { Setup(); }
-
Это куда? Вот файлик debug.ini FUNC void Setup (void) { SP = _RDWORD(0x08005000); // Setup Stack Pointer PC = _RDWORD(0x08005004); // Setup Program Counter XPSR = 0x01000000; // Set Thumb bit } Setup(); LOAD %L INCREMENTAL nocode // load debug info without performing reset Там бы дописать что-то типа: IF(RESET) Setup(); Только возможно ли такое? У меня сейчас получается что при загрузке отладчика срабатывает функция Setup(), а когда я нажимаю в нем Reset то SP и PC сбрасываются. И получается что нужно перезагружать отладчик.
-
Отлаживаю в Keil - ST-Link Debugger. Попробовал по совету x893 создал файл debug.ini. Похоже это то, что мне нужно. Только там получается что при запуске отладчика, он стартует с 0x08005004, а после reset(в отладчике) уже с 0x08000004. Помогите пожалуйста допилить этот ini.
-
Подскажите как отладчику указать, чтоб он стартовал с определенного адреса? Читал, что вроде как нужно в скаттер файле определить точку входа через команду ENTRY. Только как это сделать я не знаю, что указывать в ее параметрах? Или это не то? Сам файл у меня тот, что предлагается стандартно (с измененной адресацией под бут) ; ************************************************************* ; *** Scatter-Loading Description File generated by uVision *** ; ************************************************************* LR_IROM1 0x08005000 0x0000B000 { ; load region size_region ER_IROM1 0x08005000 0x0000B000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x200000C0 0x00001F40 { ; RW data .ANY (+RW +ZI) } }
-
Спасибо, понял в чем тут дело. Просто раньше работал только с 8 битными МК, там таких проблем нет. А у меня получилось, что буфер char - выравнивание у него по одному байту (без атрибута, начинаться может с любого адреса), а в качестве аргумента функции я передаю указатель на этот буфер с приведением типа до uint32.
-
Всем привет, наткнулся на такой баг - объявил буфер в глобальных переменных. Передаю его адрес в аргументе функции. И когда обращаюсь в функции к этой переменной через указатель сразу вылетаю в HardFault_Handler. Пол дня парился, и в конце концов выяснил, что линковщик расположил ее по адресу не кратному 4. Проверил, действительно если передать в функцию указатель не кратный 4, то при чтении по этому адресу вылетаем в HardFault_Handler. И теперь не могу добиться, чтоб этот буфер разместился по корректному адресу. Добавляю перед ним или после него новые переменные, адреса смещаются, и у него все равно адрес не корректный. Что делать? P.S Keil V5.23.0.0
-
Да как только отключил, все работает нормально.
-
Понял. То есть даже если не включены прерывания по ошибкам, флаги все равно нужно сбрасывать при их установке?
-
Народ подскажите, натолкнулся на такую штуку: Включен USART1 на прием и разрешен только один тип прерывания по приему байта. void USART1_IRQHandler(void){ char bt; if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET){ bt = (char)USART_ReceiveData(USART1); USART_ClearITPendingBit(USART1, USART_IT_RXNE); if(bt != 0){ bUartRx[cUartRx] = bt; if(cUartRx >= (BRXSIZE-2)) bUartRx[(BRXSIZE-1)] = 0, cUartRx = 0, fUartRxOver = 1; else cUartRx++, bUartRx[cUartRx] = 0; xSemaphoreGiveFromISR(xSemRxInBuf, NULL); } } } void UART_Init(void){ GPIO_InitTypeDef GPIO_InitStruct; USART_InitTypeDef USART_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1); USART_InitStruct.USART_BaudRate = 19200; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_InitStruct.USART_Parity = USART_Parity_No; USART_InitStruct.USART_StopBits = USART_StopBits_1; USART_InitStruct.USART_WordLength = USART_WordLength_8b; USART_Init(USART1, &USART_InitStruct); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_Cmd(USART1, ENABLE); NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPriority = 0; NVIC_Init(&NVIC_InitStruct); Так вот, во время отладки при нажатии Stop или остановки по брекпоинту, если в этот момент что то принималось в UART, то после запуска отладчика все время висим в обработчике прерывания. Причем все флаги сброшены и больше не устанавливаются, даже если приходят данные. P.S. STM32F051R8T6 Keil v.5.23.0.0
-
Меня интересует, нужна ли повторная инициализация startup в основной программе, или от нее нужно избавиться?