摘要:
本能篇主要講一下AXI GPIO 中斷,AXI GPIO 中斷也是共享外設中斷的一種。本講和上一講說的中斷很像,區別就是AXI GPIO 中斷需要AXI GPIO核。
本章也是使用PL邏輯產生一組方波信號來做中斷信號,方波的週期也是2秒。如下圖L:
中斷信號
產生的中斷信號捅進AXI_GPIO0,然後輸入到ZYNQ中。同時將AXI_GPIO0的中斷信號連接到ZYNQ的中斷輸入端口。ZYNQ對中斷做出響應,在中斷處理函數裏面讀取AXI_GPIO0的值,再通過AXI_GPIO1寫到LED燈上,通過LED燈來觀察中斷響應。同時也可以通過串口來打印響應的信息來觀察中斷響應的情況。
一、創建Block Design模塊
整體結構如下:
說明:
a、通過PL邏輯產生中斷方波信號,輸入到sws_8bits.
b、從FCLK_CLK0引出CLK_100M信號
c、從FCLK_RESET0_N引出FCLK_RESET0_N信號
1、配置ZYNQ
勾選PL到PS的中斷
2、引出兩路時鐘
3、添加AXI_GPIO0,按如下配置(注意使能中斷)
4、添加AXI_GPIO1,按如下配置
5、點擊自動連接,(如果有需要可以選中Block design中的信號線,然後右鍵debug添加ila)
6、Generate Output Product
7、創建頂層
8、生成Bit文件
9、導入到SDK
二、在SD中進行編程
1、創建一個HelloWorld工程
2、按照上一講說的中斷設置流程編寫程序
3、程序分析
主函數:
#include <stdio.h>
#include "xparameters.h"
#include "xgpio.h"
#include "sleep.h"
#include "xscugic.h"
#include "xil_exception.h"
//使用全局變量定義AXI_GPIO0(SW)、AXI_GPIO1(LED)結構體
XGpio LED;
XGpio SW;
static u32 num=0;
//中斷函數聲明爲static,可以加快速度
static void handler_btn(void* Callback)
{
//在XScuGic_Connect設置XGpio對象指針作爲參數送入
XGpio* g = (XGpio*)Callback;
XGpio_InterruptClear(g, 0xFF);//進入中處理函數先清除中斷標誌,否則可能有意外的結果。我就是因爲把清除中斷標誌放在最後導致上升沿觸發時兩次進入中斷
XGpio_InterruptDisable(&SW, 0xFF);//失能全部8個按鈕的中斷
//讀出按鈕狀態
u8 r;
r = XGpio_DiscreteRead(g, 1);
printf(" sw is %d\n\r", r);//打印AXOI_GPIO0的當前值
XGpio_DiscreteWrite(&LED,1,r);//將AXOI_GPIO1的值寫到AXI_GPIO1
printf("num is %lu\n\r",num);//每進入一次中斷就加一,通過串口觀察
num++;
XGpio_InterruptEnable(&SW, 0xFF);//使能全部8個按鈕的中斷
}
int main(void)
{
int sta = -1;
//初始化GPIO0,按鍵初始化
//ID在xparameters.h中定義,查找/* Definitions for driver GPIO */
sta = XGpio_Initialize(&SW, XPAR_AXI_GPIO_0_DEVICE_ID);
if (sta != XST_SUCCESS)
{
return XST_FAILURE;
}
//設置GPIO0,1通道每一位的傳輸方向爲輸入
//在vivado中已設置爲8位SW輸入
XGpio_SetDataDirection(&SW, 1, 0xFF);
//初始化GPIO1,LED
//ID在xparameters.h中定義,查找/* Definitions for driver GPIO */
sta = XGpio_Initialize(&LED, XPAR_AXI_GPIO_1_DEVICE_ID);
if (sta != XST_SUCCESS)
{
return XST_FAILURE;
}
//設置GPIO1,1通道每一位的傳輸方向爲輸出
//在vivado中已設置爲8位按鈕輸出
XGpio_SetDataDirection(&LED, 1, 0x00);
/***********************************中斷相關函數***********************************/
/***********************************中斷相關函數***********************************/
//設置GPIO0的中斷
XScuGic intc;
XScuGic_Config* intc_conf;
//查找中斷設置
intc_conf = XScuGic_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID);
if (intc_conf == NULL)
{
printf("config fail");
return XST_FAILURE;
}
//中斷初始化
sta = XScuGic_CfgInitialize(&intc, intc_conf, intc_conf->CpuBaseAddress);
if (sta != XST_SUCCESS)
{
printf("config initialize fail");
return XST_FAILURE;
}
//由PS模塊的PL中斷輸入口接入的中斷必須設置優先級與中斷響應模式
//0x3表示設置爲上升沿觸發
XScuGic_SetPriorityTriggerType(&intc, XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR, 0xA0, 0x3);
//連接中斷控制函數
//中斷序號在xparameters.h中查找/* Definitions for Fabric interrupts connected to psu_acpu_gic */
sta = XScuGic_Connect(&intc, XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR, (Xil_ExceptionHandler)handler_btn, &SW);
if (sta != XST_SUCCESS)
{
printf("connect fail");
return XST_FAILURE;
}
//中斷控制器中使能GPIO中斷
XScuGic_Enable(&intc, XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR);
//使能硬件中斷
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &intc);
Xil_ExceptionEnable();
//axi gpio使能中斷
//必須使用下方2個語句
XGpio_InterruptEnable(&SW, 0xFF);//使能全部8個按鈕的中斷
XGpio_InterruptGlobalEnable(&SW);
//printf("Numb %d\n\r", num);
while (1)
{
}
//禁用GPIO中斷
XGpio_InterruptDisable(&SW, 0xFF);
//關閉中斷響應
XScuGic_Disable(&intc, XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR);
XScuGic_Disconnect(&intc, XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR);
return 0;
}
三、現象分析
在說中斷現象之前,我們來分析一下PL邏輯產生的中斷信號。
PL產生中斷信號——>AXI_GPIO0產生中斷——>輸入到ZYNQ中
根據查詢AXI_GPIO手冊得知,當輸入發生變化時就會產生一個高電平的中斷信號,不論是由0->1或者1->0都會產生一個電平信號,經過我使用ila分析,AXI_GPIO0產生的中斷信號持續的時間是100個週期左右。使用波形來說明的話就是如下圖:
也就在PL邏輯的上升沿核下降沿都會產生一個高電平信號,然後送入ZYNQ作爲中斷信號,也就是在PL的上升沿和下降沿都會產生中斷。
但是由於產生的中斷信號只有100個時鐘週期,所以使用電平觸發時,也只能產生一次中斷,看起來就和上升沿觸發的一樣,都是一次。在做實驗的時候,我在這裏就卡了挺久,想着電平觸發爲什麼只響應一次中斷,後來慢慢才摸索到是因爲高電平時間太少了的原因。
本文的主要代碼借鑑了這個博主的代碼。
https://blog.csdn.net/botao_li/article/details/86242850#commentsedit