admin 发表于 2022-8-4 16:23:30

【zynq课程笔记】【裸机】【第12课 】【AXI_GPIO原理与应用】

更多课程笔记请查看:【zynq裸机编程课程笔记合集】
http://www.corecourse.cn/forum.php?mod=viewthread&tid=29095


1      介绍

在前面课程中,我们带领大家一起学习了PS GPIO的原理及基本使用。并最终通过C编程,实现了按键控制LED的效果。
但是Zynq上GPIO无论是MIO还是EMIO,都是属于PS侧的资源,相当于是硬核。而作为一个PS与PL相互协作的平台,当PS侧的GPIO硬核不够用或者无法使用的场合,我们能否使用PL端的逻辑资源来构建一个或多个GPIO软核呢?当然是可以的, Xilinx官方为我们提供了一个名为AXI GPIO的软核。该核使用标准的AXI总线与PS交互,用户可以通过AXI总线,控制AXI GPIO的输入输出模式、输出值、读取指定引脚等。该IP核的结构如下:



图 3 4AXI GPIO框图
从图中可以看出,最右侧有两个具有三态输出功能的端口,分别为GPIO和GPIO2,这也就意味着该控制器可以最多提供2个通道的GPIO。
每个通道的GPIO都有3个标准的信号,也就是输出值(GPIO_O)、输入值(GPIO_I)以及管脚输出使能控制信号(GPIO_T)。
对于输出值,使用一个名为GPIO_DAT的寄存器/D触发器存储所需要输出的值
对于输入值,使用一个名为GPIO_DATA_IN的寄存器/D触发器存储GPIO Pin管脚上的值。
对于输出使能控制信号,使用一个名为GPIO_TRI的寄存器/D触发器存储设置状态。
这两个三态缓冲器工作时,其输入输出状态受GPIO_T信号控制。当GPIO_T=0时,为输出态,三态缓冲器会输出GPIO_O的值;当GPIO_T=1时,为输入态,此时GPIO_I的值会输入到AXI GPIO中。
因此,我们只需要通过对这3个寄存器进行读写,就能够实现对该Pin的状态的控制和读取。
这些寄存器由谁读写,又是通过什么方式读写呢?这个就是我们刚刚提到的,PS通过AXI-Lite总线来读写这些寄存器。
另外该控制器还提供了中断检测逻辑,以及中断控制寄存器,用于中断检测以及中断使能/屏蔽/状态显示。


2      课程目的
   
接下来我们将以该IP核为例,通过拨码开关控制LED的设计,带领大家了解AXI GPIO核的使用,体会在使用时与PS GPIO的异同点。
本次设计中,将会使用到AXI GPIO的两个通道,其中一整个通道被设置为输入,用于获取拨码开关的电平;另一整个通道被设置为输出,用于驱动LED显示。


3      所包含硬件

由于开发板上PL端仅有一个LED灯,且不包含拨码开关,不能单独完成本次设计,因此我们还需要用到一个专门为0基础学习FPGA和ARM编程的用户设计的EDA拓展板。板上包含8个拨码开关和8个可由用户控制的LED灯,非常适合本次设计。




拓展板的更多资料可以查看该帖:
http://www.corecourse.cn/forum.php?mod=viewthread&tid=28643


4      系统框图

在开始设计之前我们首先要对整个系统有个大致的认识,这里我给大家做了一张简易设计图。



在设计时,AXI GPIO的通道1(GPIO)被配置为输入模式,用来接拨码开关,通道2(GPIO2)被设置为输出模式,用来接LED灯。AXI GPIO会捕获用户通过拨码开关设置的电平,PS则通过AXI4-Lite接口读取对应寄存器,以获知该电平值,然后ARM将需要设置的LED的亮灭状态值通过AXI4-Lite接口传输回AXI GPIO,作为通道2(GPIO2)的输出,驱动LED的亮灭显示。



5      创建工程

介绍完了系统的模型之后,我们就可以使用Vivado和SDK来进行系统的设计和实现了。
1.      创建一个名为AXI_GPIO的Vivado工程
2.      新建blockdesign设计
3.      添加ZYNQ、AXI GPIO IP核



6      IP配置与端口连接

(1)      Zynq核
      配置DDR型号,MT41K128M16 JT-125

(2)      AXI GPIO核
      勾选Enable Dual Channel,使能双通道
      设置两个通道的GPIO Width为8,对应8个拨码开关,8个LED
