Vivado Vitis协同开发一般流程:

image-20230708091436431

领航者B站教程:https://www.bilibili.com/video/BV1Hq4y1u7qH/?vd_source=1f2a3d74b293649da6aeac79edac185b
B站老哥的笔记:https://space.bilibili.com/94007900/article
ALINX教程博客:https://zhuanlan.zhihu.com/p/339433531
ALINXB站视频:https://space.bilibili.com/473639301/channel/collectiondetail?sid=567806

点亮LED灯

创建硬件平台

这里不使用PS的IO外设MIO、EMIO点灯,而是使用PL的资源。在ZYNQ中配置PS-PL configuration,配置上PS-PL Interfaces—Master Interface—AXI HPM0 LPD(用于PS向PL传数据),以及General—Interrupts—PL to PS—IRQ0(PL的按键中断)。

2023-07-08 11-18-22 的屏幕截图

添加两个AXI GPIO,一个用于输出led灯信号,一个用于输入按键中断信号。

2023-07-08 11-18-56 的屏幕截图 2023-07-08 11-19-10 的屏幕截图

各模块连接完成后,Validate Design—右击.bd文件—Create HDL Wrapper—Generate Output Products。之后打开RTL,绑定输入输出的管脚,这里我们定义了一个按键输入,一个led灯输出。

2023-07-08 11-20-58 的屏幕截图

可以通过开发板白皮书查询用户IO的名称:

image-20230708101001932

以及对应的关键Pin,和电压:

image-20230708153612451

方式1:PS 通过AXI GPIO点亮PL端LED灯

这部分主要是想了解PS和PL的交互,从网上大概找了一些教程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include "xparameters.h"
#include "xgpio.h"
#include "xil_printf.h"
/************************** Constant Definitions *****************************/
#define LED 0x01 /* Assumes bit 0 of GPIO is connected to an LED */
#define GPIO_EXAMPLE_DEVICE_ID XPAR_GPIO_0_DEVICE_ID
#define LED_DELAY 10000000
#define LED_CHANNEL 1
XGpio Gpio; /* The Instance of the GPIO Driver */

int main(void)
{
int Status;
volatile int Delay;
Status = XGpio_Initialize(&Gpio, GPIO_EXAMPLE_DEVICE_ID);//初始化驱动器
if (Status != XST_SUCCESS) {
xil_printf("Gpio Initialization Failed\r\n");
return XST_FAILURE;
}
XGpio_SetDataDirection(&Gpio, LED_CHANNEL, ~LED);//将驱动器上,指定通道,设置为输出方向,写 XGPIO_TRI_OFFSET
while (1) {
XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, LED);//信号变为高电平,LED灯点亮,写 XGPIO_DATA_OFFSET
for (Delay = 0; Delay < LED_DELAY; Delay++);
XGpio_DiscreteClear(&Gpio, LED_CHANNEL, LED);//信号变为低电平。LED灯熄灭
for (Delay = 0; Delay < LED_DELAY; Delay++);
}
}

上述函数都是在操作GPIO的寄存器,如果觉得Xilinx提供的API函数比较繁琐,效率低,也可以采取直接操作寄存器的方式控制LED。

方式2:直接操作寄存器方式实现点灯

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#define GPIO_BASEDDR 0x80000000 //GPIO基地址
#define DATA_OFFSET 0x0 // 数据偏移地址
#define TRI_OFFSET 0x4 // 方向偏移地址
#define LED_DELAY 10000000
int main()
{
volatile int Delay;
*(int *)(GPIO_BASEDDR+TRI_OFFSET)=0x0;//设置方向为输出
while(1){
*(int*)(GPIO_BASEDDR+DATA_OFFSET)=0x1;
for(Delay=0;Delay<LED_DELAY;Delay++);
*(int*)(GPIO_BASEDDR+DATA_OFFSET)=0x0;
for(Delay=0;Delay<LED_DELAY;Delay++);
}
return 0;
}

image-20230708164025701

2023-07-08 17-07-20 的屏幕截图

AXI GPIO之PL端按键中断

参考:https://zhuanlan.zhihu.com/p/345852999

PS内部可以实现中断,PS也可以接收来自PL的中断,PS最大可以接收16个来自PL的中断信号,都是上升沿或高电平触发。PL端可以给PS发送中断信号,这提高了PL和PS数据交互的效率,在需要大数量、低延时的应用中需要用到中断处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main(void)
{
int Status;
u32 DataRead;
print(" Press button to Generate Interrupt\r\n");
Status = GpioIntrExample(&Intc, &Gpio,GPIO_DEVICE_ID,
INTC_GPIO_INTERRUPT_ID, GPIO_CHANNEL1, &DataRead);
if (Status == 0 ){
if(DataRead == 0)
print("No button pressed. \r\n");
else
print("Successfully ran Gpio Interrupt Tapp Example\r\n");
} else {
print("Gpio Interrupt Tapp Example Failed.\r\n");
return XST_FAILURE;
}
return XST_SUCCESS;
}

image-20230709155747248

main函数主要通过GpioIntrExample函数组成,这个函数会返回DataRead标志,DataRead用来检测中断是否发生。在GpioIntrExample函数中主要有三个子函数调用,其中GpioSetupIntrSystem设置终端系统,里边将中断事件和具体的处理函数关联了(中断处理函数使得发生中断时DataRead结果为1)。其中中断处理函数GpioHandler调用了XGpio_InterruptClear(GpioPtr, GlobalIntrMask)来清理ISR中断状态寄存器,表示中断以处理完。GpioDisableIntr(IntcInstancePtr, InstancePtr, IntrId, IntrMask);函数写中断IER使能寄存器,将Gpio中断源屏蔽。