ARM的GPIO中断

yummy 阅读:531 2022-05-03 16:40:24 评论:0

一、实验目的

调用ZYNQ处理器,导出硬件到SDK 进行软件开发,使用GPIO输入的中断机制进行按键读取。

二、ZYNQ工程建立

三、新建bd以及ZYNQ处理器IP调用

image.png

image.png

image.png

1. 打开IP Catalog,Search输入GPIO,添加 AXI_GPIO:(添加IP也可以通过点击Diagram 上面的+号来添加):

image.png

2. 设置axi_gpio_0,勾选全部为输入,GPIO宽度1,其余不变,点击OK

image.png

3. 设置axi_gpio_1,勾选全部为输出,GPIO宽度4,其余不变,点击OK

image.png

4. 点击Diagram上方的Run Conection Automation自动连接信号:

弹出的界面,勾选所有的模块,表示全部都需要自动连接,点击OK:

image.png

5. 最后点击 Run Block Automation生成ZYNQ对外的管脚,包括DDR3和其他引脚:

image.png

6.默认勾选左边唯一一个IP,也就是ZYNQ IP还未连接,点击OK自动连接对外引脚:

image.png

7.重新布局

image.png

8.最后,手动连接axi_gpio_0智能高端输出接口和ZYNQ终端输入接口

image.png

9. 完成之后,按下ctrl+s保存设置,回到source窗口,生成输出文件和生成顶层文件。 生成输出,生成顶层

image.png

10.完成之后点击工程管理栏->RTL ANALYSIS->Open Elaborated Design,然后切换视图 到I/O Planing分配管脚视图,分配管脚。分配完成之后管脚如下,我们按ctrl+s保存管脚约束 文件,文件名为gpio_input_output。

image.png

11.工程管理栏直接点击生成比特文件。等待生成完成,生成完成之后,菜单栏File- >Export->Export Hardware导出硬件。我们的硬件部分设计到此结束。接下来我们开始软件 SDK开发,进行代码编写,debug。导出硬件需要勾选包含bit文件

四、SDK下的代码开发

 1.. 我们启动SDK。在工具栏File ->Launch SDK启动。 启动SDK后,可以看到默认带的一个硬件描述工程。我们新建一个app工程。File->New- >Application Project,然后,工程名gpio_interrupt,点击NEXT:

image.png

 2. 我们编辑gpio_interrupt工程中的helloword.c文件,写入如下代码:


#include <stdio.h>

#include "platform.h"

#include "xparameters.h"

#include "xscugic.h"

#include "xil_exception.h"

#include "xgpio.h"

#include <unistd.h>


#define INTC_DEVICE_ID          XPAR_PS7_SCUGIC_0_DEVICE_ID

#define KEY_DEVICE_ID           XPAR_AXI_GPIO_0_DEVICE_ID

#define LED_DEVICE_ID           XPAR_AXI_GPIO_1_DEVICE_ID

#define INTC_GPIO_INTERRUPT_ID  XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR

#define KEY_INT_MASK            XGPIO_IR_CH1_MASK

XGpio LEDInst;

XGpio KEYInst;

XScuGic INTCInst;


static void KeyIntrHandler(void * InstancePtr);

static int IntcInitFunction(u16 DeviceId, XGpio * GpioInstancePtr);

static int InterruptSystemSetup(XScuGic * XScuGicInstancePtr);


int main()

{

    init_platform();

    int status;

    status = XGpio_Initialize(&KEYInst, KEY_DEVICE_ID); // initial KEY

    if(status != XST_SUCCESS) return XST_FAILURE;

    status = XGpio_Initialize(&LEDInst, LED_DEVICE_ID);  // initial LED

    if(status != XST_SUCCESS)return XST_FAILURE;

    XGpio_SetDataDirection(&KEYInst, 1, 0xFF);

    XGpio_SetDataDirection(&LEDInst, 1, 0); // set LED IO direction as out

    XGpio_DiscreteWrite(&LEDInst, 1, 0x00);// at initial, all LED turn off

    printf(">>Press PL KEY1, and check the PL LED1 \n");

    status = IntcInitFunction(INTC_DEVICE_ID, &KEYInst);

    if(status != XST_SUCCESS)return XST_FAILURE;

    while(1)

    {

      ;

    }

    cleanup_platform();

    return 0;

}


