SYD8801是一款低功耗高性能蓝牙低功耗SOC,集成了高性能2.4GHz射频收发机、32位ARM Cortex-M0处理器、128kB Flash存储器、以及丰富的数字接口。SYD8801片上集成了Balun无需阻抗匹配网络、高效率DCDC降压转换器,适合用于可穿戴、物联网设备等。具体可咨询:http://www.syd-tek.com/
Cortex-M0中断向量表:
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
下文摘录于:http://blog.csdn.net/fervor_heart/article/details/8288914
这里向前辈敬礼!
NMI (Non Maskable Interrupt)——不可屏蔽中断(即CPU不能屏蔽)
无论状态寄存器中 IF 位的状态如何,CPU收到有效的NMI必须进行响应;NMI是上升沿有效;中断类型号固定为2;它在被响应时无中断响应周期.不可屏蔽中断通常用于故障处理(如:协处理器运算出错,存储器校验出错,I/O通道校验出错等).
IF = Interrupt Flag(中断状态)
在DSP等学习中NMI解释同样为“不可屏蔽中断”,其英文解释为“External Non-Maskable Interrupt”
下文摘录于:http://blog.csdn.net/guozhongwei1/article/details/49544671
这里向前辈敬礼!
SVC(系统服务调用,亦简称系统调用)和PendSV(可悬起系统调用),它们多用于在操作系统之上的软件开发中。SVC 用于产生系统函数的调用请求。例如,操作系统不让用户程序直接访问硬件,而是通过提供一些系统服务函数,用户程序使用SVC 发出对系统服务函数的呼叫请求,以这种方法调用它们来间接访问硬件。因此,当用户程序想要控制特定的硬件时,它就会产生一个SVC 异常,然后操作系统提供的SVC 异常服务例程得到执行,它再调用相关的操作系统函数,后者完成用户程序请求的服务。
这种“提出要求——得到满足”的方式,很好、很强大、很方便、很灵活、很能可持续发展。首先,它使用户程序从控制硬件的繁文缛节中解脱出来,而是由OS 负责控制具体的硬件。第二,OS 的代码可以经过充分的测试,从而能使系统更加健壮和可靠。第三,它使用户程序无需在特权级下执行,用户程序无需承担因误操作而瘫痪整个系统的风险。第四,通过SVC 的机制,还让用户程序变得与硬件无关,因此在开发应用程序时无需了解硬件的操作细节,从而简化了开发的难度和繁琐度,并且使应用程序跨硬件平台移植成为可能。开发应用程序唯一需要知道的就是操作系统提供的应用编程接口(API),并且了解各个请求代号和参数表,然后就可以使用SVC 来提出要求了(事实上,为使用方便,操作系统往往会提供
一层封皮,以使系统调用的形式看起来和普通的函数调用一致。各封皮函数会正确使用SVC指令来执行系统调用——译者注)。其实,严格地讲,操作硬件的工作是由设备驱动程序完成的,只是对应用程序来说,它们也是操作系统的一部分。如图7.14 所示
SVC 异常通过执行”SVC”指令来产生。该指令需要一个立即数,充当系统调用代号。SVC异常服务例程稍后会提取出此代号,从而解释本次调用的具体要求,再调用相应的服务函数。例如,
SVC 0x3 ; 调用3 号系统服务
在SVC 服务例程执行后,上次执行的SVC 指令地址可以根据自动入栈的返回地址计算出。找到了SVC 指令后,就可以读取该SVC 指令的机器码,从机器码中萃取出立即数,就获知了请求执行的功能代号。如果用户程序使用的是PSP,服务例程还需要先执行
MRS Rn,PSP
指令来获取应用程序的堆栈指针。通过分析LR 的值,可以获知在SVC 指令执行时,正在使用哪个堆栈。
由CM3 的中断优先级模型可知,你不能在SVC 服务例程中嵌套使用SVC 指令(事实上这样做也没意义),因为同优先级的异常不能抢占自身。这种作法会产生一个用法fault。同理,在NMI 服务例程中也不得使用SVC,否则将触发硬fault。
PendSV:
另一个相关的异常是PendSV(可悬起的系统调用),它和SVC 协同使用。一方面,SVC异常是必须立即得到响应的(若因优先级不比当前正处理的高,或是其它原因使之无法立即响应,将上访成硬fault——译者注),应用程序执行SVC 时都是希望所需的请求立即得到响应。另一方面,PendSV 则不同,它是可以像普通的中断一样被悬起的(不像SVC 那样会上访)。OS 可以利用它“缓期执行”一个异常——直到其它重要的任务完成后才执行动作。悬起PendSV 的方法是:手工往NVIC 的PendSV 悬起寄存器中写1。悬起后,如果优先级不够高,则将缓期等待执行。
PendSV 的典型使用场合是在上下文切换时(在不同任务之间切换)。例如,一个系统中有两个就绪的任务,上下文切换被触发的场合可以是:
Cortex-M0中断控制和系统控制
本文摘录于:http://blog.csdn.net/jasenmaodj/article/details/46941605
版权归原作者所有,这里向前辈致敬!
一. NVIC和系统控制块特性
1. 灵活的中断管理:使能/禁止中断,优先级配置
2. 硬件嵌套中断支持
3. 向量化的异常入口
4. 中断屏蔽
5. NVIC寄存器的起始地址:0xE000E100, 对其访问必须是每次32bit
6. SCB的起始地址: 0xE000E010,也是每次32bit访问。
二. 中断使能和清除使能
1. 中断寄存器是可编程的,用于控制中断请求(异常编号16以上)的使能(SETENA)和禁止(CLRENA), 如下所示:
这里说一下:
对于ARM M0而言,SysTick_Handler是第15号中断,从16号开始是NVIC所控制的外部中断,最多只能有32个外部中断
2. 使能/禁止 中断的代码:
1). C代码:
*(volatile unsigned long) (0xE000E100) = 0x4 ; //使能#2中断
*(volatile unsigned long) (0xE000E180) = 0x4 ; //禁止#2中断
2). 汇编代码:
LDR R0, =0xE000E100 ; //SETEAN寄存器的地址
MOVS R1, #04 ; //设置#2中断
STR R1, [R0] ; //使能中断#2
3). CMSIS标准设备驱动函数:
void NVIC_EnableIRQ(IRQn_Type_IRQn); //使能中断#IRQn;
void NVIC_DisableIRQ(IRQn_Type_IRQn); //禁止中断#IRQn;
三. 中断挂起和清除挂起:
1. 可以通过操作中断挂起(SETPEND)和清除挂起(CLRPEND),这两个寄存器来访问和修改中断挂起状态。
如果软件配置挂起中断就是软中断的实现!
2.挂起/清除挂起的代码:
1). C代码:
*(volatile unsigned long)(0xE000E100) = 0x4 ; //使能中断#2
*(volatile unsigned long)(0xE000E200) = 0x4 ; // 挂起中断#2
*(volatile unsigned long)(0xE000E280) = 0x4 ; // 清除中断#2的挂起状态
2). 汇编代码:
LDR R0, =0xE000E100 ; //设置使能中断寄存器地址
MOVS R1, #0x4 ; //中断#2
STR R1, [R0] ; //使能#2中断
LDR R0, =0xE000E200 ; //设置挂起中断寄存器地址
MOVS R1, #0x4 ; //中断#2
STR R1, [R0] ; //挂起#2中断
LDR R0, =0xE000E280 ; //设置清除中断挂起寄存器地址
MOVS R1, #0x4 ; //中断#2
STR R1, [R0] ; //清除#2的挂起状态
3). CMSIS标准设备驱动函数:
void NVIC_SetPendingIRQ(IRQn_Type_IRQn) ; //设置一个中断挂起
void NVIC_ClearPendingIRQ(IRQn_Type_IRQn); //清除中断挂起
void NVIC_GetPendingIRQ(IRQn_Type_IRQn) ; //读取中断挂起状态
四. 中断优先级:(0xE000E400~0xE000E41C)
1. 每个外部中断都有一个对应的中断有先级寄存器,每个优先级都是只有一个字节且只有最高2Bit有效;
2. NVIC支持字传输,所以每次访问都会涉及4个中断优先级寄存器。
也就是说ARM MO只是支持四级优先级,并且高优先级中断能够打断低优先级中断。
3. 设置中断优先级代码:(先读一个字,再修改对应字节,最后整个字写回)
1). C代码:
unsigned long temp; //定义一个临时变量
temp = *(volatile unsigned long)(0xE000E400); //读取IRP0值
temp &= (0xFF00FFFF |(0xC0 << 16)); //修改中断#2优先级为0xC0
*(volatile unsigned long)(0xE000E400) = temp; //设置IPR0
2). 汇编代码:
LDR R0, =0xE000E100 ; //设置使能中断寄存器地址
MOVS R1, #0x4 ; //中断#2
STR R1, [R0] ; //使能#2中断
LDR R0, =0xE000E200 ; //设置挂起中断寄存器地址
MOVS R1, #0x4 ; //中断#2
STR R1, [R0] ; //挂起#2中断
LDR R0, =0xE000E280 ; //设置清除中断挂起寄存器地址
MOVS R1, #0x4 ; //中断#2
STR R1, [R0] ; //清除#2的挂起状态
3). CMSIS标准设备驱动函数:
void NVIC_SetPriority(IRQn_Type_IRQn, uint32_t priority) ; //设置中断优先级
uint32_t NVIC_GetPriority(IRQn_Type_IRQn); //读取中断优先级
这里的priority是0,1,2,3.函数内部会自动移位到对应的优先级最高2位:
void NVIC_SetPriority(2, 3) ; //设置#2中断的优先级为0xC0
SYD8801设置中断优先级的方法如下:
NVIC_SetPriority(GPIO_IRQn, 3);
NVIC_SetPriority(UART0_IRQn, 0);
五. 异常屏蔽寄存器(PRIMASK)
1.对时间敏感的应用,需要用PRIMASK来屏蔽掉除NMI和硬件错误异常以外的其他所有中断和异常。
2.PRIMASK只有1Bit有效,默认为0,为1时起屏蔽作用。
3.操作PRIMASK的代码:
1). 汇编代码:
MOVS R0, #1 ;
MSR PRIMASK, R0 ; //使用MSR指令设置PRIMASK值
2). CPS指令:
CPSIE i ; //清除PRIMASK值
CPSID i ; //设置PRIMASK值
3). CMSIS标准设备驱动函数:
void _enable_irq(void) ; //清除PRIMASK值
void _disable_irq(void) ; //设置PRIMASK值
六. 中断输入和挂起行为
1. Cortex-M0允许电平触发和脉冲触发两种方式;
2. 每个外部中断请求都会对应一个挂起状态寄存器,且只有1bit,当开始处理这个异常时,硬件会自动清除挂起状态;
3. 大多数外设都是使用电平触发,当执行中断服务程序并且清除外设中断信号之前,该信号一直为高:
4. 使用脉冲触发中断时,至少持续1个时钟周期:
七. 中断等待 (中断确认 –> 中断服务处理开始执行)
1. Cortex-M0中断默认等待的时间为16个时钟周期;
2. 中断等待的条件:
1). 改中断使能并且没有被PRIMASK屏蔽掉;
2). 存储器系统没有任何等待。
3. IRQLATENCY的8位信号可以控制中断等待:设置为0,则以最快速度响应中断。
八. 系统异常的控制寄存器(SHPR2,SHPR3)
1. Cortex-M0处理器只有SVC、PendSV和SysTick 3个与OS相关的系统异常才具有可编程的 优先级
2. 符合CMSIS的设备驱动,可使用如下方式访问:
3. 中断控制状态寄存器(ICSR, 0xE000ED04):
P139, 表9.6
4. 符合CMSIS的设备驱动,可使用 "SCB -> ICRS" 来访问。
九. 系统控制寄存器(0xE000E000~0xE000EFFF)
1. SCS包括NVIC、调试控制、SysTick定时器;
2. CPU ID基址寄存器(0xE000ED00),只读,包含处理器ID信息,"SCB -> CPUID" 访问;
3. 应用中断和复位控制寄存器(AIRCR, 0xE000ED0C):
1). 用于应用程序请求系统复位,识别系统的大小端,以及清除所有的异常活动状态:
2). CMSIS 设备驱动,可以使用 "SCB -> AIRCR" 来访问;
3). CMSIS 设备驱动, 请求系统复位的函数:
Void NVIC_SystemReset(void);
十. 配置和控制寄存器(CCR, 0xE000ED14)
1. CCR 只读, 决定了栈的双字节对齐设置和非对称访问的处理;
2. CMSIS 设备驱动,可以使用 "SCB -> CCR" 来访问;
硬件错误后仿真器的作用
M0内核在发生硬件错误后依旧会输出一些调试信息,以下内容摘录于:《Fundamentals_in_debugging_nRF5x_systems - Hard Fault on nRF52.pdf》,因为对于M0而言处理都一样,所以这里引用如下:
PDF源文档如下:https://download.csdn.net/download/chengdong1314/10414491
也就是说硬件错误的时候会把R0到R3和R12压到堆栈中