学习内容
实现对GPIO的中断控制程序,实现按键按下使得led等闪亮一次,并结合前文的IIC工程,实现按键控制iic的数据采集。
开发环境
vivado 18.3
SDK
PYNQ-Z2
中断初始化的设置
对于熟悉ARM和32开发的人来说,中断的概念对其并不陌生。下面我给出按键在32开发时候的初始化的流程:
按键中断编程步骤分析:
- 使能相应的时钟
- 配置GPIO管脚为中断功能
- 设置中断优先级
- 使能相应的中断
- 实现中断服务程序
然后我给出ZYNQ的中断初始化的设置流程:
- 初始化CPU异常功能
- 初始化中断控制器
- 向CPU注册异常处理回调函数
- 向中断控制器中对应的中断ID和中断控制器相连接
- 设置中断的类型
- 设置中断的回调函数(用户自己设置)
- 使能对应引脚的中断
- 使能中断控制器
- 使能异常处理功能
对比纯arm开发和zynq的开发,我们可以大致看出,两者在中断初始化的过程中有很多相似的地方。 因为zynq的功能比较多,比较复杂,在开发的时的配置过程也相对麻烦。
对应初始化过程中的每一步,我们可以找到对应的函数进行调用,具体过程如下:
硬件平台搭建
新建工程初始化我们需要用到了GPIO的资源引脚,具体的工程可以参考ZYNQ-利用PS引脚实现EMIO GPIO的驱动
这里只给出搭建后的结果:
(这里只进行设计了gpio可以实现对应按键控制灯闪烁)
SDK软件部分
新建工程后,在main中添加中断初始化代码:
#define SCUGIC_0_ID XPAR_PS7_SCUGIC_0_DEVICE_ID #define GPIO_INTR_ID 52 #define SW_BANK_ID 2 static XScuGic GicPs; static XScuGic_Config *XScuGic_Cfg; int setupinterrupt(){ int status; //初始化异常处理 Xil_ExceptionInit(); //初始化中断控制器 XScuGic_Cfg = XScuGic_LookupConfig(SCUGIC_0_ID); status = XScuGic_CfgInitialize(&GicPs,XScuGic_Cfg,XScuGic_Cfg->CpuBaseAddress); if( status != XST_SUCCESS){ return XST_FAILURE; } //CPU中断异常注册 Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&GicPs); //链接中断信号 status = XScuGic_Connect(&GicPs,GPIO_INTR_ID,(Xil_InterruptHandler)XGpioPs_IntrHandler,&GpioPs); if( status != XST_SUCCESS){ return XST_FAILURE; } //中断类型设置 XGpioPs_SetIntrType(&GpioPs,SW_BANK_ID,0xffffffff,0xffffffff,0x00); //设置中断回调函数 XGpioPs_SetCallbackHandler(&GpioPs,(void *) &GpioPs, IntrHandler); //打开gpio中断 XGpioPs_IntrEnable(&GpioPs,SW_BANK_ID,1<<(BTN1-54)); XScuGic_Enable(&GicPs,GPIO_INTR_ID); Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ); return XST_SUCCESS; }
对于部分参数的查找进行简单说明,具体函数的使用,可以参考system.mss中进行查找:
GPIO_INTR_ID :中断配置时,要对中断ID进行设置,否则对应不上配置的中断
SW_BANK_ID :
因为我们BANK0和BANK1对应的是MIO的管脚是54个,我们声明的管脚在BANK 2,所以我们就设置的BANK ID为2
按键控制led
#include <stdio.h> #include "platform.h" #include "xil_printf.h" #include "xgpiops.h" #include "xparameters.h" #include "xscugic.h" #define GPIO_ID XPAR_PS7_GPIO_0_DEVICE_ID #define SCUGIC_0_ID XPAR_PS7_SCUGIC_0_DEVICE_ID #define GPIO_INTR_ID 52 #define SW_BANK_ID 2 #define LED0 54 #define LED1 55 #define BTN1 56 static XGpioPs GpioPs; static XGpioPs_Config *XGpioPs_Cfg; static XScuGic GicPs; static XScuGic_Config *XScuGic_Cfg; int initGpio(); int setupinterrupt(); void IntrHandler(void *CallBack,u32 Bank,u32 status); int main() { init_platform(); initGpio(); print("Hello World\n\r"); setupinterrupt(); while(1) { XGpioPs_WritePin(&GpioPs,LED0,0); XGpioPs_WritePin(&GpioPs,LED1,0); usleep(1000); } cleanup_platform(); return 0; } int initGpio(){ int status; XGpioPs_Cfg = XGpioPs_LookupConfig(GPIO_ID); status = XGpioPs_CfgInitialize(&GpioPs,XGpioPs_Cfg,XGpioPs_Cfg->BaseAddr); if( status != XST_SUCCESS){ return XST_FAILURE; } XGpioPs_SetDirectionPin(&GpioPs,LED0,0x01); XGpioPs_SetOutputEnablePin(&GpioPs,LED0,0x01); XGpioPs_SetDirectionPin(&GpioPs,LED1,0x01); XGpioPs_SetOutputEnablePin(&GpioPs,LED1,0x01); XGpioPs_SetDirectionPin(&GpioPs,BTN1,0x00); XGpioPs_SetOutputEnablePin(&GpioPs,BTN1,0x00); } int setupinterrupt(){ int status; //初始化异常处理 Xil_ExceptionInit(); //初始化中断控制器 XScuGic_Cfg = XScuGic_LookupConfig(SCUGIC_0_ID); status = XScuGic_CfgInitialize(&GicPs,XScuGic_Cfg,XScuGic_Cfg->CpuBaseAddress); if( status != XST_SUCCESS){ return XST_FAILURE; } //CPU中断异常注册 Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&GicPs); //链接中断信号 status = XScuGic_Connect(&GicPs,GPIO_INTR_ID,(Xil_InterruptHandler)XGpioPs_IntrHandler,&GpioPs); if( status != XST_SUCCESS){ return XST_FAILURE; } //中断类型设置 XGpioPs_SetIntrType(&GpioPs,SW_BANK_ID,0xffffffff,0xffffffff,0x00); //设置中断回调函数 XGpioPs_SetCallbackHandler(&GpioPs,(void *) &GpioPs, IntrHandler); //打开gpio中断 XGpioPs_IntrEnable(&GpioPs,SW_BANK_ID,1<<(BTN1-54)); XScuGic_Enable(&GicPs,GPIO_INTR_ID); Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ); return XST_SUCCESS; } void IntrHandler(void *CallBack,u32 Bank,u32 status){ XGpioPs *GPIO_ptr; u32 read_val; GPIO_ptr = (XGpioPs *)CallBack; if(XGpioPs_ReadPin(GPIO_ptr,BTN1) == 1) { XGpioPs_WritePin(GPIO_ptr,LED0,1); XGpioPs_WritePin(GPIO_ptr,LED1,1); printf("%d\n",XGpioPs_ReadPin(&GpioPs,BTN1)); usleep(1000000); } }
按键控制数据采集
/* * helloworld.c: simple test application * * This application configures UART 16550 to baud rate 9600. * PS7 UART (Zynq) is not initialized by this application, since * bootrom/bsp configures it to baud rate 115200 * * ------------------------------------------------ * | UART TYPE BAUD RATE | * ------------------------------------------------ * uartns550 9600 * uartlite Configurable only in HW design * ps7_uart 115200 (configured by bootrom/bsp) */ #include <stdio.h> #include "platform.h" #include "xil_printf.h" #include "xgpiops.h" #include "xiicps.h" #include "xparameters.h" #include "xscugic.h" #define GPIO_ID XPAR_PS7_GPIO_0_DEVICE_ID #define SCUGIC_0_ID XPAR_PS7_SCUGIC_0_DEVICE_ID #define I2C_0_DEVICE_ID XPAR_PS7_I2C_0_DEVICE_ID #define I2C_0_CLK 100000 #define IIC_0_SALV_ADDR 0x23 //定义器件在IIC总线中的从地址,根据ALT ADDRESS地址引脚不同修改 //ALT ADDRESS引脚接地时地址为0x23 #define GPIO_INTR_ID 52 #define SW_BANK_ID 2 #define LED0 54 #define LED1 55 #define BTN1 56 //声明结构体 static XGpioPs GpioPs; static XGpioPs_Config *XGpioPs_Cfg; static XScuGic GicPs; static XScuGic_Config *XScuGic_Cfg; // XIicPs* iicps; static XIicPs iicps; static XIicPs_Config * iicpscfgtr; int status; double out=0; unsigned short tmp; unsigned char Cmdon = 0x01; unsigned char Cmdlight = 0x10; char temp[2]; int initGpio(); int setupinterrupt(); //初始化 iic int InitIic(XIicPs *iips,XIicPs_Config *iiccfg); void IntrHandler(void *CallBack,u32 Bank,u32 status); int main() { init_platform(); initGpio(); setupinterrupt(); status=InitIic(&iicps,iicpscfgtr); if(status !=XST_SUCCESS){ return XST_FAILURE; } //初始化 status = XIicPs_MasterSendPolled(&iicps,&Cmdon,1,IIC_0_SALV_ADDR); if(status !=XST_SUCCESS){ return XST_FAILURE; } usleep(10000);//延时10ms printf("init iic successful!\n"); while(1) { XGpioPs_WritePin(&GpioPs,LED0,0); XGpioPs_WritePin(&GpioPs,LED1,0); usleep(1000); } cleanup_platform(); return 0; } int initGpio(){ int status; XGpioPs_Cfg = XGpioPs_LookupConfig(GPIO_ID); status = XGpioPs_CfgInitialize(&GpioPs,XGpioPs_Cfg,XGpioPs_Cfg->BaseAddr); if( status != XST_SUCCESS){ return XST_FAILURE; } XGpioPs_SetDirectionPin(&GpioPs,LED0,0x01); XGpioPs_SetOutputEnablePin(&GpioPs,LED0,0x01); XGpioPs_SetDirectionPin(&GpioPs,LED1,0x01); XGpioPs_SetOutputEnablePin(&GpioPs,LED1,0x01); XGpioPs_SetDirectionPin(&GpioPs,BTN1,0x00); XGpioPs_SetOutputEnablePin(&GpioPs,BTN1,0x00); } int InitIic(XIicPs *iips,XIicPs_Config * iiccfg){ int status; iiccfg = XIicPs_LookupConfig(I2C_0_DEVICE_ID); status = XIicPs_CfgInitialize(iips,iiccfg,iiccfg->BaseAddress); if(status !=XST_SUCCESS){ return XST_FAILURE; } status = XIicPs_SelfTest(iips); if (status != XST_SUCCESS) { return XST_FAILURE; } status = XIicPs_SetSClk(iips,I2C_0_CLK); if(status !=XST_SUCCESS){ return XST_FAILURE; } return 0; } int setupinterrupt(){ int status; //初始化异常处理 Xil_ExceptionInit(); //初始化中断控制器 XScuGic_Cfg = XScuGic_LookupConfig(SCUGIC_0_ID); status = XScuGic_CfgInitialize(&GicPs,XScuGic_Cfg,XScuGic_Cfg->CpuBaseAddress); if( status != XST_SUCCESS){ return XST_FAILURE; } //CPU中断异常注册 Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&GicPs); //链接中断信号 status = XScuGic_Connect(&GicPs,GPIO_INTR_ID,(Xil_InterruptHandler)XGpioPs_IntrHandler,&GpioPs); if( status != XST_SUCCESS){ return XST_FAILURE; } //中断类型设置 XGpioPs_SetIntrType(&GpioPs,SW_BANK_ID,0xffffffff,0xffffffff,0x00); //设置中断回调函数 XGpioPs_SetCallbackHandler(&GpioPs,(void *) &GpioPs, IntrHandler); //打开gpio中断 XGpioPs_IntrEnable(&GpioPs,SW_BANK_ID,1<<(BTN1-54)); XScuGic_Enable(&GicPs,GPIO_INTR_ID); Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ); return XST_SUCCESS; } void IntrHandler(void *CallBack,u32 Bank,u32 status){ XGpioPs *GPIO_ptr; u32 read_val; GPIO_ptr = (XGpioPs *)CallBack; if(XGpioPs_ReadPin(GPIO_ptr,BTN1) == 1) { XGpioPs_WritePin(&GpioPs,LED0,1); status = XIicPs_MasterSendPolled(&iicps,&Cmdon,1,IIC_0_SALV_ADDR); if(status !=XST_SUCCESS){ return XST_FAILURE; } status = XIicPs_MasterSendPolled(&iicps,&Cmdlight,1,IIC_0_SALV_ADDR); if(status !=XST_SUCCESS){ return XST_FAILURE; } usleep(180000);//延时180ms status = XIicPs_MasterRecvPolled(&iicps,&temp,2,IIC_0_SALV_ADDR); //串口检测结果 tmp = (temp[0]<<8)| temp[1]; out = tmp/1.2; printf("light intensity : %.1f lx\n",out); usleep(1000000); } }
运行效果