PYNQ(zynq) PS端+PL端gpio使用 实现软件驱动按键点led灯

平台:pynq z2

发现没有针对PYNQ的,或者过程并不适合,开个头。

实现功能

PS端和PL端是通过AXI总线通信。
调用gpio核,实现由arm读取按键的输入,再将按键值送到led
PYNQ(zynq) PS端+PL端gpio使用 实现软件驱动按键点led灯_第1张图片

总体思路

分为几步

(一) 硬件vivado

思路就是,把arm和fpga的接口通过gpio连起来,形成硬件结构。

step 1:block design调用zynq核
step 2:这里用两个gpio核,分别作为button和led输入输出,设置位宽4
step 3:检查一下地址映射,保证调用软件可以找到gpio的reg
step 4:自动连接,wrap HDL生成顶层的verilog,output hardware product
step 5:xdc约束管脚
step 6:export hardware,并且打开sdk,不用包含bitstream ,到时候再烧进去
step 7:让硬先件生成着bitstream,同步进行sdk设计

(二) 软件sdk

思路就是,根据gpio手册,用arm寻址,写数据

step 1 :新建project
step 2 :找到gpio 三态门的tri地址,设置两个gpio的输入、输出,
step 3 :找到gpio数据的地址,设置输入输出数值
step 4 :烧写bitstream,亮灯。

over.

具体实现

(1)硬件

step 1:block design调用zynq核

方便起见,不用裁剪,出来啥用啥。

step 2:两个gpio核

分别作为button和led输入输出,设置位宽4,
ps一共32bit,只用了4个

这里有个坑,默认的tri state value没法修改,输入输出都是0xffff_ffff,是不对的。所以在软件中需要修改

PYNQ(zynq) PS端+PL端gpio使用 实现软件驱动按键点led灯_第2张图片
PYNQ(zynq) PS端+PL端gpio使用 实现软件驱动按键点led灯_第3张图片
自动连线后,增加了axi-interconnect 和100Mclk\rst系统
PYNQ(zynq) PS端+PL端gpio使用 实现软件驱动按键点led灯_第4张图片

step 3:检查一下地址映射

看一眼地址 ,保证调用软件可以找到gpio的reg

PYNQ(zynq) PS端+PL端gpio使用 实现软件驱动按键点led灯_第5张图片

step 4:自动连接,wrap HDL生成顶层的verilog,output hardware product

step 5:xdc约束管脚

只用button led,注意名字用顶层verilog中的输入输出

 ##LEDs

set_property -dict { PACKAGE_PIN R14   IOSTANDARD LVCMOS33 } [get_ports { led_tri_o[0] }]; #IO_L6N_T0_VREF_34 Sch=led[0]
set_property -dict { PACKAGE_PIN P14   IOSTANDARD LVCMOS33 } [get_ports { led_tri_o[1] }]; #IO_L6P_T0_34 Sch=led[1]
set_property -dict { PACKAGE_PIN N16   IOSTANDARD LVCMOS33 } [get_ports { led_tri_o[2] }]; #IO_L21N_T3_DQS_AD14N_35 Sch=led[2]
set_property -dict { PACKAGE_PIN M14   IOSTANDARD LVCMOS33 } [get_ports { led_tri_o[3] }]; #IO_L23P_T3_35 Sch=led[3]

##Buttons

set_property -dict { PACKAGE_PIN D19   IOSTANDARD LVCMOS33 } [get_ports { sw_tri_i[0] }]; #IO_L4P_T0_35 Sch=btn[0]
set_property -dict { PACKAGE_PIN D20   IOSTANDARD LVCMOS33 } [get_ports { sw_tri_i[1] }]; #IO_L4N_T0_35 Sch=btn[1]
set_property -dict { PACKAGE_PIN L20   IOSTANDARD LVCMOS33 } [get_ports { sw_tri_i[2] }]; #IO_L9N_T1_DQS_AD3N_35 Sch=btn[2]
set_property -dict { PACKAGE_PIN L19   IOSTANDARD LVCMOS33 } [get_ports { sw_tri_i[3] }]; #IO_L9P_T1_DQS_AD3P_35 Sch=btn[3]


step 6:export hardware,并且打开sdk

不用包含bitstream ,到时候再烧进去

step7 :让硬先件生成着bitstream

同步进行sdk设计

(2)软件

思路就是,根据gpio手册,用arm寻址,写数据

看一下gpio规则

没用到中断,gpio都是一个channel,不存在gpiox_的x

读写都是两步走

  • 设置gpio_tri
  • 设置gpio_data
    PYNQ(zynq) PS端+PL端gpio使用 实现软件驱动按键点led灯_第6张图片

寄存器的位置

上面已知硬件的基地址, 目标就是找需要的寄存器偏移
PYNQ(zynq) PS端+PL端gpio使用 实现软件驱动按键点led灯_第7张图片

以上, 手册用完。

编程

step 1 :新建project

可以建pheriperial test或者helloword 用一下他的头文件。
官方api 其实用了很多宏定义,可以参考
https://blog.csdn.net/tangkunjyy/article/details/62038253?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

官方为了规范,比较啰嗦,层层套娃,做的无非就是以下两步。

step 2 :找到gpio 三态门的tri地址,设置两个gpio的输入、输出,

根据手册,channel1 ,需要偏移4,base_addr+b’100

#define tri_in *(volatile u32 *) 0x41210100
#define tri_out *(volatile u32 *) 0x41200100

step 3 :找到gpio数据的地址,设置输入输出数值

根据手册,就是基地址

#define sw_in *(volatile u32 *) 0x41210000
#define led_out *(volatile u32 *) 0x41200000

main.c