另外介绍一点,在GUI配置界面可以将某一通道设置为全输入/输出模式,这种情况下,该通道的GPIO就只能输入或者输出了,这种配置在GPIO功能和使用场景明确的情况下可以有效降低PL逻辑资源的使用虑。本实验考虑到灵活性以及让大家对GPIO的各项功能有较为明确的了解,这里不设置单输入或者输出模式。

(3)      端口连接
点击“Run Block Automation”和“Run Connection Automation”



7      管脚约束

当完成block design设计之后,我们还需要对该block design生成输出文件(generate output products),并生成一个例化了该设计的HDL格式的顶层文件。
当顶层文件生成好之后,点击“Open Elaborated Design”对设计进行详细的分析,分析完成后就可以自动打开管脚约束界面进行管脚约束,如果显示的界面不是管脚分配,大家可以通过手动在右上角的下拉列表中选择I/O planning选项卡以切换到IO分配界面。关于ACZ702开发版各项功能对应的管脚信息,可以直接在下述帖子中查看。
ACZ702开发板管脚信息表
http://www.corecourse.cn/forum.php?mod=viewthread&tid=29058
以下为本次实验所用功能对应的引脚分配表:

Pin Name
Signial Name
Pin NO.
   
Pin Name
Signial Name
Pin NO.

SW7
gpio_rtl_0_tri_io
E17
   
LED7
gpio_rtl_1_tri_io
K18

SW6
gpio_rtl_0_tri_io
D18
   
LED6
gpio_rtl_1_tri_io
H17

SW5
gpio_rtl_0_tri_io
H15
   
LED5
gpio_rtl_1_tri_io
J18

SW4
gpio_rtl_0_tri_io
F16
   
LED4
gpio_rtl_1_tri_io
K19

SW3
gpio_rtl_0_tri_io
J14
   
LED3
gpio_rtl_1_tri_io
G18

SW2
gpio_rtl_0_tri_io
G14
   
LED2
gpio_rtl_1_tri_io
G20

SW1
gpio_rtl_0_tri_io
L15
   
LED1
gpio_rtl_1_tri_io
G19

SW0
gpio_rtl_0_tri_io
K14
   
LED0
gpio_rtl_1_tri_io
G17




分配完成后将引脚电平标准修改为LVCMOS33,然后保存约束文件,命名为AXI_GPIO.xdc,
到此,我们已经完成了整个系统的硬件系统部分的设计,接下来,我们就可以点击generate bitstream来生成本系统的PL配置文件,也就是我们常说的bit文件。


8      查看编译报告

等待比特流生成完成,我们就可以通过点击Project Summary图标,并切换到Dashboard选项卡中,来查看当前设计的资源使用等信息。



9      创建SDK工程并添加实例源码

通过前面的操作,我们已经完成了本系统的硬件系统的设计,并得到了相应的FPGA配置文件(bit)。
接下来我们还需要针对该硬件系统,生成对应的描述文件,只有基于这些描述文件,我们才能在SDK中对该系统进行正确的编程。
在菜单栏中点击File->Export->Export Hardware,以生成本系统的硬件描述文件。导出时请务必勾选包含bitstream文件,因为本系统已经使用到了FPGA侧的逻辑资源(AXI_GPIO软核)。
然后我们就可以点击File->Launch SDK来打开Vivado提供的SDK集成开发软件。然后在软件中创建一个空白模板的SDK工程,创建好之后,将我们为本节课准备好的例程源码直接拷贝到工程中。
(添加头文件包含路径)
这样,我们的应用程序就创建完了,程序写完之后,我们首先运行一次程序,带领大家体验一下实验效果,然后再来回头分析我们的程序内容,通过分析程序实现的思路,带领大家掌握和学习AXI_GPIO的使用方法。



10      硬件连接

本次硬件连接如下图所示,



将EDA拓展板连接在开发板40pin拓展接口上并连接好调试接口即可。由于本实验只进行简单的LED驱动,所以整体设计功耗不高,因此不需要使用独立供电,使用调试口Type-C供电就足够。使用调试口供电时,右侧的电源开关需要拨到上端USB侧。
(Run Configuration - SystemDebugger)


11      运行程序

现象:拓展板上拨码开关控制与之对应的LED灯亮灭(SW0控制LED0...SW7控制LED7)


12      代码分析

