芯路恒电子技术论坛

 找回密码
 立即注册
热搜: 合集
查看: 14634|回复: 10

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

[复制链接]
  • TA的每日心情
    慵懒
    2021-2-24 10:16
  • 428

    主题

    811

    帖子

    1万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    16109
    QQ
    发表于 2022-8-4 16:23:30 | 显示全部楼层 |阅读模式
    更多课程笔记请查看:【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核的结构如下:

    图1.png

    图 3 4  AXI 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灯,非常适合本次设计。

    图2.png
    图3.png

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


    4        系统框图

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

    图4.png

    在设计时,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[7]
      
      E17
      
       
      
      LED7
      
      gpio_rtl_1_tri_io[7]
      
      K18
      
      SW6
      
      gpio_rtl_0_tri_io[6]
      
      D18
      
       
      
      LED6
      
      gpio_rtl_1_tri_io[6]
      
      H17
      
      SW5
      
      gpio_rtl_0_tri_io[5]
      
      H15
      
       
      
      LED5
      
      gpio_rtl_1_tri_io[5]
      
      J18
      
      SW4
      
      gpio_rtl_0_tri_io[4]
      
      F16
      
       
      
      LED4
      
      gpio_rtl_1_tri_io[4]
      
      K19
      
      SW3
      
      gpio_rtl_0_tri_io[3]
      
      J14
      
       
      
      LED3
      
      gpio_rtl_1_tri_io[3]
      
      G18
      
      SW2
      
      gpio_rtl_0_tri_io[2]
      
      G14
      
       
      
      LED2
      
      gpio_rtl_1_tri_io[2]
      
      G20
      
      SW1
      
      gpio_rtl_0_tri_io[1]
      
      L15
      
       
      
      LED1
      
      gpio_rtl_1_tri_io[1]
      
      G19
      
      SW0
      
      gpio_rtl_0_tri_io[0]
      
      K14
      
       
      
      LED0
      
      gpio_rtl_1_tri_io[0]
      
      G17
      



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


    8        查看编译报告

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

    图5.png

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

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



    10        硬件连接

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

    图6.jpg

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


    11        运行程序

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


    12        代码分析

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

    [C] 纯文本查看 复制代码
    #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 GPIO  3态控制寄存器
      
      0x0008
      
      GPIO2_DATA
      
      R/W
      
      0x0
      
      通道2 AXI  GP[IO数据寄存器
      
      0x000C
      
      GPIO2_TRI
      
      R/W
      
      0x0
      
      通道2 AXI GPIO  3态寄存器
      
      0x011C
      
      GIER
      
      R/W
      
      0x0
      
      全局中断使能寄存器
      
      0x0128
      
      IP IER
      
      R/W
      
      0x0
      
      IP中断使能寄存器
      
      0x0120
      
      IP ISR
      
      R/TOW
      
      0x0
      
      IP中断状态寄存器
      


    表 2  AXI GPIO数据寄存器描述
      位
      
      字段名
      
      访问类型
      
      复位值
      
      描述
      
      [GPIOx_Width-1:0]
      
      GPIOx_DATA
      
      R/W
      
      对应通道默认输出值
      
      AXI GPIO数据寄存器
      对于每个被配置为输入的I/O:
      读:读取输入引脚的值
      写:无效
      对于每个被配置为输出的I/O:
      读:读取这些位将会返回0
      写:将值写入相应寄存器位和输出引脚。
      

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

    图7.png

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

    表 3  AXI GPIO 3态寄存器位描述
      位
      
      字段名
      
      访问类型
      
      复位值
      
      描述
      
      [GPIOx_Width-1:0]
      
      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裸机编程课程笔记合集”

    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2021-2-24 10:16
  • 428

    主题

    811

    帖子

    1万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    16109
    QQ
     楼主| 发表于 2022-8-4 16:56:13 | 显示全部楼层
    课程完整工程文件包括Vivado工程和SDK中的源码(工程发布前已经执行了reset_project操作,故大家下载后需要先执行generate bitstream操作)
    AXI_GPIO.rar (2.29 MB, 下载次数: 427)




    C源码
    src路径下源码
    COMMON.c (464 Bytes, 下载次数: 258)
    COMMON.h (783 Bytes, 下载次数: 245)
    ISR.c (849 Bytes, 下载次数: 250)
    ISR.h (160 Bytes, 下载次数: 238)
    main.c (920 Bytes, 下载次数: 260)

    ACZ702_Lib路径下源码
    AXI_GPIO
    AXI_GPIO.c (4.78 KB, 下载次数: 240)
    AXI_GPIO.h (667 Bytes, 下载次数: 264)

    SCU
    SCU_GIC.c (2.07 KB, 下载次数: 247)
    SCU_GIC.h (421 Bytes, 下载次数: 271)
    SCU_TIMER.c (1.56 KB, 下载次数: 249)
    SCU_TIMER.h (212 Bytes, 下载次数: 236)



    回复 支持 反对

    使用道具 举报

    该用户从未签到

    71

    主题

    100

    帖子

    1525

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    1525
    发表于 2022-8-4 17:03:40 | 显示全部楼层
    新课程解锁,开始追番
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    慵懒
    2021-2-24 10:16
  • 428

    主题

    811

    帖子

    1万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    16109
    QQ
     楼主| 发表于 2022-8-4 17:05:41 | 显示全部楼层

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

    使用道具 举报

  • TA的每日心情
    擦汗
    2024-3-26 13:58
  • 3

    主题

    30

    帖子

    319

    积分

    中级会员

    Rank: 4

    积分
    319
    发表于 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;

    }

    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2024-3-26 13:58
  • 3

    主题

    30

    帖子

    319

    积分

    中级会员

    Rank: 4

    积分
    319
    发表于 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;

    }
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2024-3-26 13:58
  • 3

    主题

    30

    帖子

    319

    积分

    中级会员

    Rank: 4

    积分
    319
    发表于 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;

    }
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2024-3-26 13:58
  • 3

    主题

    30

    帖子

    319

    积分

    中级会员

    Rank: 4

    积分
    319
    发表于 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;

    }
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2024-3-26 13:58
  • 3

    主题

    30

    帖子

    319

    积分

    中级会员

    Rank: 4

    积分
    319
    发表于 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);
            }
    }
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2024-3-26 13:58
  • 3

    主题

    30

    帖子

    319

    积分

    中级会员

    Rank: 4

    积分
    319
    发表于 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);
            }

    }
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|小黑屋|Archiver|芯路恒电子技术论坛 |鄂ICP备2021003648号

    GMT+8, 2024-11-23 17:51 , Processed in 0.127393 second(s), 36 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc. Template By 【未来科技】【 www.wekei.cn 】

    快速回复 返回顶部 返回列表