本帖最后由 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。
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
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上。
本方案只讲解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所以亮度会比较低一些。
配套工程的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的数量。
5.2EMIO在PL中定义设置好后,右击GPIO_0引出GPIO_0并且改名为ps_emio.
由于ps_emio最终需要定义到FPGA的IO中,所以我们需要引出ps_emio信号到顶层文件
- `timescale 1 ps / 1 ps
- module system_wrapper
- (DDR_addr,
- DDR_ba,
- DDR_cas_n,
- DDR_ck_n,
- DDR_ck_p,
- DDR_cke,
- DDR_cs_n,
- DDR_dm,
- DDR_dq,
- DDR_dqs_n,
- DDR_dqs_p,
- DDR_odt,
- DDR_ras_n,
- DDR_reset_n,
- DDR_we_n,
- FIXED_IO_ddr_vrn,
- FIXED_IO_ddr_vrp,
- FIXED_IO_mio,
- FIXED_IO_ps_clk,
- FIXED_IO_ps_porb,
- FIXED_IO_ps_srstb,
- ps_emio_tri_io);
- inout [14:0]DDR_addr;
- inout [2:0]DDR_ba;
- inout DDR_cas_n;
- inout DDR_ck_n;
- inout DDR_ck_p;
- inout DDR_cke;
- inout DDR_cs_n;
- inout [3:0]DDR_dm;
- inout [31:0]DDR_dq;
- inout [3:0]DDR_dqs_n;
- inout [3:0]DDR_dqs_p;
- inout DDR_odt;
- inout DDR_ras_n;
- inout DDR_reset_n;
- inout DDR_we_n;
- inout FIXED_IO_ddr_vrn;
- inout FIXED_IO_ddr_vrp;
- inout [53:0]FIXED_IO_mio;
- inout FIXED_IO_ps_clk;
- inout FIXED_IO_ps_porb;
- inout FIXED_IO_ps_srstb;
- inout [5:0]ps_emio_tri_io;
- wire [14:0]DDR_addr;
- wire [2:0]DDR_ba;
- wire DDR_cas_n;
- wire DDR_ck_n;
- wire DDR_ck_p;
- wire DDR_cke;
- wire DDR_cs_n;
- wire [3:0]DDR_dm;
- wire [31:0]DDR_dq;
- wire [3:0]DDR_dqs_n;
- wire [3:0]DDR_dqs_p;
- wire DDR_odt;
- wire DDR_ras_n;
- wire DDR_reset_n;
- wire DDR_we_n;
- wire FIXED_IO_ddr_vrn;
- wire FIXED_IO_ddr_vrp;
- wire [53:0]FIXED_IO_mio;
- wire FIXED_IO_ps_clk;
- wire FIXED_IO_ps_porb;
- wire FIXED_IO_ps_srstb;
- wire [0:0]ps_emio_tri_i_0;
- wire [1:1]ps_emio_tri_i_1;
- wire [2:2]ps_emio_tri_i_2;
- wire [3:3]ps_emio_tri_i_3;
- wire [4:4]ps_emio_tri_i_4;
- wire [5:5]ps_emio_tri_i_5;
- wire [0:0]ps_emio_tri_io_0;
- wire [1:1]ps_emio_tri_io_1;
- wire [2:2]ps_emio_tri_io_2;
- wire [3:3]ps_emio_tri_io_3;
- wire [4:4]ps_emio_tri_io_4;
- wire [5:5]ps_emio_tri_io_5;
- wire [0:0]ps_emio_tri_o_0;
- wire [1:1]ps_emio_tri_o_1;
- wire [2:2]ps_emio_tri_o_2;
- wire [3:3]ps_emio_tri_o_3;
- wire [4:4]ps_emio_tri_o_4;
- wire [5:5]ps_emio_tri_o_5;
- wire [0:0]ps_emio_tri_t_0;
- wire [1:1]ps_emio_tri_t_1;
- wire [2:2]ps_emio_tri_t_2;
- wire [3:3]ps_emio_tri_t_3;
- wire [4:4]ps_emio_tri_t_4;
- wire [5:5]ps_emio_tri_t_5;
- IOBUF ps_emio_tri_iobuf_0
- (.I(ps_emio_tri_o_0),
- .IO(ps_emio_tri_io[0]),
- .O(ps_emio_tri_i_0),
- .T(ps_emio_tri_t_0));
- IOBUF ps_emio_tri_iobuf_1
- (.I(ps_emio_tri_o_1),
- .IO(ps_emio_tri_io[1]),
- .O(ps_emio_tri_i_1),
- .T(ps_emio_tri_t_1));
- IOBUF ps_emio_tri_iobuf_2
- (.I(ps_emio_tri_o_2),
- .IO(ps_emio_tri_io[2]),
- .O(ps_emio_tri_i_2),
- .T(ps_emio_tri_t_2));
- IOBUF ps_emio_tri_iobuf_3
- (.I(ps_emio_tri_o_3),
- .IO(ps_emio_tri_io[3]),
- .O(ps_emio_tri_i_3),
- .T(ps_emio_tri_t_3));
- IOBUF ps_emio_tri_iobuf_4
- (.I(ps_emio_tri_o_4),
- .IO(ps_emio_tri_io[4]),
- .O(ps_emio_tri_i_4),
- .T(ps_emio_tri_t_4));
- IOBUF ps_emio_tri_iobuf_5
- (.I(ps_emio_tri_o_5),
- .IO(ps_emio_tri_io[5]),
- .O(ps_emio_tri_i_5),
- .T(ps_emio_tri_t_5));
- system system_i
- (.DDR_addr(DDR_addr),
- .DDR_ba(DDR_ba),
- .DDR_cas_n(DDR_cas_n),
- .DDR_ck_n(DDR_ck_n),
- .DDR_ck_p(DDR_ck_p),
- .DDR_cke(DDR_cke),
- .DDR_cs_n(DDR_cs_n),
- .DDR_dm(DDR_dm),
- .DDR_dq(DDR_dq),
- .DDR_dqs_n(DDR_dqs_n),
- .DDR_dqs_p(DDR_dqs_p),
- .DDR_odt(DDR_odt),
- .DDR_ras_n(DDR_ras_n),
- .DDR_reset_n(DDR_reset_n),
- .DDR_we_n(DDR_we_n),
- .FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn),
- .FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp),
- .FIXED_IO_mio(FIXED_IO_mio),
- .FIXED_IO_ps_clk(FIXED_IO_ps_clk),
- .FIXED_IO_ps_porb(FIXED_IO_ps_porb),
- .FIXED_IO_ps_srstb(FIXED_IO_ps_srstb),
- .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}),
- .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}),
- .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}));
- endmodule
复制代码
以上代码中,原语IOBUF对于很多初学者来说,可能会有疑惑,所以有必要介绍下如何使用。 - IOBUF IOBUF_inst (
- .O(O), // 1-bit output: Buffer output 方向是外部引脚IO 输入到FPGA内部逻辑
- .I(I), // 1-bit input: Buffer input方向是FPGA内部逻辑输出到外部引脚IO
- .IO(IO), // 1-bit inout: Buffer inout (connect directly to top-level port) 外部引脚IO
- .T(T) // 1-bit input: 3-state enable input 定义输入还是输出,当T=0 IO是三态的可以用于输入,当T=1 是输出
- );
复制代码
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平台。
6 搭建Vitis-sdk工程创建soc_base sdk platform和APP工程的过程不再重复,如果不清楚请参考本章节第一个demo。 6.1创建SDK Platform工程
右击soc_base编译,编译的时间可能会有点长 - #include "xparameters.h"
- #include "xgpiops.h"
- #include "xstatus.h"
- #include "xplatform_info.h"
- #include <xil_printf.h>
- #ifndef GPIO_DEVICE_ID
- #define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
- #endif
- #define printf xil_printf /* Smalller foot-print printf */
- XGpioPs Gpio; /* The driver instance for GPIO Device. */
- #define LED0 (50)// 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 (51)// MIO
- int GpioPolledInit(u16 DeviceId);
- int main(void)
- {
- int Status;
- u8 nled =0;
- u32 val_btn0 ;
- u32 val_btn1 ;
- u32 val_btn2 ;
- printf("GPIO Polled Mode Example Test \r\n");
- Status = GpioPolledInit(GPIO_DEVICE_ID);
- if (Status != XST_SUCCESS) {
- printf("GPIO Polled Mode Example Test Failed\r\n");
- return XST_FAILURE;
- }
- while(Status == XST_SUCCESS)
- {
- //驱动LED
- XGpioPs_WritePin(&Gpio, LED0, nled==0);
- XGpioPs_WritePin(&Gpio, LED1, nled==1);
- XGpioPs_WritePin(&Gpio, LED2, nled==2);
- XGpioPs_WritePin(&Gpio, LED3, nled==3);
- XGpioPs_WritePin(&Gpio, LED4, nled==4);
- //读取硬件值
- val_btn0 = XGpioPs_ReadPin(&Gpio, BTN0 );
- val_btn1 = XGpioPs_ReadPin(&Gpio, BTN1 );
- val_btn2 = XGpioPs_ReadPin(&Gpio, BTN2 );
-
- printf("btn0=0x%x btn1=0xx% btn2=0x%x \n\r", val_btn0,val_btn1,val_btn2);
- if(nled == 4)
- nled = 0;
- else
- nled++;
- sleep(1);
- }
- return XST_SUCCESS;
- }
- int GpioPolledInit(u16 DeviceId)
- {
- int Status;
- XGpioPs_Config *ConfigPtr;
- /* Initialize the GPIO driver. */
- ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
- Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);
- //设置LED相关的MIO EMIO为输出方向
- XGpioPs_SetDirectionPin(&Gpio, LED0, 0x1);
- XGpioPs_SetDirectionPin(&Gpio, LED1, 0x1);
- XGpioPs_SetDirectionPin(&Gpio, LED2, 0x1);
- XGpioPs_SetDirectionPin(&Gpio, LED3, 0x1);
- XGpioPs_SetDirectionPin(&Gpio, LED4, 0x1);
- //设置按键相关的IO为输入方向
- XGpioPs_SetDirectionPin(&Gpio,BTN0, 0x0);
- XGpioPs_SetDirectionPin(&Gpio,BTN1, 0x0);
- XGpioPs_SetDirectionPin(&Gpio,BTN2, 0x0);
- //设置LED的输出使能
- XGpioPs_SetOutputEnablePin(&Gpio, LED0, 1);
- XGpioPs_SetOutputEnablePin(&Gpio, LED1, 1);
- XGpioPs_SetOutputEnablePin(&Gpio, LED2, 1);
- XGpioPs_SetOutputEnablePin(&Gpio, LED3, 1);
- XGpioPs_SetOutputEnablePin(&Gpio, LED4, 1);
- //设置LED默认的输出为1
- XGpioPs_WritePin(&Gpio, LED0, 1);
- XGpioPs_WritePin(&Gpio, LED1, 1);
- XGpioPs_WritePin(&Gpio, LED2, 1);
- XGpioPs_WritePin(&Gpio, LED3, 1);
- XGpioPs_WritePin(&Gpio, LED4, 1);
- return Status;
- }
复制代码
接下来对程序进行分析。 7.1结构体static XGpioPs Gpio含义:这是一个指针实例,指向添加的GPIO端口。 具体分析: XGpiops:绿色标识的一个结构体。Vitis IDE中结构体都用绿色标识。 将鼠标停留在XGpiops上或右键Open Declaration,查看这个结构体所包含的内容。
结构体包含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,查看这个结构体所包含的内容。
此结构体存放的是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的参数信息,右击可以查看具体信息
继续右击以下GPIO地址定义,可以查到GPIO外设的基地址:
7.5 XGpioPs_CfgInitialize(InstancePtr, ConfigPtr, ConfigPtr->BaseAddr)函数
以上代码中首先根据硬件平台如果是ZYNQ SOC那么IO BANK最多4个 IO数量最多118个,如果是ZYNQ MPSOC平台,那么IO BANK最多是6个,IO数量最多174个。 7.6 XGpioPs_SetDirectionPin(InstancePtr, LED0,1)函数设置IO方向,最后一个参数0代表输入,1代表输出。
以上代码首先需计算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)函数
以上代码首先需计算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查看下其功能。
上述部分为程序查找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号和写入的数据。定义如下:
这里仅以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函数的接下来的这段程序:
这段程序完成向指定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)
8.2实验结果IO输出功能,可看到底板上的流水灯运行 IO输入功能,可以通过串口打印读到的按键输入,默认按键都是上拉的高电平。
|