完成了程序效果的演示,接下来一起就来看看,我们的程序是按照怎样的思路来控制AXI_GPIO,实现我们想要的功能的。


#include"COMMON.h"
int main(void)
{
    uint32_t State;
    AXI_GPIO_Init(&AXI_GPIO0,GPIO_0_ID);    //初始化AXI GPIO0
    AXI_GPIO_Set_Channel(&AXI_GPIO0, XGPIO_IR_CH1_MASK, 0xFF, 0);//设置通道1为输入

    while(1){
      State = XGpio_DiscreteRead(&AXI_GPIO0,XGPIO_IR_CH1_MASK);//读取通道1输入的值
      AXI_GPIO_Set_Channel(&AXI_GPIO0, XGPIO_IR_CH2_MASK, 0, State);//将通道2设置为输出,输出从通道1读取的值
    }
    return 0;
}

12.1      头文件分析:

对AXI GPIO的操作属于PL端的操作,所以包含的头文件为xgpio.h(GPIO对应xgpiops.h),该头文件包含Xilinx 通用 I/O (XGpio) 设备驱动程序的软件 API 定义。


12.2      代码分析:

1.      根据xparameters.h中查找到的器件ID查询配置表初始化AXI GPIO
2.      使用AXI_GPIO_Set_Channel()函数设置通道1为输入,并设置输出值为0
进入函数分析,这里分两步,首先是设置方向,本质使用的是XGpio_SetDataDirection()函数,底层是调用的XGpio_Out32()函数对指定通道的3态控制器寄存器直接写操作
XGpio_WriteReg(InstancePtr->BaseAddress,
      ((Channel - 1) * XGPIO_CHAN_OFFSET) + XGPIO_TRI_OFFSET,
      DirectionMask);
接下来是输出值,这里使用的XGpio_DiscreteWrite()函数,通过XGpio_WriteReg()函数实现,底层是调用的XGpio_Out32()函数对指定通道的数据寄存器直接写操作
XGpio_WriteReg(InstancePtr->BaseAddress,
            ((Channel - 1) * XGPIO_CHAN_OFFSET) + XGPIO_DATA_OFFSET,
            Data);
这里由于我们已经将通道1设置为了输入模式,此时对寄存器进行写操作无效。

3.      读取通道1状态,保存在state中。这里使用的是XGpio_DiscreteRead()函数,对通道1的数据寄存器读操作(输入状态,读操作能正常完成)
return XGpio_ReadReg(InstancePtr->BaseAddress,
                  ((Channel - 1) * XGPIO_CHAN_OFFSET) +
                  XGPIO_DATA_OFFSET);
4.      再次使用AXI_GPIO_Set_Channel()函数,设置通道2 为输出,并将State的值作为通道2输出值。

寄存器空间及涉及寄存器描述
表 1寄存器映射

偏移地址
寄存器名
访问类型
默认值
描述

0x0000
GPIO_DATA
R/W
0x0
通道1 AXI GPIO数据寄存器

0x0004
GPIO_TRI
R/W
0x0
通道1 AXI GPIO3态控制寄存器

