裸板开发中,使用的就是现在的框架:
………………………………………………………………
main (void) {
// 一系列的初始化
while (1) {
// 周期性的事物
}
}
↓+↓
异常处理 (异步事件的处理)
………………………………………………………………
1、异常如何触发
用按键触发异常,触发IRQ / FIQ类型的异常。
1.1 电路原理图 // x6818bv2【底板】.pdf
当SW6对应的按键 - 断开,导线GPIOA28 - 高电平。
当SW6对应的按键 - 闭合,导线GPIOA28 - 低电平。
导线GPIOA28 → 连接到了 → CPU的GPIOA28的管脚。
1.2 对GPIOA28管脚进行配置 - (市长)
配置后GPIOA28管脚上的变化才会被视为IRQ / FIQ异常
异常上报给ARM core
GPIOA28'管脚上出现一个下降沿时触发中断'信号
--->P66. // 确认I/O输出
GPIOA28 - I/O: Function0
---> P759. // 配置:输出功能 function0
GPIOA_ALTFN1 - 0xc001a024 - [25:24] 00=ALT Function0
---> P745. // 配置:输入模式 mode
GPIOA_OUTENB - 0xc001a004 - [ 28 ] 0=Input Mode
---> P752. // 配置:检测模式 (1+2=3bit)
GPIOA_DETMODE1 - 0xc001a00c - [25:24] 2-bit 10=Falling Edge
GPIOA_DETMODEEX - 0xc001a028 - [ 28 ] 1-bit 0=Falling Edge
010 : 检测下降沿,检测到下降沿信号产生中断异常
---> P770. // 配置:检测使能
GPIOA_DETENB - 0xc001a03c - [ 28 ] 1=Enable
---> P756. // 配置:中断源级使能
GPIOA_INTENB - 0xc001a010 - [ 28 ] 1/0=Enable/Disable
---> P756. // 配置:检测状态显示
GPIOA_DET - 0xc001a014 - [ 28 ] read: 0/1=未/检测到配置的信号
write: 1=清除对应的检测bit位
【对应的代码】
key_irq.c
void key_irq_init (void) {...}
该函数在main.c中被调用,效果是当按键按下时产生一个中断信号
1.3 中断控制器 GIC - (省长)
【特点】
1)中断源可以配置为group0或者group1;
2)group0中的中断可以配置为IRQ/FIQ的形式向目标处理器报告;
3)grout1中的中断只能以IRQ的形式向目标处理器报告;
【支持4种类型的中断】
SGI * 16 :软件产生的中断信号,cpu和cpu之间的通信。
PPI * 6 :私有外围设备中断
PPI * 1 :私有内部设备中断
SPI * 128 :'共享的外部设备中断(按键就属于SPI)
【中断状态】
inactive:非中断未决和中断进行。
pending:中断未决。中断已产生,等待cpu处理阶段。
active:中断进行。中断已产生,并正在执行相应的中断服务过程中。
【中断被处理的模式】
1-N model / N-N model
【中断优先级】了解
【中断编号】interrupt IDs
ID0~ID15:SGI
ID16~ID31:PPI
ID32~ID1019:SPI // 按键可用的编号在此范围内
【中断源】---> P472.
GPIOA中断对应的interrupt ID是 32 + 53 == 85
【关于特殊功能寄存器的设置,分两部分】
distributor<分配器> + CPU interface<接口> = '中断控制器(GIC)'
1)以GICD_xxxx开头的寄存器,对distributor配置;
2)以GICC_xxxx开头的寄存器,对CPU interface配置。
" GICD_CTRL // 归为group的中断信号是否可向interface
GICD_CTRL - 0xc0009000 - [ 0 ] 0=屏蔽,1=使能
" GICD_IGROUPR // 决定中断归为group0还是group1
GICD_IGROUPR2 - 0xc0009088 - [ 21 ] 0=group0
" GICD_ITARGETSR21 //配置中断产生后分配给那个核(cpu0,cou1...)
GICD_ITARGETSR21
配置中断产生后分发给哪个核(cpu0 cpu1 ...cpu7)
[15:8] 00000001 ID=85的中断发送到CPU0
GICD_IPRORITYR21
[15:8] 0x0a ID=85的中断优先级为10
GICD_ICPENDERR2
READ:
1, 中断产生了未得到处理 PENDING (未决/挂起)
WRITE,
1 导致对应的bit 清0
GPIOA ID = 85
[21] 向其中写入1,将其清0
GICD_ISENABLER2
[21] 0/1 屏蔽/使能 ID=85的中断信号
GICC_CTRL
[0], 0/1 禁止/使能上报group0组的中断信号给CPUn
[1], 0/1 禁止/使能上报group1组的中断信号给CPUn
[3], 0/1 group0的中断按照IRQ/FIQ方式上报
GICC_PMR
中断优先级阈值设置
优先级高于阈值的中断信号才有可能上报给CPU
[7:0]
【对应的代码】interrupt.c
int interrupt_init (void){ }
该函数在main.c
1.4 ARM core设置
CPSR
[I] 0,响应上报的IRQ信号
1,屏蔽上报的IRQ信号
start.s
enable_interrupts
增加start.s
而且调整shell.lds
IRQ异常产生,硬件会自动做4件事
1)备份CPSR 到spsr_<irq>
2) 修改CPSR
[4:0] 10010
[5] T=0
[6] F=1
[7] I=1
3) 保存返回地址到LR_<irq>
LR_<irq> = PC -4
4) 给PC寄存器赋值
PC = vector_base + 0x18
= 0x48000000 + 0x18
start.s
1)异常向量表
b reset
ldr ...
ldr ...
2)reset:
重新设置异常向量表首地址
栈空间设置
bl main ( ) {
中断源 中断控制 arm初始化 //按键就出异常并且异常可以传递ARM CORE
while(1) {
}
}
当有人按下key1键 ,IRQ异常报告给ARM CORE
ARM CORE
1)备份cpsr
2)修改CPSR
3)保存返回地址到LR
4)PC = 0X48000018
软件代码执行
ldr pc, _irq
irq:
保护现场 stmfd sp!, {r0-r12, lr}
执行按键处理动作 bl do_irq
恢复现场 ldmfd sp!, {r0-r12, r15}^
r15= lr
^: cpsr = spsr_<irq>
do_irq()
{
/*确认哪个触发的IRQ*/
GPIOA28 interrupt id = 85
判断是否为GPIOA28触发的中断?
{
do_gpioa_irq()
{
/*重要的事:清除中断源的中断标志位*/
}
清除gpioa28在中断控制器中的pending位
}
}
练习:
梳理按键异常是如何产生的?流程
异常的软硬件响应过程?
能不能向其中再增加一个按键?
………………………………………………………………
main (void) {
// 一系列的初始化
while (1) {
// 周期性的事物
}
}
↓+↓
异常处理 (异步事件的处理)
………………………………………………………………
1、异常如何触发
用按键触发异常,触发IRQ / FIQ类型的异常。
1.1 电路原理图 // x6818bv2【底板】.pdf
当SW6对应的按键 - 断开,导线GPIOA28 - 高电平。
当SW6对应的按键 - 闭合,导线GPIOA28 - 低电平。
导线GPIOA28 → 连接到了 → CPU的GPIOA28的管脚。
1.2 对GPIOA28管脚进行配置 - (市长)
配置后GPIOA28管脚上的变化才会被视为IRQ / FIQ异常
异常上报给ARM core
GPIOA28'管脚上出现一个下降沿时触发中断'信号
--->P66. // 确认I/O输出
GPIOA28 - I/O: Function0
---> P759. // 配置:输出功能 function0
GPIOA_ALTFN1 - 0xc001a024 - [25:24] 00=ALT Function0
---> P745. // 配置:输入模式 mode
GPIOA_OUTENB - 0xc001a004 - [ 28 ] 0=Input Mode
---> P752. // 配置:检测模式 (1+2=3bit)
GPIOA_DETMODE1 - 0xc001a00c - [25:24] 2-bit 10=Falling Edge
GPIOA_DETMODEEX - 0xc001a028 - [ 28 ] 1-bit 0=Falling Edge
010 : 检测下降沿,检测到下降沿信号产生中断异常
---> P770. // 配置:检测使能
GPIOA_DETENB - 0xc001a03c - [ 28 ] 1=Enable
---> P756. // 配置:中断源级使能
GPIOA_INTENB - 0xc001a010 - [ 28 ] 1/0=Enable/Disable
---> P756. // 配置:检测状态显示
GPIOA_DET - 0xc001a014 - [ 28 ] read: 0/1=未/检测到配置的信号
write: 1=清除对应的检测bit位
【对应的代码】
key_irq.c
void key_irq_init (void) {...}
该函数在main.c中被调用,效果是当按键按下时产生一个中断信号
/** 代码演示 - key_irq.c **/
void do_gpioa_irq(void) {
uart_puts("\n\r do_gpioa_irq \n\r");
GPIOA_DET |= (1<<28);
}
void key_irq_init(void) {
GPIOA_INTENB &= ~(1<<28); // 先做中断源级屏蔽
//GPIO 配置
// 1、GPIO配置为输入
// 2、禁止内部上、下拉电阻
// 3、GPIO检测使能
// 4、GPIO检测下降沿事件
// 5、GPIO中断使能
// FUNC 0
// 输入口,禁止内部上下拉电阻
GPIOA_ALTFN1 &= ~(3<<(24));
GPIOA_OUTEN &= ~(1<<28);
//清除检测标志位
GPIOA_DET |= (1<<28);
//检测下降沿事件,使能检测
GPIOA_DETMODE1 = (GPIOA_DETMODE1 & ~(3<<24)) | (2<<24);
GPIOA_DETMODEEX &= ~(1<<28);
GPIOA_DETENB |= (1<<28);
GPIOA_INTENB |= (1<<28); // 最后中断源级使能
}
/** ------------------------------------------------------ **/
1.3 中断控制器 GIC - (省长)
【特点】
1)中断源可以配置为group0或者group1;
2)group0中的中断可以配置为IRQ/FIQ的形式向目标处理器报告;
3)grout1中的中断只能以IRQ的形式向目标处理器报告;
【支持4种类型的中断】
SGI * 16 :软件产生的中断信号,cpu和cpu之间的通信。
PPI * 6 :私有外围设备中断
PPI * 1 :私有内部设备中断
SPI * 128 :'共享的外部设备中断(按键就属于SPI)
【中断状态】
inactive:非中断未决和中断进行。
pending:中断未决。中断已产生,等待cpu处理阶段。
active:中断进行。中断已产生,并正在执行相应的中断服务过程中。
【中断被处理的模式】
1-N model / N-N model
【中断优先级】了解
【中断编号】interrupt IDs
ID0~ID15:SGI
ID16~ID31:PPI
ID32~ID1019:SPI // 按键可用的编号在此范围内
【中断源】---> P472.
GPIOA中断对应的interrupt ID是 32 + 53 == 85
【关于特殊功能寄存器的设置,分两部分】
distributor<分配器> + CPU interface<接口> = '中断控制器(GIC)'
1)以GICD_xxxx开头的寄存器,对distributor配置;
2)以GICC_xxxx开头的寄存器,对CPU interface配置。
" GICD_CTRL // 归为group的中断信号是否可向interface
GICD_CTRL - 0xc0009000 - [ 0 ] 0=屏蔽,1=使能
" GICD_IGROUPR // 决定中断归为group0还是group1
GICD_IGROUPR2 - 0xc0009088 - [ 21 ] 0=group0
" GICD_ITARGETSR21 //配置中断产生后分配给那个核(cpu0,cou1...)
GICD_ITARGETSR21
配置中断产生后分发给哪个核(cpu0 cpu1 ...cpu7)
[15:8] 00000001 ID=85的中断发送到CPU0
GICD_IPRORITYR21
[15:8] 0x0a ID=85的中断优先级为10
GICD_ICPENDERR2
READ:
1, 中断产生了未得到处理 PENDING (未决/挂起)
WRITE,
1 导致对应的bit 清0
GPIOA ID = 85
[21] 向其中写入1,将其清0
GICD_ISENABLER2
[21] 0/1 屏蔽/使能 ID=85的中断信号
GICC_CTRL
[0], 0/1 禁止/使能上报group0组的中断信号给CPUn
[1], 0/1 禁止/使能上报group1组的中断信号给CPUn
[3], 0/1 group0的中断按照IRQ/FIQ方式上报
GICC_PMR
中断优先级阈值设置
优先级高于阈值的中断信号才有可能上报给CPU
[7:0]
【对应的代码】interrupt.c
int interrupt_init (void){ }
该函数在main.c
1.4 ARM core设置
CPSR
[I] 0,响应上报的IRQ信号
1,屏蔽上报的IRQ信号
start.s
enable_interrupts
该函数在main.c中被调用
2、异常的处理流程
增加start.s
而且调整shell.lds
IRQ异常产生,硬件会自动做4件事
1)备份CPSR 到spsr_<irq>
2) 修改CPSR
[4:0] 10010
[5] T=0
[6] F=1
[7] I=1
3) 保存返回地址到LR_<irq>
LR_<irq> = PC -4
4) 给PC寄存器赋值
PC = vector_base + 0x18
= 0x48000000 + 0x18
start.s
1)异常向量表
b reset
ldr ...
ldr ...
2)reset:
重新设置异常向量表首地址
栈空间设置
bl main ( ) {
中断源 中断控制 arm初始化 //按键就出异常并且异常可以传递ARM CORE
while(1) {
}
}
当有人按下key1键 ,IRQ异常报告给ARM CORE
ARM CORE
1)备份cpsr
2)修改CPSR
3)保存返回地址到LR
4)PC = 0X48000018
软件代码执行
ldr pc, _irq
irq:
保护现场 stmfd sp!, {r0-r12, lr}
执行按键处理动作 bl do_irq
恢复现场 ldmfd sp!, {r0-r12, r15}^
r15= lr
^: cpsr = spsr_<irq>
do_irq()
{
/*确认哪个触发的IRQ*/
GPIOA28 interrupt id = 85
判断是否为GPIOA28触发的中断?
{
do_gpioa_irq()
{
/*重要的事:清除中断源的中断标志位*/
}
清除gpioa28在中断控制器中的pending位
}
}
练习:
梳理按键异常是如何产生的?流程
异常的软硬件响应过程?
能不能向其中再增加一个按键?