содержимое стека Я написал простую процедуру прерывания ввода-вывода для проверки вывода ввода-вывода в кору ARM m4 (cm408F). Код ниже и очень простой и заполняет таблицу векторов (также включает в себя прагма слабые и другие вещи).
Я запускаю прерывание, устанавливая соответствующие биты в NVIC_ISER0 и NVIC_ISPR0. В момент возникновения прерывания процессор выдает мне следующее исключение при сбое и зацикливается на загрузочном ПЗУ L1.
Процессор превратил исключение настраиваемого приоритета в HardFault.
Инструкция выполнена с недопустимым полем EPSR.T или EPSR.IT (CFSR.INVSTATE).
Исключение произошло при ПК = 0xffffffff, LR = 0x0
В окне стека вызовов я вижу:
__iar_systems$$modulde + 0x1451
Может ли это помочь?
Я также добавил цикл while (1) для HardFault_Handler.
Таким образом, если процессор фактически утверждает HardFault_Handler, он должен идти в этот бесконечный цикл, но он никогда не идет туда. Не имеет значения, какое прерывание активировано (через NVIC_ISER0 и NVIC_ISPR0), возникает та же проблема (при получении прерывания оно скачет и застревает в цикле в строке загрузочного ПЗУ L1: 1452!).
Я прикрепил снимок стека, как только прерывание поднято. Прежде чем поднять прерывание я изменился
содержимое R12 и R0-R3 (0x1238 .... 0x1234), чтобы лучше реализовать их в стеке. Как я сказал
когда прерывание поднято, программа никогда не возвращается, поэтому я приостановил его и посмотрел на стек (прикрепленная картинка).
Кажется, что первый толчок в порядке; мы видим, что xPSR, ПК, LR, R12, R0-R3 все сложены правильно (FPU отключен).
Но во втором толкании в стек ПК равен нулю (LR в порядке)! Я предполагаю, что это показывает проблему. ПК не должен быть нулевым.
Почему он не возвращается из прерывания, нажав правильный адрес обратного адреса на ПК. Я думаю третий
толчок в стек является результатом этой проблемы.
До прерывания: SP = 0x2005FFF0
После прерывания: SP = 0x2005FFA4
............................
// My code is very simple as follows.
// main.c
#include <intrinsics.h>
int main()
{
int k1=123;
k1=k1+2*k1;
while(1)
{
k1=k1;
}
return 0;
}
// =========================================
// my_int_Routines.c
void PINT0_BLOCK_Int_Handler(void)
{
while(1)
{
asm("nop");
}
}
void PINT1_BLOCK_Int_Handler(void)
{
while(1)
{
asm("nop");
}
}
void PINT2_BLOCK_Int_Handler(void)
{
while(1)
{
asm("nop");
}
}
void PINT3_BLOCK_Int_Handler(void)
{
while(1)
{
asm("nop");
}
}
void PINT4_BLOCK_Int_Handler(void)
{
while(1)
{
asm("nop");
}
}
// =====================================
// my_startup.c
// This is ARM standard cstartup.c in IAR folder. I only added the relevant lines
// (marked as Reza)
/**************************************************
*
* This file contains an interrupt vector for Cortex-M written in C.
* The actual interrupt functions must be provided by the application developer.
*
* Copyright 2007-2017 IAR Systems AB.
*
* $Revision: 112610 $
*
**************************************************/
#pragma language=extended
#pragma segment="CSTACK"
extern void __iar_program_start( void );
extern void NMI_Handler( void );
extern void HardFault_Handler( void );
extern void MemManage_Handler( void );
extern void BusFault_Handler( void );
extern void UsageFault_Handler( void );
extern void SVC_Handler( void );
extern void DebugMon_Handler( void );
extern void PendSV_Handler( void );
extern void SysTick_Handler( void );
extern void PINT0_BLOCK_Int_Handler(void); // 18 Pin Interrupt Block Reza
extern void PINT1_BLOCK_Int_Handler(void); // 19 Pin Interrupt Block Reza
extern void PINT2_BLOCK_Int_Handler(void); // 20 Pin Interrupt Block Reza
extern void PINT3_BLOCK_Int_Handler(void); // 21 Pin Interrupt Block Reza
extern void PINT4_BLOCK_Int_Handler(void); // 22 Pin Interrupt Block Reza
typedef void( *intfunc )( void );
typedef union { intfunc __fun; void * __ptr; } intvec_elem;
// The vector table is normally located at address 0.
// When debugging in RAM, it can be located in RAM, aligned to at least 2^6.
// If you need to define interrupt service routines,
// make a copy of this file and include it in your project.
// The name "__vector_table" has special meaning for C-SPY, which
// is where to find the SP start value.
// If vector table is not located at address 0, the user has to initialize
// the NVIC vector table register (VTOR) before using interrupts.
#pragma location = ".intvec"
const intvec_elem __vector_table[] =
{
{ .__ptr = __sfe( "CSTACK" ) },
__iar_program_start,
NMI_Handler,
HardFault_Handler,
MemManage_Handler,
BusFault_Handler,
UsageFault_Handler,
0,
0,
0,
0,
SVC_Handler,
DebugMon_Handler,
0,
PendSV_Handler,
SysTick_Handler,
// ******* Reza (all zeros below)
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
PINT0_BLOCK_Int_Handler, // 18 Pin Interrupt Block Reza
PINT1_BLOCK_Int_Handler, // 19 Pin Interrupt Block Reza
PINT2_BLOCK_Int_Handler, // 20 Pin Interrupt Block Reza
PINT3_BLOCK_Int_Handler, // 21 Pin Interrupt Block Reza
PINT4_BLOCK_Int_Handler // 22 Pin Interrupt Block Reza
};
#pragma call_graph_root = "interrupt"
__weak void NMI_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void HardFault_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void MemManage_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void BusFault_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void UsageFault_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void SVC_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void DebugMon_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void PendSV_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void SysTick_Handler( void ) { while (1) {} }
// ====================== Reza
#pragma call_graph_root = "interrupt"
__weak void PINT0_BLOCK_Int_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void PINT1_BLOCK_Int_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void PINT2_BLOCK_Int_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void PINT3_BLOCK_Int_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void PINT4_BLOCK_Int_Handler( void ) { while (1) {} }
void __cmain( void );
__weak void __iar_init_core( void );
__weak void __iar_init_vfp( void );
#pragma required=__vector_table
void __iar_program_start( void )
{
__iar_init_core();
__iar_init_vfp();
__cmain();
}