0x0008
GPIO2_DATA
R/W
0x0
通道2 AXIGP[IO数据寄存器

0x000C
GPIO2_TRI
R/W
0x0
通道2 AXI GPIO3态寄存器

0x011C
GIER
R/W
0x0
全局中断使能寄存器

0x0128
IP IER
R/W
0x0
IP中断使能寄存器

0x0120
IP ISR
R/TOW
0x0
IP中断状态寄存器



表 2AXI GPIO数据寄存器描述


字段名
访问类型
复位值
描述


GPIOx_DATA
R/W
对应通道默认输出值
AXI GPIO数据寄存器
对于每个被配置为输入的I/O:
读:读取输入引脚的值
写:无效
对于每个被配置为输出的I/O:
读:读取这些位将会返回0
写:将值写入相应寄存器位和输出引脚。


这里需要注意的一点是,官方手册中给出的描述是对于每个被配置为输出的I/O进行读操作时都会返回0。如下图



但是在实际操作中我们发现,只有在IP核中将通道设置为“All Outputs”时,读取该通道的值才会为0;而如果是通过软件配置的,则能够正常读取。

表 3AXI GPIO 3态寄存器位描述


字段名
访问类型
复位值
描述


GPIOx_TRI
R/W
对应通道默认3态输出值
AXI GPIO 3态控制寄存器
每个 I/O 引脚都可单独编程为输入或输出。
对于每一位:
0=I/O引脚配置为输出
1=I/O引脚配置为输入



编程方法和思路:

到了这里,我们就完成了AXI GPIO 的拨码开关控制LED亮灭的实验,从这个实验我们可以看到,在进行编程设计时,无论是PS GPIO还是AXI GPIO,使用前都需要进行如下几个步骤:
1.      初始化GPIO驱动程序
2.      设置指定引脚方向
3.      读/写指定管脚的值/状态
不同点则在于PS GPIO在输出指定管脚的值/状态时,需要先使能该引脚作为输出。而在硬件逻辑系统设计方面,AXI GPIO则是与EMIO类似,由于使用的是PL端引脚,在导出后还需要进行管脚分配和约束。


13      思考题
13.1      总结

到这里,本节课程内容就已经基本结束了,在本次的设计中,我们通过软件编程,将AXI GPIO的两个通道分别设置为了输入和输出,以方便代码的设计。实际上AXI GPIO核每个通道的每一位都是能独立设置其输入/输出模式并单独读写的,具体的实现方式可以参考我们在AXI GPIO应用库中提前封装好的AXI_GPIO_SetPin_Dir()、AXI_GPIO_SetPin()以及AXI_GPIO_GetPin()函数,三个函数功能如下:
AXI_GPIO_SetPin_Dir()      修改AXI GPIO某通道的某PIN的输入输出模式
AXI_GPIO_SetPin()      控制指定GPIO口输出高/低电平
AXI_GPIO_GetPin()      读取指定GPIO口的输入电平
关于我们为大家提供的示例程序的内容,就给大家简单介绍到这里。接下来,给大家布置两个思考题,或者说是课后小作业。


13.2      课后习题
      配置AXI GPIO为单通道16位位宽,通过软件编程,将高8位配置为输入,获取拨码开关电平。将低8位设置为输出,使用从拨码开关获取的电平控制LED,实现拨码开关控制LED亮灭设计。
      有能力的同学尝试根据对寄存器的理解,或者对我们提供的示例程序的理解,使用直接操作寄存器的方式来实现本实验。

关于本节课程所使用到的文件、文档和程序等内容,大家可以到下述链接下载。
【zynq裸机编程课程笔记合集】
http://www.corecourse.cn/forum.php?mod=viewthread&tid=29095
或者直接到www.corecourse.cn中搜索“zynq裸机编程课程笔记合集”

admin 发表于 2022-8-4 16:56:13

课程完整工程文件包括Vivado工程和SDK中的源码(工程发布前已经执行了reset_project操作,故大家下载后需要先执行generate bitstream操作)




C源码
src路径下源码






ACZ702_Lib路径下源码
AXI_GPIO



SCU







tb一下 发表于 2022-8-4 17:03:40

新课程解锁,开始追番

admin 发表于 2022-8-4 17:05:41


本楼层作者占位,主要用来统一解答大家学习本节课程过程中遇到的常见问题,后续会再次编辑完善。学习者有疑问的,请在本楼层之后开始提问和讨论。

CJC 发表于 2022-8-19 21:40:18

本帖最后由 CJC 于 2022-8-20 15:33 编辑

作业1: 发现小梅哥的代码简洁又好用 等等再补上
原代码#include "./BSP/AXI_GPIO/axi_gpio.h"
#include "sleep.h"

XGpio xgpio;

#define AXI_GPIO_ID                        XPAR_GPIO_0_DEVICE_ID

#define SW0                                        axi_gpio_getpin(&xgpio,AXI_GPIO_CHANNEL_1,7)
#define SW1                                        axi_gpio_getpin(&xgpio,AXI_GPIO_CHANNEL_1,6)

#define SW2                                        axi_gpio_getpin(&xgpio,AXI_GPIO_CHANNEL_1,9)
#define SW3                                        axi_gpio_getpin(&xgpio,AXI_GPIO_CHANNEL_1,8)
#define SW4                                        axi_gpio_getpin(&xgpio,AXI_GPIO_CHANNEL_1,11)
#define SW5                                        axi_gpio_getpin(&xgpio,AXI_GPIO_CHANNEL_1,10)

/* 高八位是拨码开关SW7-SW2对应着11-6
* 低八位是LED7-LED2对应着0-5
* */

int main(void)
{
      axi_gpio_init(&xgpio,AXI_GPIO_ID);
      /* 高八位设置为输入,低八位设置输出 */
      XGpio_SetDataDirection(&xgpio, AXI_GPIO_CHANNEL_1,0XFC0);

      while(1)
      {
                if (SW0 == 1)
                {
                        axi_gpio_setpin(&xgpio,AXI_GPIO_CHANNEL_1,5,0x1);
                }
                else
                {
                        axi_gpio_setpin(&xgpio,AXI_GPIO_CHANNEL_1,5,0x0);
                }
                if (SW1 == 1)
                {
                        axi_gpio_setpin(&xgpio,AXI_GPIO_CHANNEL_1,4,0x1);
                }
                else
                {
                        axi_gpio_setpin(&xgpio,AXI_GPIO_CHANNEL_1,4,0x0);
                }
                if (SW2 == 1)
                {
                        axi_gpio_setpin(&xgpio,AXI_GPIO_CHANNEL_1,3,0x1);
                }
                else
                {
                        axi_gpio_setpin(&xgpio,AXI_GPIO_CHANNEL_1,3,0x0);
                }
                if (SW3 == 1)
                {
                        axi_gpio_setpin(&xgpio,AXI_GPIO_CHANNEL_1,2,0x1);
                }
                else
                {
                        axi_gpio_setpin(&xgpio,AXI_GPIO_CHANNEL_1,2,0x0);
                }
                if (SW4 == 1)
                {
                        axi_gpio_setpin(&xgpio,AXI_GPIO_CHANNEL_1,1,0x1);
                }
                else
                {
                        axi_gpio_setpin(&xgpio,AXI_GPIO_CHANNEL_1,1,0x0);
                }
                if (SW5 == 1)
                {
                        axi_gpio_setpin(&xgpio,AXI_GPIO_CHANNEL_1,0,0x1);
                }
                else
                {
                        axi_gpio_setpin(&xgpio,AXI_GPIO_CHANNEL_1,0,0x0);
                }
      }
      return 0;

}

CJC 发表于 2022-8-19 23:32:33

这里记录下学习中遇见的问题,AXI_GPIO硬件信息文件不是xgpio_hw.h而是xgpio_l.h,这个l是什么意思还没想明白

作业二,受到硬件的限制,SW和LED各配置了6位完成
#define AXI_GPIO_BASEADDR                        XPAR_AXI_GPIO_0_BASEADDR


#define SW0                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW0_PIN) & 0x1)
#define SW1                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW1_PIN) & 0x1)
#define SW2                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW2_PIN) & 0x1)
#define SW3                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW3_PIN) & 0x1)
#define SW4                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW4_PIN) & 0x1)
#define SW5                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW5_PIN) & 0x1)


#define SW0_PIN                                7
#define SW1_PIN                                6
#define SW2_PIN                                9
#define SW3_PIN                                8
#define SW4_PIN                                11
#define SW5_PIN                                10

#define LED0                                5
#define LED1                                4
#define LED2                                3
#define LED3                                2
#define LED4                                1
#define LED5                                0



int main(void)
{
        uint32_t reg_val = 0;
        uint32_t data       = 0;
        /* 高八位设置为输入,低八位设置输出 */
        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_TRI_OFFSET,0XFC0);

        while(1)
        {
                if (SW0 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED0);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED0));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                if (SW1 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED1);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED1));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                if (SW2 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED2);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED2));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                if (SW3 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED3);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED3));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                if (SW4 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED4);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED4));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                if (SW5 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED5);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED5));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }

        }

        return 0;

}