static void KeyIntrHandler(void * InstancePtr)

{

    u8 keyVal;

    usleep(10000); // 0.1s sleep, to debounce, in common, the meta-state will sustain no more than 20ms

    keyVal = XGpio_DiscreteRead(&KEYInst, 1) & 0x0f;

    printf("PL KEY1 pressed,interrupt is generated!! key value=%d\n",keyVal);

    XGpio_DiscreteWrite(&LEDInst, 1, 0X0F);//on led

    usleep(500000);

    XGpio_DiscreteWrite(&LEDInst, 1, 00);//reverse led

    XGpio_InterruptClear(&KEYInst, KEY_INT_MASK);

    XGpio_InterruptEnable(&KEYInst, KEY_INT_MASK);  // Enable GPIO interrupts

}


static int IntcInitFunction(u16 DeviceId, XGpio * GpioInstancePtr)

{

    XScuGic_Config * IntcConfig;

    int status;

    // Interrupt controller initialization

    IntcConfig = XScuGic_LookupConfig(DeviceId);

    status = XScuGic_CfgInitialize(&INTCInst, IntcConfig, IntcConfig->CpuBaseAddress);

    if(status != XST_SUCCESS)return XST_FAILURE;

    // Call interrupt setup function

    status = InterruptSystemSetup(&INTCInst);

    if(status != XST_SUCCESS) return XST_FAILURE;


    // Register GPIO interrupt handler

    status = XScuGic_Connect(&INTCInst, INTC_GPIO_INTERRUPT_ID,

            (Xil_ExceptionHandler)KeyIntrHandler, (void*)GpioInstancePtr);

    if(status != XST_SUCCESS)return XST_FAILURE;

    // Enable GPIO interrupts

    XGpio_InterruptEnable(GpioInstancePtr, 1);

    XGpio_InterruptGlobalEnable(GpioInstancePtr);

    // Enable GPIO interrupts in the controller

    XScuGic_Enable(&INTCInst, INTC_GPIO_INTERRUPT_ID);

    return XST_SUCCESS;

}


//----------------------------------------------------------------------------

// Interrupt system setup

//----------------------------------------------------------------------------

static int InterruptSystemSetup(XScuGic * XScuGicInstancePtr)

{

    // Register GIC interrupt handler

    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,

            (Xil_ExceptionHandler)XScuGic_InterruptHandler, XScuGicInstancePtr);

    Xil_ExceptionEnable();

    return XST_SUCCESS;

}

3.然后,等待SDK自动编译完成。一定要等待编译结束。SDK在新建helloword模板代码工程结束它 就自动编译,不需要手动编译。每次修改完代码,按一下ctrl+s保存即可重新编译,编译进度在右下角 会显示,以及Console窗口也会打印便已结束信息。一般第一次新建工程自动编译会比较慢,后面修改 代码都是增量编译,只重新编译修改的代码文件,就很快。下图打印编译完成的信息。

image.png

4.完成之后,我们就可以进行上板调试。点击debug的小虫子符号,选择第一项,1 Launch On Hardware(System Debugger) 。注意,第一次debug不会成功,代码不能正常运行,因为我们还没 有配置烧写FPGA。当debug启动,代码已下载到芯片,可以看到菜单栏下的 符号可用。这个 时候,我们点击小虫子 右边的下拉选项,选择Debug Configuration,进入debug配置, 设置如下:

image.png

5.然后点击小虫子 重新DEBUG,弹出的对话框均选择OK,等待再次debug就绪。然后, 我们打开terminal配置模式serial,串口号,波特率,然后连接。点击 开始debug。我们 按下KEY1, 可以看到四个LED亮起约一秒熄灭,串口打印输出按钮按下,中断发生。

image.png

image.png



本文 zblog模板 原创,转载保留链接!网址:https://www.xn--zqqs03dbu6a.cn/?id=50

可以去百度分享获取分享代码输入这里。
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。