#include 
#include "xparameters.h"
#include "xgpio.h"


#define tri_in  *(volatile u32 *) 0x41210100
#define tri_out *(volatile u32 *) 0x41200100
#define sw_in *(volatile u32 *)   0x41210000
#define led_out *(volatile u32 *) 0x41200000

int main () 
{
	tri_in=0xffffffff;
	tri_out=0x0;
	while(1)
	{
		led_out=sw_in;
	}

   return 0;
}

step 4 :烧写bitstream,亮灯。

成功!

使用一个GPIO

用两个channel,测试了发现直接赋值法在按键按下的时候,跟官方api函数读出来的不一致,就是读的时候有问题。
而且使用官方api在按下的瞬间由于抖动,也会不一致。

留个坑吧,以后研究

使用官方api实现单gpio核双通道读写

#include 
#include "platform.h"
#include "xil_printf.h"
#include "xgpio.h"       /* GPIO data struct and APIs */
#include "xstatus.h"
#include "xparameters.h" /* Peripheral parameters  */
#include "sleep.h"
#define tri_in  *(volatile u32 *) 0x41201100
#define tri_out *(volatile u32 *) 0x41200100
#define sw_in   *(volatile u32 *) 0x41201000
#define led_out *(volatile u32 *) 0x41200000
#define GPIO_BITWIDTH   4   /* This is the width of the GPIO */
#define GPIO_DEVICE_ID  XPAR_AXI_GPIO_0_DEVICE_ID //device id

#define LED_CHANNEL 1        /* GPIO channel*/
#define SW_CHANNEL 2        /* GPIO channel*/
#define printf xil_printf   /* A smaller footprint printf */


XGpio GpioOutput; /* The driver instance for GPIO Device configured as O/P */
XGpio GpioInput; /* The driver instance for GPIO Device configured as I/P */

int main(void)
{//Application start
    /* loop forever*/
	tri_in=0xffffffff;
	tri_out=0x0;
    print("Hello World\n\r");
    while(1){

    u32 Rdata;
    u32 data1;
    //read channel
    XGpio_Initialize(&GpioInput, GPIO_DEVICE_ID);
    XGpio_SetDataDirection(&GpioInput, SW_CHANNEL, 0xffffffff);
    Rdata=XGpio_DiscreteRead(&GpioInput, SW_CHANNEL);

    //out channel
    XGpio_Initialize(&GpioOutput, GPIO_DEVICE_ID);
    XGpio_SetDataDirection(&GpioOutput, LED_CHANNEL, 0x0);
    XGpio_DiscreteWrite(&GpioOutput, LED_CHANNEL, Rdata);
   /*    equal to 
    led_out=Rdata;*/

    //**********test read  
    // cant equal??
    data1=sw_in;
    if (data1 == Rdata)
    {
    	print("SUCESS!.\r\n");
        Rdata=data1;
        print("change!.\r\n");
    }
    else print("FAILED!!!!!!!!!!!!!!!!!!!!!.\r\n");




    



    }
    return XST_SUCCESS;
}

plus AXI知识

大致了解,可以不看。
AXI4:(For high-performance memory-mapped requirements)主要面向高性能地址映射通信的需求,是面向地址映射的接口,允许最大256轮的数据突发传输。
AXI4-Lite:(For simple, low-throughput memory-mapped communication)是一个轻量级的地址映射单次传输接口, 占用很少的逻辑单元。
AXI4-Stream:(For high-speed streaming data)面向高速流数据传输,去掉了地址项,允许无限制的数据突发传输。

数据在总线上是遵守协议定的规则来传输的,AXI信号传输先是传地址,然后检测READY+VALID,都为高电平时开始传数据,当主机发送最后一个数据时LAST信号拉高,通知从机传输结束。

握手协议:

READY,VALID握手通信机制,主机产生 VLAID 信号来指明何时数据或控制信息有效。从机产生 READY 信号来指明已经准备好接受数据或控制信息。传输发生在 VALID和 READY 信号同时为高的时候。(还有一个LAST信号表示什么时候传到最后一个数据了)

读时序:地址线上发来地址,地址准备和地址有效都高时,开始发送要读的数据,读准备和读有效都高时数据被读取到,发最后一个数据时读LAST信号拉高。

PYNQ(zynq) PS端+PL端gpio使用 实现软件驱动按键点led灯_第8张图片

写时序:地址线上发来地址,地址准备和地址有效都高时,开始发送要写的数据,写准备和写有效都高时数据写入,发最后一个数据时写LAST信号拉高。写数据多了一个反馈信号,反馈给主机,主机接收到这个信号,就知道写成功了。

PYNQ(zynq) PS端+PL端gpio使用 实现软件驱动按键点led灯_第9张图片
PYNQ(zynq) PS端+PL端gpio使用 实现软件驱动按键点led灯_第10张图片
AXI GPIO软核,在PL端实现,S_AXI端连接在AXI总线上与PS端处理器进行通信,GPIO端连接实际引脚(可任意分配),驱动板载外设。

  • 每个通道可设置32个I/O
  • 每个I/O可设置为输入或输出
  • 可配置支持双通道和外部中断

点击右侧Address Editor即可看到硬件相关信息,在PL端实现的axi_gpio_0 IP核中所包含的寄存器首地址和结束地址,这个信息待会就要导出到硬件设计文件中,通过软件操作相关寄存器。

接下来导出整个设计的硬件设计文件(hdf)供SDK进行软件设计使用,因为设计中包含PL端设计,生成比特流文件,用来配置PL端的设计(AXI GPIO 软ip核)

ref
https://blog.csdn.net/Mculover666/article/details/83051767

你可能感兴趣的:(PYNQ)