CJC 发表于 2022-8-20 07:56:43

这里记录下学习中遇到的问题,AXIGPIO的硬件文件不是xgpio_hw.h,二是xgpio_l.h,这个l代表什么意思还没想明白

#define AXI_GPIO_BASEADDR                        XPAR_AXI_GPIO_0_BASEADDR


#define SW0                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW0_PIN) & 0x1)
#define SW1                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW1_PIN) & 0x1)
#define SW2                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW2_PIN) & 0x1)
#define SW3                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW3_PIN) & 0x1)
#define SW4                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW4_PIN) & 0x1)
#define SW5                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW5_PIN) & 0x1)


#define SW0_PIN                                7
#define SW1_PIN                                6
#define SW2_PIN                                9
#define SW3_PIN                                8
#define SW4_PIN                                11
#define SW5_PIN                                10

#define LED0                                5
#define LED1                                4
#define LED2                                3
#define LED3                                2
#define LED4                                1
#define LED5                                0



int main(void)
{
        uint32_t reg_val = 0;
        uint32_t data       = 0;
        /* 高八位设置为输入,低八位设置输出 */
        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_TRI_OFFSET,0XFC0);

        while(1)
        {
                if (SW0 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED0);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED0));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                if (SW1 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED1);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED1));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                if (SW2 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED2);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED2));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                if (SW3 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED3);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED3));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                if (SW4 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED4);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED4));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                if (SW5 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED5);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED5));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }

        }

        return 0;

}

