SmartOS/Interrupt.cpp

393 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Interrupt.h"
// GD32F150无法把向量表映射到RAM
#if defined(GD32) && defined(STM32F0xx)
#define VEC_TABLE_ON_RAM 0
#else
#define VEC_TABLE_ON_RAM 1
#endif
/*
完全接管中断在RAM中开辟中断向量表做到随时可换。
由于中断向量表要求128对齐这里多分配128字节找到对齐点后给向量表使用
为了增强中断函数处理我们使用_Vectors作为真正的中断向量表全部使用OnHandler作为中断处理函数。
然后在OnHandler内部获取中断号再调用Vectors中保存的用户委托并向它传递中断号和参数。
*/
TInterrupt Interrupt;
// 没有必要重定向中断向量表把所有中断硬编码指向IntcHandler和FAULT_SubHandler即可
// 真正的向量表 64k=0x10000
#if VEC_TABLE_ON_RAM
#ifdef STM32F0XX
__IO Func _Vectors[VectorySize] __attribute__((at(0x20000000)));
#else
// 84个中断向量向上取整到2整数倍也就是128128*4=512=0x200。CM3权威手册
__IO Func _Vectors[VectorySize] __attribute__((__aligned__(0x200)));
#endif
#endif
#define IS_IRQ(irq) (irq >= -16 && irq <= VectorySize - 16)
void TInterrupt::Init()
{
// 禁用所有中断
NVIC->ICER[0] = 0xFFFFFFFF;
#ifdef STM32F10X
NVIC->ICER[1] = 0xFFFFFFFF;
NVIC->ICER[2] = 0xFFFFFFFF;
#endif
// 清除所有中断位
NVIC->ICPR[0] = 0xFFFFFFFF;
#ifdef STM32F10X
NVIC->ICPR[1] = 0xFFFFFFFF;
NVIC->ICPR[2] = 0xFFFFFFFF;
#endif
#if VEC_TABLE_ON_RAM
memset((void*)_Vectors, 0, VectorySize << 2);
_Vectors[2] = (Func)&FaultHandler; // NMI
_Vectors[3] = (Func)&FaultHandler; // Hard Fault
_Vectors[4] = (Func)&FaultHandler; // MMU Fault
_Vectors[5] = (Func)&FaultHandler; // Bus Fault
_Vectors[6] = (Func)&FaultHandler; // Usage Fault
_Vectors[11] = (Func)&FaultHandler; // SVC
_Vectors[12] = (Func)&FaultHandler; // Debug
_Vectors[14] = (Func)&FaultHandler; // PendSV
_Vectors[15] = (Func)&FaultHandler; // Systick
#ifdef STM32F10X
__DMB(); // 确保中断表已经被写入
SCB->AIRCR = (0x5FA << SCB_AIRCR_VECTKEY_Pos) // 解锁
| (7 << SCB_AIRCR_PRIGROUP_Pos); // 没有优先组位
SCB->VTOR = (uint)_Vectors; // 向量表基地址
//NVIC_SetVectorTable(NVIC_VectTab_RAM, (uint)Vectors);
SCB->SHCSR |= SCB_SHCSR_USGFAULTENA // 打开异常
| SCB_SHCSR_BUSFAULTENA
| SCB_SHCSR_MEMFAULTENA;
#else
// Enable the SYSCFG peripheral clock
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE);
// Remap SRAM at 0x00000000
SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM);
#endif
#else
#ifdef STM32F10X
SCB->AIRCR = (0x5FA << SCB_AIRCR_VECTKEY_Pos) // 解锁
| (7 << SCB_AIRCR_PRIGROUP_Pos); // 没有优先组位
SCB->SHCSR |= SCB_SHCSR_USGFAULTENA // 打开异常
| SCB_SHCSR_BUSFAULTENA
| SCB_SHCSR_MEMFAULTENA;
#endif
#endif
}
TInterrupt::~TInterrupt()
{
// 恢复中断向量表
#ifdef STM32F10X
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0);
#else
SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_Flash);
#endif
}
bool TInterrupt::Activate(short irq, InterruptCallback isr, void* param)
{
assert_param(IS_IRQ(irq));
short irq2 = irq + 16; // exception = irq + 16
#if VEC_TABLE_ON_RAM
_Vectors[irq2] = OnHandler;
#endif
Vectors[irq2] = isr;
Params[irq2] = param;
__DMB(); // asure table is written
//NVIC->ICPR[irq >> 5] = 1 << (irq & 0x1F); // clear pending bit
//NVIC->ISER[irq >> 5] = 1 << (irq & 0x1F); // set enable bit
if(irq >= 0)
{
NVIC_ClearPendingIRQ((IRQn_Type)irq);
NVIC_EnableIRQ((IRQn_Type)irq);
}
return true;
}
bool TInterrupt::Deactivate(short irq)
{
assert_param(IS_IRQ(irq));
short irq2 = irq + 16; // exception = irq + 16
Vectors[irq2] = 0;
Params[irq2] = 0;
//NVIC->ICER[irq >> 5] = 1 << (irq & 0x1F); // clear enable bit */
if(irq >= 0) NVIC_DisableIRQ((IRQn_Type)irq);
return true;
}
bool TInterrupt::Enable(short irq)
{
assert_param(IS_IRQ(irq));
if(irq < 0) return false;
uint ier = NVIC->ISER[irq >> 5]; // old state
//NVIC->ISER[irq >> 5] = 1 << (irq & 0x1F); // set enable bit
NVIC_EnableIRQ((IRQn_Type)irq);
return (ier >> (irq & 0x1F)) & 1; // old enable bit
}
bool TInterrupt::Disable(short irq)
{
assert_param(IS_IRQ(irq));
if(irq < 0) return false;
uint ier = NVIC->ISER[irq >> 5]; // old state
//NVIC->ICER[irq >> 5] = 1 << (irq & 0x1F); // clear enable bit
NVIC_DisableIRQ((IRQn_Type)irq);
return (ier >> (irq & 0x1F)) & 1; // old enable bit
}
bool TInterrupt::EnableState(short irq)
{
assert_param(IS_IRQ(irq));
if(irq < 0) return false;
// return enabled bit
return (NVIC->ISER[(uint)irq >> 5] >> ((uint)irq & 0x1F)) & 1;
}
bool TInterrupt::PendingState(short irq)
{
assert_param(IS_IRQ(irq));
if(irq < 0) return false;
// return pending bit
return (NVIC->ISPR[(uint)irq >> 5] >> ((uint)irq & 0x1F)) & 1;
}
void TInterrupt::SetPriority(short irq, uint priority)
{
assert_param(IS_IRQ(irq));
NVIC_SetPriority((IRQn_Type)irq, priority);
}
void TInterrupt::GetPriority(short irq)
{
assert_param(IS_IRQ(irq));
NVIC_GetPriority((IRQn_Type)irq);
}
void TInterrupt::GlobalEnable() { __enable_irq(); }
void TInterrupt::GlobalDisable() { __disable_irq(); }
bool TInterrupt::GlobalState() { return __get_PRIMASK(); }
#ifdef STM32F10X
uint TInterrupt::EncodePriority (uint priorityGroup, uint preemptPriority, uint subPriority)
{
return NVIC_EncodePriority(priorityGroup, preemptPriority, subPriority);
}
void TInterrupt::DecodePriority (uint priority, uint priorityGroup, uint* pPreemptPriority, uint* pSubPriority)
{
NVIC_DecodePriority(priority, priorityGroup, pPreemptPriority, pSubPriority);
}
#endif
void TInterrupt::OnHandler()
{
uint num = GetIPSR();
//if(num >= VectorySize) return;
//if(!Interrupt.Vectors[num]) return;
assert_param(num < VectorySize);
assert_param(Interrupt.Vectors[num]);
// 找到应用层中断委托并调用
InterruptCallback isr = (InterruptCallback)Interrupt.Vectors[num];
void* param = (void*)Interrupt.Params[num];
isr(num - 16, param);
}
void TInterrupt::FaultHandler()
{
uint exception = GetIPSR();
if (exception) {
debug_printf("EXCEPTION 0x%02x:\r\n", exception);
} else {
debug_printf("ERROR:\r\n");
}
#if DEBUG
// 显示异常详细信息
int i;
if(exception==3)
{
// 0xE000ED2C
uint n = *(uint*)(SCB_BASE + 0x2C);
debug_printf("\r\n硬件错误 %d ", n);
if(n & (1<<1))
{
debug_printf("在取向量时发生\r\n");
}
else if(n & (1u<<30))
{
debug_printf("是总线fault存储器管理fault 或是用法fault 上访的结果\r\n");
}
else if(n & (1u<<31))
{
debug_printf("因调试事件而产生\r\n");
}
}
else if(exception==5)
{
i = *(byte*)(SCB_BASE + 0x29);
#ifdef STM32F10X
debug_printf("\r\nBus Fault %d 0x%08x: \r\n", i, SCB->BFAR);
#endif
if(i & (1<<0))
{
debug_printf("IBUSERR 取指访问违例 1. 内存访问保护违例。常常是用户应用程序企图访问特权级region。在这种情况下入栈的PC给出的地址就是产生问题的代码之所在 2. 跳转到不可执行指令的 regions 3. 异常返回时使用了无效的EXC_RETURN值 4. 向量表中有无效的向量。 5. 在异常处理期间入栈的PC值被破坏了\r\n"); // 取指访问违例 1. 内存访问保护违例。常常是用户应用程序企图访问特权级region。在这种情况下入栈的PC给出的地址就是产生问题的代码之所在 2. 跳转到不可执行指令的 regions 3. 异常返回时使用了无效的EXC_RETURN值 4. 向量表中有无效的向量。例如异常在向量建立之前就发生了或者加载的是用于传统ARM内核的可执行映像 5. 在异常处理期间入栈的PC值被破坏了
}
else if(i & (1<<1))
{
debug_printf("PRECISERR 在数据访问期间的总线错误。通过BFAR可以获取具体的地址。发生fault的原因同上。\r\n"); // 在数据访问期间的总线错误。通过BFAR可以获取具体的地址。发生fault的原因同上。
}
else if(i & (1<<2))
{
debug_printf("IMPRECISERR 与设备之间传送数据的过程中发生总线错误。可能是因为设备未经初始化而引起或者在用户级访问了特权级的设备或者传送的数据单位尺寸不能为设备所接受。此时有可能是LDM/STM指令造成了非精确总线fault。\r\n"); // 与设备之间传送数据的过程中发生总线错误。可能是因为设备未经初始化而引起或者在用户级访问了特权级的设备或者传送的数据单位尺寸不能为设备所接受。此时有可能是LDM/STM指令造成了非精确总线fault。
}
else if(i & (1<<3))
{
debug_printf("UNSTKERR 自动出栈期间出错。如果没有发生过STKERR则最可能的就是在异常处理期间把SP的值破坏了\r\n"); // 自动出栈期间出错。如果没有发生过STKERR则最可能的就是在异常处理期间把SP的值破坏了
}
else if(i & (1<<4))
{
debug_printf("STKERR (自动)入栈期间出错 1. 堆栈指针的值被破坏 2. 堆栈用量太大,到达了未定义存储器的区域 3. PSP未经初始化就使用\r\n"); // (自动)入栈期间出错 1. 堆栈指针的值被破坏 2. 堆栈用量太大,到达了未定义存储器的区域 3. PSP未经初始化就使用
}
else if(i & (1<<5))
{
debug_printf("BFARVALID 表示BFAR有效\r\n"); // 表示BFAR有效
}
//debug_printf("\r\n");
}
else if(exception==4)
{
i = *(byte*)(SCB_BASE + 0x28);
#ifdef STM32F10X
debug_printf("\r\nMemManage Fault %d 0x%08x: \r\n", i, SCB->MMFAR);
#endif
if(i & (1<<0))
{
debug_printf("IACCVIOL 取指访问违例 1. 内存访问保护违例。常常是用户应用程序企图访问特权级region。在这种情况下入栈的PC给出的地址就是产生问题的代码之所在 2. 跳转到不可执行指令的 regions 3. 异常返回时使用了无效的EXC_RETURN值 4. 向量表中有无效的向量。 5. 在异常处理期间入栈的PC值被破坏了\r\n"); // 取指访问违例 1. 内存访问保护违例。常常是用户应用程序企图访问特权级region。在这种情况下入栈的PC给出的地址就是产生问题的代码之所在 2. 跳转到不可执行指令的 regions 3. 异常返回时使用了无效的EXC_RETURN值 4. 向量表中有无效的向量。例如异常在向量建立之前就发生了或者加载的是用于传统ARM内核的可执行映像 5. 在异常处理期间入栈的PC值被破坏了
}
else if(i & (1<<1))
{
debug_printf("DACCVIOL 数据内存访问保护违例。一般是访问非法内存位置所致。可以注意筛查野指针问题。\r\n"); // 内存访问保护违例。这是MPU发挥作用的体现。常常是用户应用程序企图访问特权级region所致
}
else if(i & (1<<3))
{
debug_printf("MUNSTKERR 出栈时发生错误 1. 异常服务例程破坏了堆栈指针 2. 异常服务例程更改了MPU配置\r\n"); // 出栈时发生错误 1. 异常服务例程破坏了堆栈指针 2. 异常服务例程更改了MPU配置
}
else if(i & (1<<4))
{
debug_printf("MSTKERR 入栈时发生错误 1. 堆栈指针的值被破坏 2. 堆栈容易过大已经超出MPU允许的region范围\r\n"); // 入栈时发生错误 1. 堆栈指针的值被破坏 2. 堆栈容易过大已经超出MPU允许的region范围
}
else if(i & (1<<7))
{
debug_printf("MMARVALID 表示MMAR有效\r\n"); // 表示MMAR有效
}
}
else if(exception==6)
{
i = *(byte*)(SCB_BASE + 0x2A);
debug_printf("\r\nUsage Fault %d: \r\n", i);
if(i & (1<<0))
{
debug_printf("UNDEFINSTR 执行的指令其编码是未定义的——解码不能\r\n"); // 执行的指令其编码是未定义的——解码不能
}
else if(i & (1<<1))
{
debug_printf("INVSTATE 试图切入ARM状态\r\n"); // 试图切入ARM状态
}
else if(i & (1<<2))
{
debug_printf("INVPC 在异常返回时试图非法地加载EXC_RETURN到PC\r\n"); // 在异常返回时试图非法地加载EXC_RETURN到PC。包括非法的指令非法的上下文以及非法的EXC_RETURN值。The return PC指向的指令试图设置PC的值
}
else if(i & (1<<3))
{
debug_printf("NOCP 企图执行一个协处理器指令。引发此fault的指令可以从入栈的PC读取\r\n"); // 企图执行一个协处理器指令。引发此fault的指令可以从入栈的PC读取
}
else if(i & (1<<4))
{
debug_printf("UNALIGNED 当UNALIGN_TRP置位时发生未对齐访问。引发此fault的指令可以从入栈的PC读取\r\n"); // 当UNALIGN_TRP置位时发生未对齐访问。引发此fault的指令可以从入栈的PC读取
}
else if(i & (1<<5))
{
debug_printf("DIVBYZERO 表示除法运算时除数为零。引发此fault的指令可以从入栈的PC读取\r\n"); // 表示除法运算时除数为零只有在DIV_0_TRP置位时才会发生。引发此fault的指令可以从入栈的PC读取
}
}
#endif
while(true);
}
__asm uint TInterrupt::GetIPSR()
{
mrs r0,IPSR // exception number
bx lr
}
#if !VEC_TABLE_ON_RAM
extern "C"
{
void NMI_Handler() { TInterrupt::FaultHandler(); }
void HardFault_Handler() { TInterrupt::FaultHandler(); }
void MemManage_Handler() { TInterrupt::FaultHandler(); }
void BusFault_Handler() { TInterrupt::FaultHandler(); }
void UsageFault_Handler() { TInterrupt::FaultHandler(); }
void SVC_Handler() { TInterrupt::OnHandler(); }
void PendSV_Handler() { TInterrupt::OnHandler(); }
void SysTick_Handler() { TInterrupt::OnHandler(); }
void WWDG_IRQHandler() { TInterrupt::OnHandler(); }
void PVD_IRQHandler() { TInterrupt::OnHandler(); }
void RTC_IRQHandler() { TInterrupt::OnHandler(); }
void FLASH_IRQHandler() { TInterrupt::OnHandler(); }
void RCC_IRQHandler() { TInterrupt::OnHandler(); }
void EXTI0_1_IRQHandler() { TInterrupt::OnHandler(); }
void EXTI2_3_IRQHandler() { TInterrupt::OnHandler(); }
void EXTI4_15_IRQHandler() { TInterrupt::OnHandler(); }
void TS_IRQHandler() { TInterrupt::OnHandler(); }
void DMA1_Channel1_IRQHandler() { TInterrupt::OnHandler(); }
void DMA1_Channel2_3_IRQHandler() { TInterrupt::OnHandler(); }
void DMA1_Channel4_5_IRQHandler() { TInterrupt::OnHandler(); }
void ADC1_COMP_IRQHandler() { TInterrupt::OnHandler(); }
void TIM1_BRK_UP_TRG_COM_IRQHandler() { TInterrupt::OnHandler(); }
void TIM1_CC_IRQHandler() { TInterrupt::OnHandler(); }
void TIM2_IRQHandler() { TInterrupt::OnHandler(); }
void TIM3_IRQHandler() { TInterrupt::OnHandler(); }
void TIM6_DAC_IRQHandler() { TInterrupt::OnHandler(); }
void TIM14_IRQHandler() { TInterrupt::OnHandler(); }
void TIM15_IRQHandler() { TInterrupt::OnHandler(); }
void TIM16_IRQHandler() { TInterrupt::OnHandler(); }
void TIM17_IRQHandler() { TInterrupt::OnHandler(); }
void I2C1_IRQHandler() { TInterrupt::OnHandler(); }
void I2C2_IRQHandler() { TInterrupt::OnHandler(); }
void SPI1_IRQHandler() { TInterrupt::OnHandler(); }
void SPI2_IRQHandler() { TInterrupt::OnHandler(); }
void USART1_IRQHandler() { TInterrupt::OnHandler(); }
void USART2_IRQHandler() { TInterrupt::OnHandler(); }
void CEC_IRQHandler() { TInterrupt::OnHandler(); }
}
#endif