[X]关闭

[米联客-XILINX-H3_CZ08_7100] FPGA_SDK入门篇连载-05 PS-MIO/EMIO实验

文档创建者:FPGA课程
浏览次数:120
最后更新:2024-09-24
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-SOC » 1_SDK应用方案(仅旗舰型号) » 1-SDK基础入门方案
本帖最后由 FPGA课程 于 2024-9-24 19:55 编辑

​ 软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!



1 概述
本课对ZYNQ芯片的PS GPIO进行介绍,通过点亮LED和读取按键输入值,演示PS端MIO/EMIO的使用方法。
本文实验目的:
1:熟悉ZYNQ SOC PS部分MIO/EMIO的内部结构、相关寄存器
2:掌握ZYNQ IP核中如何分配MIO/EMIO
3:掌握SDK 中如何使用MIO/EMIO
2系统框图
PS MIO一般会分配到固定的外设,包括FLASH、EMMC、TFCARD、UART、USB2.0、ETH以太网。PS的IO也可以单独配置成普通的GPIO,如果IO不够用也可以通过EMIO扩展更多IO,对于ZYNQ最多支持扩展64个EMIO。
e4086fccd5224d44823643b854f11c4c.jpg
3PS-MIO/PS-EMIO介绍
ZYNQ SOC PS部分的IO包括PS-MIO和PS-EMIO。MIO分布在PS的Bank0、Bank1,EMIO分布在PS的Bank2、Bank3。PS-MIO具有54个GPIO,PS-EMIO具有最多64个。PS-MIO的IO位置是固定好的,功能也是预先定义好了,而PS-EMIO是通过把芯片内部PS的PS-EMIO引线接到了PL部分的FPGA Pin脚上。
在实际的应用中PS-MIO主要满足必要常用的外设IO需求,比如串口、SDIO、以太网等,而PS-EMIO按需配置,用多少,配置多少。
PS的54个MIO与PS直接相连。不需要添加FPGA的引脚约束,对于EMIO是通过FPGA的IO扩展的,除了需要对PS的ZYNQ IP设置,还需要绑定到FPGA的引脚,所以需要对EMIO做IO引脚约束。
GPIO控制和状态寄存器是从基地址0xE000_A000开始的存储器映射。
3.1PS-MIO/EMIO的BANK
c1165fdea02d4a3a8b829a4f8703b6e0.jpg
PS-MIO:
Bank0:MIO[31:0] GPIO PIN脚号:MIO31~MIO0
Bank1:MIO[53:32] GPIO PIN脚号:MIO53~MIO32
PS-EMIO:
Bank2:EMIO[ 0:31] 可以分配到任意的FPGA IO
Bank3:EMIO[32:63] 可以分配到任意的FPGA IO
所以PS-MIO和EMIO 最多118个IO可用
3.2PS-MIO/EMIO的寄存器
上图中,每个BANK的IO都具有以下的IO结构,下图中不管是MIO还是EMIO,他们的控制寄存器、状态寄存器等都一样,差异也仅仅是MIO是PS固定好了,而EMIO可以把信号映射到FPGA的IO上。
f00fac9b914643729ddca7aa16969c7b.jpg
本方案只讲解MIO/EMIO的输入输出配置,中断相关的寄存器,下一个方案中讲解。
1:DATA_RO寄存器:
MIO/EMIO的数据只读寄存器,不管是输入还是输出,都可以通过该寄存器读取到当前IO的状态;
2:DATA寄存器:
MIO/EMIO数据寄存器,可读写,一般是写入数据控制IO的输出值;  
3:MASK_DATA_LSW寄存器:
BANK IO中低16位IO位设置寄存器。该寄存器分高16中对应位设置0,用于数据的更新输出,低16用于设置需要输出的数据。
4:MASK_DATA_MSW寄存器:
BANK IO中高16位IO位设置寄存器。该寄存器分高16中对应位设置0,用于数据的更新输出,低16用于设置需要输出的数据。
5:DIRM:寄存器
MIO/EMIO的方向控制寄存器,当DIRM[x]==0时候,禁止输出
6:OEN寄存器:
MIO/EMIO输出使能寄存器,当配置成MIO的时候,设置OEN[x]=0,MIO处于三态,但是EMIO不支持三态。
当设置DIRM[x] & OEN[x]=0  MIO/EMIO输出;
当设置DIRM[x] & OEN[x]=1  MIO/EMIO输入;
关于更多寄存器的定义说明,可以参考技术手册ug585-Zynq-7000-TRM.pdf
注意:如果MIO TRI_ENABLE设置为1,则启用三态并禁用驱动器,则OEN将被忽略并且输出为三态。
4硬件电路分析
这里我们需要用到2个MIO,6个EMIO(PL 的IO 可以定义为EMIO),其中MIO51的输出高电平是1.8V所以亮度会比较低一些。
05f91914894d4ef3a28e869b395de8a5.jpg
配套工程的FPGA PIN脚定义路径为soc_prj/uisrc/04_pin/ fpga_pin.xdc。
5搭建SOC系统工程
详细的搭建过程这里不再重复,对于初学读者如果还不清楚如何创建SOC工程的,请学习“01Vitis Soc开发入门”这篇文章。
本文中的PS设置内容是新增加的EMIO部分,关于DDR、MIO、CPU时钟等设置请参考“01Vitis Soc开发入门”这篇文章。
5.1MIO/EMIO配置
01Vitis Soc开发入门”这篇文章中已经对特定功能的MIO做了设置,只有剩余的MIO可以用于其他的自定义功能。以下设置未分配功能的MIO,以及需要扩展的EMIO的数量。
64aa393ffa7b4c47a12127fd1484f874.jpg
5.2EMIO在PL中定义
设置好后,右击GPIO_0引出GPIO_0并且改名为ps_emio.
114f647e562e4918998eb2f2c3740a36.jpg
由于ps_emio最终需要定义到FPGA的IO中,所以我们需要引出ps_emio信号到顶层文件
0ddaa687a3e94af3a7899a501010a584.jpg

  1. `timescale 1 ps / 1 ps

  2. module system_wrapper
  3.    (DDR_addr,
  4.     DDR_ba,
  5.     DDR_cas_n,
  6.     DDR_ck_n,
  7.     DDR_ck_p,
  8.     DDR_cke,
  9.     DDR_cs_n,
  10.     DDR_dm,
  11.     DDR_dq,
  12.     DDR_dqs_n,
  13.     DDR_dqs_p,
  14.     DDR_odt,
  15.     DDR_ras_n,
  16.     DDR_reset_n,
  17.     DDR_we_n,
  18.     FIXED_IO_ddr_vrn,
  19.     FIXED_IO_ddr_vrp,
  20.     FIXED_IO_mio,
  21.     FIXED_IO_ps_clk,
  22.     FIXED_IO_ps_porb,
  23.     FIXED_IO_ps_srstb,
  24.     ps_emio_tri_io);
  25.   inout [14:0]DDR_addr;
  26.   inout [2:0]DDR_ba;
  27.   inout DDR_cas_n;
  28.   inout DDR_ck_n;
  29.   inout DDR_ck_p;
  30.   inout DDR_cke;
  31.   inout DDR_cs_n;
  32.   inout [3:0]DDR_dm;
  33.   inout [31:0]DDR_dq;
  34.   inout [3:0]DDR_dqs_n;
  35.   inout [3:0]DDR_dqs_p;
  36.   inout DDR_odt;
  37.   inout DDR_ras_n;
  38.   inout DDR_reset_n;
  39.   inout DDR_we_n;
  40.   inout FIXED_IO_ddr_vrn;
  41.   inout FIXED_IO_ddr_vrp;
  42.   inout [53:0]FIXED_IO_mio;
  43.   inout FIXED_IO_ps_clk;
  44.   inout FIXED_IO_ps_porb;
  45.   inout FIXED_IO_ps_srstb;
  46.   inout [5:0]ps_emio_tri_io;

  47.   wire [14:0]DDR_addr;
  48.   wire [2:0]DDR_ba;
  49.   wire DDR_cas_n;
  50.   wire DDR_ck_n;
  51.   wire DDR_ck_p;
  52.   wire DDR_cke;
  53.   wire DDR_cs_n;
  54.   wire [3:0]DDR_dm;
  55.   wire [31:0]DDR_dq;
  56.   wire [3:0]DDR_dqs_n;
  57.   wire [3:0]DDR_dqs_p;
  58.   wire DDR_odt;
  59.   wire DDR_ras_n;
  60.   wire DDR_reset_n;
  61.   wire DDR_we_n;
  62.   wire FIXED_IO_ddr_vrn;
  63.   wire FIXED_IO_ddr_vrp;
  64.   wire [53:0]FIXED_IO_mio;
  65.   wire FIXED_IO_ps_clk;
  66.   wire FIXED_IO_ps_porb;
  67.   wire FIXED_IO_ps_srstb;
  68.   wire [0:0]ps_emio_tri_i_0;
  69.   wire [1:1]ps_emio_tri_i_1;
  70.   wire [2:2]ps_emio_tri_i_2;
  71.   wire [3:3]ps_emio_tri_i_3;
  72.   wire [4:4]ps_emio_tri_i_4;
  73.   wire [5:5]ps_emio_tri_i_5;
  74.   wire [0:0]ps_emio_tri_io_0;
  75.   wire [1:1]ps_emio_tri_io_1;
  76.   wire [2:2]ps_emio_tri_io_2;
  77.   wire [3:3]ps_emio_tri_io_3;
  78.   wire [4:4]ps_emio_tri_io_4;
  79.   wire [5:5]ps_emio_tri_io_5;
  80.   wire [0:0]ps_emio_tri_o_0;
  81.   wire [1:1]ps_emio_tri_o_1;
  82.   wire [2:2]ps_emio_tri_o_2;
  83.   wire [3:3]ps_emio_tri_o_3;
  84.   wire [4:4]ps_emio_tri_o_4;
  85.   wire [5:5]ps_emio_tri_o_5;
  86.   wire [0:0]ps_emio_tri_t_0;
  87.   wire [1:1]ps_emio_tri_t_1;
  88.   wire [2:2]ps_emio_tri_t_2;
  89.   wire [3:3]ps_emio_tri_t_3;
  90.   wire [4:4]ps_emio_tri_t_4;
  91.   wire [5:5]ps_emio_tri_t_5;

  92.   IOBUF ps_emio_tri_iobuf_0
  93.        (.I(ps_emio_tri_o_0),
  94.         .IO(ps_emio_tri_io[0]),
  95.         .O(ps_emio_tri_i_0),
  96.         .T(ps_emio_tri_t_0));
  97.   IOBUF ps_emio_tri_iobuf_1
  98.        (.I(ps_emio_tri_o_1),
  99.         .IO(ps_emio_tri_io[1]),
  100.         .O(ps_emio_tri_i_1),
  101.         .T(ps_emio_tri_t_1));
  102.   IOBUF ps_emio_tri_iobuf_2
  103.        (.I(ps_emio_tri_o_2),
  104.         .IO(ps_emio_tri_io[2]),
  105.         .O(ps_emio_tri_i_2),
  106.         .T(ps_emio_tri_t_2));
  107.   IOBUF ps_emio_tri_iobuf_3
  108.        (.I(ps_emio_tri_o_3),
  109.         .IO(ps_emio_tri_io[3]),
  110.         .O(ps_emio_tri_i_3),
  111.         .T(ps_emio_tri_t_3));
  112.   IOBUF ps_emio_tri_iobuf_4
  113.        (.I(ps_emio_tri_o_4),
  114.         .IO(ps_emio_tri_io[4]),
  115.         .O(ps_emio_tri_i_4),
  116.         .T(ps_emio_tri_t_4));
  117.   IOBUF ps_emio_tri_iobuf_5
  118.        (.I(ps_emio_tri_o_5),
  119.         .IO(ps_emio_tri_io[5]),
  120.         .O(ps_emio_tri_i_5),
  121.         .T(ps_emio_tri_t_5));
  122.   system system_i
  123.        (.DDR_addr(DDR_addr),
  124.         .DDR_ba(DDR_ba),
  125.         .DDR_cas_n(DDR_cas_n),
  126.         .DDR_ck_n(DDR_ck_n),
  127.         .DDR_ck_p(DDR_ck_p),
  128.         .DDR_cke(DDR_cke),
  129.         .DDR_cs_n(DDR_cs_n),
  130.         .DDR_dm(DDR_dm),
  131.         .DDR_dq(DDR_dq),
  132.         .DDR_dqs_n(DDR_dqs_n),
  133.         .DDR_dqs_p(DDR_dqs_p),
  134.         .DDR_odt(DDR_odt),
  135.         .DDR_ras_n(DDR_ras_n),
  136.         .DDR_reset_n(DDR_reset_n),
  137.         .DDR_we_n(DDR_we_n),
  138.         .FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn),
  139.         .FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp),
  140.         .FIXED_IO_mio(FIXED_IO_mio),
  141.         .FIXED_IO_ps_clk(FIXED_IO_ps_clk),
  142.         .FIXED_IO_ps_porb(FIXED_IO_ps_porb),
  143.         .FIXED_IO_ps_srstb(FIXED_IO_ps_srstb),
  144.         .ps_emio_tri_i({ps_emio_tri_i_5,ps_emio_tri_i_4,ps_emio_tri_i_3,ps_emio_tri_i_2,ps_emio_tri_i_1,ps_emio_tri_i_0}),
  145.         .ps_emio_tri_o({ps_emio_tri_o_5,ps_emio_tri_o_4,ps_emio_tri_o_3,ps_emio_tri_o_2,ps_emio_tri_o_1,ps_emio_tri_o_0}),
  146.         .ps_emio_tri_t({ps_emio_tri_t_5,ps_emio_tri_t_4,ps_emio_tri_t_3,ps_emio_tri_t_2,ps_emio_tri_t_1,ps_emio_tri_t_0}));
  147. endmodule
复制代码

以上代码中,原语IOBUF对于很多初学者来说,可能会有疑惑,所以有必要介绍下如何使用。
  1.    IOBUF IOBUF_inst (
  2.       .O(O),   // 1-bit output: Buffer output  方向是外部引脚IO 输入到FPGA内部逻辑
  3.       .I(I),   // 1-bit input: Buffer input方向是FPGA内部逻辑输出到外部引脚IO
  4.       .IO(IO), // 1-bit inout: Buffer inout (connect directly to top-level port) 外部引脚IO
  5.       .T(T)    // 1-bit input: 3-state enable input 定义输入还是输出,当T=0 IO是三态的可以用于输入,当T=1 是输出
  6.    );
复制代码

5.3编译并导出平台文件
以下步骤简写,有不清楚的看第一篇文章。
1:单击Block文件à右键àGenerate the Output ProductsàGlobalàGenerate。
2:单击Block文件à右键à Create a HDL wrapper(生成HDL顶层文件)àLet vivado manager wrapper and auto-update(自动更新)。
3:添加配套工程路径下uisrc/04_pin/fpga_pin.xdc约束文件
4:生成Bit文件。
5:导出到硬件: FileàExport HardwareàInclude bitstream
6:导出完成后,对应工程路径的soc_hw路径下有硬件平台文件:system_wrapper.xsa的文件。根据硬件平台文件system_wrapper.xsa来创建需要Platform平台。
4e5d02643a6546e2a909938711b4b3c6.jpg
6 搭建Vitis-sdk工程
创建soc_base sdk platform和APP工程的过程不再重复,如果不清楚请参考本章节第一个demo。
6.1创建SDK Platform工程
25cd8000bbee4e508e162d01586ba96a.jpg
右击soc_base编译,编译的时间可能会有点长
  1. #include "xparameters.h"
  2. #include "xgpiops.h"
  3. #include "xstatus.h"
  4. #include "xplatform_info.h"
  5. #include <xil_printf.h>


  6. #ifndef GPIO_DEVICE_ID
  7. #define GPIO_DEVICE_ID                XPAR_XGPIOPS_0_DEVICE_ID
  8. #endif

  9. #define printf xil_printf        /* Smalller foot-print printf */

  10. XGpioPs Gpio;        /* The driver instance for GPIO Device. */

  11. #define LED0  (50)// MIO
  12. #define LED1  (54)//EMIO
  13. #define LED2  (55)//EMIO
  14. #define LED3  (56)//EMIO
  15. #define LED4  (57)//EMIO
  16. #define BTN0  (58)//EMIO
  17. #define BTN1  (59)//EMIO
  18. #define BTN2  (51)// MIO

  19. int GpioPolledInit(u16 DeviceId);

  20. int main(void)
  21. {
  22.         int Status;
  23.         u8  nled =0;
  24.         u32 val_btn0 ;
  25.         u32 val_btn1 ;
  26.         u32 val_btn2 ;

  27.         printf("GPIO Polled Mode Example Test \r\n");

  28.         Status = GpioPolledInit(GPIO_DEVICE_ID);

  29.         if (Status != XST_SUCCESS) {
  30.                 printf("GPIO Polled Mode Example Test Failed\r\n");
  31.                 return XST_FAILURE;
  32.         }

  33.         while(Status == XST_SUCCESS)
  34.         {
  35.                 //驱动LED
  36.                 XGpioPs_WritePin(&Gpio, LED0, nled==0);
  37.                 XGpioPs_WritePin(&Gpio, LED1, nled==1);
  38.                 XGpioPs_WritePin(&Gpio, LED2, nled==2);
  39.                 XGpioPs_WritePin(&Gpio, LED3, nled==3);
  40.                 XGpioPs_WritePin(&Gpio, LED4, nled==4);
  41. //读取硬件值
  42.                 val_btn0 = XGpioPs_ReadPin(&Gpio, BTN0 );
  43.                 val_btn1 = XGpioPs_ReadPin(&Gpio, BTN1 );
  44.                 val_btn2 = XGpioPs_ReadPin(&Gpio, BTN2 );
  45.                         
  46.                 printf("btn0=0x%x btn1=0xx% btn2=0x%x \n\r", val_btn0,val_btn1,val_btn2);               
  47.                 if(nled == 4)
  48.                         nled = 0;
  49.                 else
  50.                         nled++;

  51.                 sleep(1);
  52.         }

  53.         return XST_SUCCESS;
  54. }

  55. int GpioPolledInit(u16 DeviceId)
  56. {
  57.         int Status;
  58.         XGpioPs_Config *ConfigPtr;
  59.         /* Initialize the GPIO driver. */
  60.         ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
  61.         Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);

  62.      //设置LED相关的MIO EMIO为输出方向
  63.         XGpioPs_SetDirectionPin(&Gpio, LED0, 0x1);
  64.         XGpioPs_SetDirectionPin(&Gpio, LED1, 0x1);
  65.         XGpioPs_SetDirectionPin(&Gpio, LED2, 0x1);
  66.         XGpioPs_SetDirectionPin(&Gpio, LED3, 0x1);
  67.         XGpioPs_SetDirectionPin(&Gpio, LED4, 0x1);

  68.         //设置按键相关的IO为输入方向
  69.         XGpioPs_SetDirectionPin(&Gpio,BTN0, 0x0);
  70.         XGpioPs_SetDirectionPin(&Gpio,BTN1, 0x0);
  71.         XGpioPs_SetDirectionPin(&Gpio,BTN2, 0x0);

  72. //设置LED的输出使能
  73.         XGpioPs_SetOutputEnablePin(&Gpio, LED0, 1);
  74.         XGpioPs_SetOutputEnablePin(&Gpio, LED1, 1);
  75.         XGpioPs_SetOutputEnablePin(&Gpio, LED2, 1);
  76.         XGpioPs_SetOutputEnablePin(&Gpio, LED3, 1);
  77.         XGpioPs_SetOutputEnablePin(&Gpio, LED4, 1);

  78. //设置LED默认的输出为1
  79.         XGpioPs_WritePin(&Gpio, LED0, 1);
  80.         XGpioPs_WritePin(&Gpio, LED1, 1);
  81.         XGpioPs_WritePin(&Gpio, LED2, 1);
  82.         XGpioPs_WritePin(&Gpio, LED3, 1);
  83.         XGpioPs_WritePin(&Gpio, LED4, 1);

  84.         return Status;
  85. }
复制代码

接下来对程序进行分析。
7.1结构体static XGpioPs Gpio
含义:这是一个指针实例,指向添加的GPIO端口。
具体分析:
XGpiops:绿色标识的一个结构体。Vitis IDE中结构体都用绿色标识。
将鼠标停留在XGpiops上或右键Open Declaration,查看这个结构体所包含的内容。
3aae7e26b7bb409e8289bf643bbe396c.jpg
结构体包含GPIO一些参数,分别是:
typedef struct {
XGpioPs_Config GpioConfig; /**< 设备配置*/
u32 IsReady;     /**<设备是否初始化并准备好 */
XGpioPs_Handler Handler; /**<所有状态的处理程序*/
void *CallBackRef; /**<块处理程序的回调*/
u32 Platform;     /**<设备数据*/
u32 MaxPinNum; /**< GPIO的最大pin数量 */
u8 MaxBanks;     /**< GPIO的最大的bank数量 */
} XGpioPs;
7.2结构体XGpioPs_Config *ConfigPtr
含义:这是一个指针实例。
具体分析
XGpioPs_Config:绿色标识的一个结构体。
将鼠标停留在XGpiops上或右键Open Declaration,查看这个结构体所包含的内容。
a1de2f81ec2949b7a921643cba65d7d4.jpg
          此结构体存放的是GPIO的设备地址和基地址。
7.3 MIO/EMIO序号定义
#define LED0  (51)// MIO
#define LED1  (54)//EMIO
#define LED2  (55)//EMIO
#define LED3  (56)//EMIO
#define LED4  (57)//EMIO
#define BTN0  (58)//EMIO
#define BTN1  (59)//EMIO
#define BTN2  (50)// MIO
含义:PIN序号
是告知程序,操作的MIO或者EMIO在SDK代码中的序号,根据整个需要可以找到当前操作的IO寄存器属于哪一个BANK,以及哪一位,具体的下面代码会继续分析。
7.4 XGpioPs_LookupConfig(DeviceId)函数
此函数中XGpioPs_ConfigTable定义了GPIO的参数信息,右击可以查看具体信息
85e56b344eaf4f768cee6258e8d63906.jpg

99c37d1700804bf59584a4b0c30380e1.jpg
继续右击以下GPIO地址定义,可以查到GPIO外设的基地址:
ba3a3f26478543788d23d6d7af558cd9.jpg

d824ebcb97cd4e2eb4521ce4add510fe.jpg
7.5 XGpioPs_CfgInitialize(InstancePtr, ConfigPtr, ConfigPtr->BaseAddr)函数
095f8a92a4974bf39834ceacad86f3b5.jpg
以上代码中首先根据硬件平台如果是ZYNQ SOC那么IO BANK最多4个 IO数量最多118个,如果是ZYNQ MPSOC平台,那么IO BANK最多是6个,IO数量最多174个。
7.6 XGpioPs_SetDirectionPin(InstancePtr, LED0,1)函数
设置IO方向,最后一个参数0代表输入,1代表输出。
8e866205b7c44bbb92efadb1fa2ed69b.jpg
以上代码首先需计算IO所在的BANK和在这个BANK中IO序号。通过函数XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber)计算。这里以MIO51来说,其位于BANK1中
每个BANK的PS IO方向控制寄存器偏移计算=BANK *XGPIOPS_REG_MASK_OFFSET+ XGPIOPS_DIRM_OFFSET我们主要看XGPIOPS_DIRM_OFFSET。
其中XGPIOPS_DIRM_OFFSET = 0x00000204代表了相对每个BANK的偏移地址,我们看方向寄存器的定义:

                        
Field Name
                        
                        
Bits
                        
                        
Type
                        
                        
Reset Value
                        
                        
Description
                        
                        
DIRECTION_1
                        
                        
31:0
                        
                        
Rw
                        
                        
0x0
                        
                        
0:输入
                        
1:输出
                        

7.7 XGpioPs_SetOutputEnablePin(InstancePtr, LED, 1)函数
6a1cf78dc41c491ebb9d7697ae8c576f.jpg
以上代码首先需计算IO所在的BANK和在这个BANK中IO序号。通过函数XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber)计算。以MIO51来说,其位于BANK1
每个BANK的PS IO方向控制寄存器偏移计算=BANK *XGPIOPS_REG_MASK_OFFSET+ XGPIOPS_OUTEN_OFFSET我们主要看XGPIOPS_ XGPIOPS_OUTEN_OFFSET其中XGPIOPS_OUTEN_OFFSET = 0x00000208代表了相对每个BANK的偏移地址,我们看方向寄存器的定义:

                        
Field Name
                        
                        
Bits
                        
                        
Type
                        
                        
Reset Value
                        
                        
Description
                        
                        
OP_ENABLE_1
                        
                        
31:0
                        
                        
Rw
                        
                        
0x0
                        
                        
0:禁止输出
                        
1:使能输出
                        
7.8 XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber)函数
将鼠标停留在XGpioPs_GetBankPin函数上,按F3查看下其功能。
610d748fa29d43c595489fec728f4a8f.jpg
上述部分为程序查找bank号对应代码。程序首先判断平台的类型,这里是ZYNQ平台。GPIO简介介绍ZYNQ有4个bank,因此当程序执行后,程序首先执行else部分的程序。此时看else部分程序。程序给出了4个bank的bank号的最大值,初始化bank号为0,while语句限制了bank的最大数量为4。然后用pin的序号从bank0到bank3逐个比对,若是此时pin的序号小于或等于当前bank的最大值,则可以判断出pin是属于这个bank的,跳出while语句,否则bank号进行自加操作直到得出符合的bank号。接下来if语句,判断bank号是否为bank0,若是则将PinNumber直接赋值,否则在最后的else代码中计算得出PinNumber。
7.9 XGpioPs_WritePin函数
语句:XGpioPs_WritePin(&psGpioInstancePtr, LED0, 1)
含义:写数据到pin脚
具体分析:
XGpioPs_WritePin的参数分别为gpio的基地址、要操作的MIO号和写入的数据。定义如下:
a83f36d0f77c4accb05836e6d0d96a3a.jpg
这里仅以MIO51所在BANK1的做介绍,其他BANK使用一样。
这里设置位控制输出寄存器MASK_DATA_MSW,该寄存器分2部分,高16bit是控制输出更新,低16bit为输出具体的值。
                        
Field Name
                        
                        
Bits
                        
                        
Type
                        
                        
Reset Value
                        
                        
Description
                        
                        
MASK_1_MSW
                        
                        
31:16
                        
                        
wo
                        
                        
0x0
                        
                        
0:更新输出
                        
1:屏蔽该位
                        
                        
DATA_1_MSW
                        
                        
15:0
                        
                        
rw
                        
                        
x
                        
                        
需要更新的数据
                        
根据XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber)获取IO所在BANK以及IO号,决定是要写入数据的高16位数据寄存器还是低16位数据寄存器。
此时再看XGpioPs_WritePin函数的接下来的这段程序:
75d787663bae4f849ff541899e3adaf1.jpg
这段程序完成向指定PS IO写入某个值的操作。这里我们以MIO51写入1来做说明。
1-MIO51在BANK1,对应的BANK1中的位号为19
2-19>16因此需要写入高16bit数据寄存器,其地址偏移为XGPIOPS_DATA_MSW_OFFSET的偏移地址
3-DataVar &= (u32)0x01;因为输入的是1所以计算后DataVar还是1
4-~((u32)1 << (PinNumber + 16U)) 设置 MASK_1_MSW[31:16] 高16bit掩码,MASK_1_MSW[31:16] = ~(1<<19)=0xf7ff
5-(DataVar << PinNumber) | 0xFFFF0000U)设置MASK_1_MSW[15:0]低16bit对应的IO值,MASK_1_MSW[15:0]=0xfff8
XGpioPs_WriteReg函数中第一个参数为设备的基地址, 第二个参数为偏移量,此处为12,第三个参数为要写入寄存器的数据。按照之前讲解的方法,开发人员可自行对库函数进行学习分析。
8方案演示
8.1硬件准备
本实验需要用到 JTAG 下载器、USB 转串口外设,另外需要把核心板上的 2P 模式开关设置到 JTAG 模式,即 ON ON(注意新版本的 MLK_H3_CZ08-7100-MZ7100FC),支持 JTAG 模式,对于老版本的核心板,JTAG 调试的时候 一定要拔掉 TF 卡,并且设置模式开关为 OFF OFF)
5b1c6a2f159945f1b2e0f20cfd4fe434.jpg
8.2实验结果
IO输出功能,可看到底板上的流水灯运行
IO输入功能,可以通过串口打印读到的按键输入,默认按键都是上拉的高电平。
6d96ee1ca24e4b998b1c82bd5be51537.jpg

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

本版积分规则