CJC 发表于 2022-8-20 10:57:17

作业二: 需要提醒的是AXIGPIO的硬件信息文件在xgpio_l.h中,但不太理解这个l是什么意思
用寄存器的方式要注意 使用读改写的编程方式,否则很容易影响到其他位
#define AXI_GPIO_BASEADDR                        XPAR_AXI_GPIO_0_BASEADDR


#define SW0                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW0_PIN) & 0x1)
#define SW1                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW1_PIN) & 0x1)
#define SW2                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW2_PIN) & 0x1)
#define SW3                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW3_PIN) & 0x1)
#define SW4                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW4_PIN) & 0x1)
#define SW5                                ((Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET) >> SW5_PIN) & 0x1)


#define SW0_PIN                                7
#define SW1_PIN                                6
#define SW2_PIN                                9
#define SW3_PIN                                8
#define SW4_PIN                                11
#define SW5_PIN                                10

#define LED0                                5
#define LED1                                4
#define LED2                                3
#define LED3                                2
#define LED4                                1
#define LED5                                0



int main(void)
{
        uint32_t reg_val = 0;
        uint32_t data       = 0;
        /* 高八位设置为输入,低八位设置输出 */
        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_TRI_OFFSET,0XFC0);

        while(1)
        {
                if (SW0 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED0);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED0));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                if (SW1 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED1);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED1));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                if (SW2 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED2);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED2));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                if (SW3 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED3);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED3));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                if (SW4 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED4);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED4));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                if (SW5 == 1)
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val | (1 << LED5);
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }
                else
                {
                        reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                        data = reg_val & (~(1 << LED5));
                        Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
                }

        }

        return 0;

}

CJC 发表于 2022-8-20 15:11:24

CJC 发表于 2022-8-20 10:57
作业二: 需要提醒的是AXIGPIO的硬件信息文件在xgpio_l.h中,但不太理解这个l是什么意思
用寄存器的方式要注 ...
这是看了小梅哥AXIGPIO视频(一)写出来的代码

下面是看了小梅哥编程思路后的代码(寄存器方式) PS:我的拨码开关和LED只有6个
int main(void)
{
      uint32_t reg_val = 0;
      uint32_t data         = 0;
      /* 高六位设置为输入,低六位设置输出 */
      Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_TRI_OFFSET,0XFC0);

      while(1)
      {
                reg_val = Xil_In32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET);
                data = reg_val >> 6;
                Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR + XGPIO_DATA_OFFSET,data);
      }
}

CJC 发表于 2022-8-20 15:33:50

CJC 发表于 2022-8-19 21:40
作业1: 发现小梅哥的代码简洁又好用 等等再补上
原代码#include "./BSP/AXI_GPIO/axi_gpio.h"
#include "sl ...

改进后:
XGpio xgpio;
#define AXI_GPIO_ID                        XPAR_GPIO_0_DEVICE_ID


int main(void)
{
        uint32_t reg_val = 0;
        uint32_t data       = 0;
        axi_gpio_init(&xgpio,AXI_GPIO_ID);
        /* 高六位设置为输入,低六位设置输出 */
        XGpio_SetDataDirection(&xgpio, AXI_GPIO_CHANNEL_1,0XFC0);

        while(1)
        {
                reg_val = XGpio_DiscreteRead(&xgpio, AXI_GPIO_CHANNEL_1);
                data = reg_val >> 6;
                XGpio_DiscreteWrite(&xgpio, AXI_GPIO_CHANNEL_1, data);
        }

}
页: [1] 2
查看完整版本: 【zynq课程笔记】【裸机】【第12课 】【AXI_GPIO原理与应用】