视频十七:GPIO中断源的配置以及中断试验
本视频的目的是和大家一起详细看看GPIO的中断源配置,以及从汇编代码层面带大家一起分析中断的过程情景。
注意:这里的GPIO是包含MIO和EMIO的GPIO;中断源配置分析到产生52号中断;GPIO有128个,所以可以有128个52号中断,这些中断源“或”的关系产生中断请求。
在上一个视频里面讲到了GPIO的输入输出的控制原理以及从寄存器层面和库函数层面分别做了演示试验。这一节我们来看看GPIO中断源的原理,各个寄存器的意义,并在SDK环境下用C语言控制寄存器实现对GPIO中断源的配置,并以实际试验运行来验证控制正确。为了更能凸显出中断的原理,让大家看到中断的本质,我们自己写启动文件,编辑中断向量,以及用自己的链接文件。同时也演示了如何不通过VIVADO自己手动建立一个SDK项目。
INT_MASK,INT_DIS,INT_EN为一组,表示对对应位是否使能。
INT_TYPE ,INT_POLARITY,INT_ANY为一组,表示触发的方式,是电平还是边缘以及是否双边缘。
INT_STAT 读之可以知道对应位是否发生了中断,对应位写1表示清除中断(实际应用中要以注意中断撤掉或者被屏蔽)。
SDK除了提供上一个视频所讲的GPIO读写的函数之外,还提供了中断源配置的库函数供我们调用。这里结合寄存器定义一和大家一起详细看看各个函数的实现。
启发:由于EMIO的输入输出可以不必接到芯片引脚,可以接PL的逻辑上,因此PL的逻辑可以对EMIO的引脚产生中断信号。这就有了一种PL请求PS中断的一个可行简单通用的方式。
强调:MIO是复用的,EMIO不是复用的,初始化的是GPIO,如果是别的功能,VIVADO的配置信息里就包含了对这些MIO复用寄存器的配置。(P1555例证)
步骤:
1.1各个寄存器含义:
INT_MASK:为只读寄存器;
INT_EN:向这个寄存器的任何一位写“1”,使能该信号用于中断。
INT_DIS: 向这个寄存器的任何一位写“1”,使屏蔽这个信号用于中断。
INT_STAT:指示是否发生了中断事件。写“1”清除中断事件。
INT_POLARITY:控制中断是边缘触发是高还是低有效(或者上升沿或者下降沿敏感)。
INT_ON_ANY:如果设置INT_TYPE为边缘敏感,则这个寄存器用于使能在所有上升沿和下降沿使能一个中断事件。如果设置为电平敏感,则忽略该位。
INT_MASK,INT_DIS,INT_EN为一组,表示对对应位是否使能。
INT_TYPE ,INT_POLARITY,INT_ANY为一组,表示触发的方式,是电平还是边缘以及是否双边缘。
1.2 GPIO中断触发设置类型
表14-1:GPIO中断触发设置类型
gpio.INT- TYPE_0 gpio.INT-POLARITY_o gpio.INT ANYO
上升的边缘敏感 1 1 0
下降的边缘敏感 1 0 0
上升和下降的边缘敏感电平敏感 1 X 1
高电平敏感 0 1 X
低电平敏感 0 0 X
→选择empty application
→把文件夹src里的拷贝到我们建立的sdk的src里去;
→ 在sdk按f5 refresh(刷新);就会把刚才的文件添加进去 ;
→看注释:
.section .vectors
_vector_table://中断向量
B _boot /0地址(开机复位也是一个中断,颛桥到boot)/
B Undefined/4/
B SVCHandler/8/
B PrefetchAbortHandler/12/
B DataAbortHandler/16/
NOP /* Placeholder for address exception vector*/
B IRQHandler/24/
B FIQHandler/28/
→看boot(在boot.s里):做了处理器、【mmu(存储控制器):虚拟地址和物理地址转化的基础】的初始化:
→IRQ中断/24/24地址颛桥到下面:
IRQHandler: /* IRQ vector handler /
stmdb sp!,{r0-r3,r12,lr} / state save from compiled code*/
bl IRQInterrupt /* IRQ vector / 转到main.c文件去看
ldmia sp!,{r0-r3,r12,lr} / state restore from compiled code /
subs pc, lr, #4 / adjust return */寄存器r0-r3,r12,lr调用了之后恢复
→看IRQInterrupt函数:
void IRQInterrupt(void)
{
Xil_Out32(0xe000a258,0xFFFFFFFF);//清除中断标志位 //INT_STA
Xil_Out32(0xF8F01284,0xFFFFFFFF);//清除中断等待标志未
Xil_Out32(0xe000a254,0xFFFFFFFF);//不使能GPIO中断 //INT_DIS
DATA_0=~ DATA_0;//改变LED状态
Xil_Out32(0xe000a250,0x40000);//使能GPIO中断 //INT_EN
}
(用的按键是mo50,灯是mo7;)
【这个方法是把zynq当成单独的ps使用;不需要生成bit文件;】
→pdf: pga1854;看MIO_PIN_07的引脚复用设置
int main()
{
MIO_PIN_07=0x0FFFFF600;
/设置MIO_PIN_07为GPIO/
DIRM_0=0x00000080;
/设置MIO_PIN_07为输出引脚/
OEN_0=0x00000080;
/设置MIO_PIN_07输出使能/
DATA_0=0x00000080;//点亮LED
int RegValue;
int Int_Id;
Xil_Out32(0xe000a254,0xFFFFFFFF);//屏蔽中断 //INT_DIS
Xil_Out32(0xe000a25C,1<<(50-32));//中断类型,电平或者边沿 // INT_TYPE
Xil_Out32(0xe000a260,1<<(50-32));//中断极性 // INT_POLARITY
Xil_Out32(0xe000a264,0x0);//如果为边沿,是单边沿,或者双边沿 // INT_ANY
Xil_Out32(0xf8f01000,0x0);//关闭所有安全中断
/*BANK0 0-31
0
/*BANK1 32-53
0
/*BANK2 54-(54+31)
3 86-117 (????我不太懂他的这个返回值咋算的)
→
asm volatile(
“msr cpsr,%0\n”
: : “r” (({unsigned int rval;
asm volatile(
“mrs %0, cpsr\n”
: “=r” (rval)
);
rval;
}) & ~ (0x80 & (0x40 | 0x80)))
);
Xil_Out32(0xe000a250,0x40000);//中断使能
void IRQInterrupt(void)
{
Xil_Out32(0xe000a258,1<<(50-32));//清除中断标志位 //INT_STA
Xil_Out32(0xF8F01284,0xFFFFFFFF);//清除中断等待标志未
Xil_Out32(0xe000a254,0xFFFFFFFF);//不使能GPIO中断 //INT_DIS
DATA_0=~ DATA_0;//改变LED状态
Xil_Out32(0xe000a250,0x40000);//使能GPIO中断 //INT_EN
}
(注意:蓝色为修改部分)
按一下mo50按一下亮;按一下灭(电平翻转):可以加上延时去除抖动;
多加几条在void IRQInterrupt(void)里:Xil_Out32(0xe000a254,0xFFFFFFFF);//屏蔽中断