基于pynq开发板的软硬件设计

本文详细介绍了基于PYNQ开发板的嵌入式系统设计,包括使用Python进行软硬件开发,FPGA上的SOC开发流程,高层次综合的硬件设计,以及如何利用HLS进行卷积神经网络的软硬件映射。涵盖了AXI总线应用,DMA设计,矩阵运算,池化和卷积单元的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

**

日程安排

**
第一天:基于PYNQ开发板的SOC软件开发
第二天:基于FPGA的SOC软硬件开发流程(一)
第三天:基于FPGA的SOC软硬件开发流程(二)
第四天:基于高层次综合的硬件设计(一)
第五天:基于高层次综合的硬件设计(二)
第六天:基于HLS的卷积神经网络软硬件映射

第一天:基于PYNQ开发板的SOC软件开发

  1. 什么是PYNQ

PYNQ is an open-source project from Xilinx® that makes it easy to design embedded systems with Xilinx Zynq® Systems on Chips (SoCs).

Using the Python language and libraries, designers can exploit the benefits of programmable logic and microprocessors in Zynq to build more capable and exciting embedded systems.
2.结构
在这里插入图片描述
3.baseoverlay
PS和PL模块接口单元设计
在这里插入图片描述
可将设计好的ip核利用vivado生曾bit流,导入到板子中。就可利用此ip核再PL模块中生成所要的模块电路。
具体下载到板子运行方式:
在这里插入图片描述
4.pynq板子的配置过程
1)准备
在这里插入图片描述
2).烧写镜像文件
在这里插入图片描述
3)同一网段的设置,资源管理器设置,jupyter notebook环境的搭建

pynq板子基本功能实现

1.GPIO的基本实现
在这里插入图片描述

from pynq.overlays.base import BaseOverlay
base = BaseOverlay("base.bit") 
base.download()
led = base.leds
sw = base.switchs
buttons =base.buttons
led.write(val,mask)
sw.read()
buttons.read()

说明:将之前的嵌入式linux镜像烧入到pynq中,然后将生成的基本ip核烧入,并配置成FPGA的相关 电路(PL部分)。然后取利用各部分小的ip电路,如led灯模块,开关,按键,通过控制其状态,进一步通过外设与之相连,就可控制外设了。
2.音频模块的实现
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
说明:在jupyter notebook的环境下实现音频模块的采集录制,以及对其进行时域与频谱分析。
3.控制摄像头
在这里插入图片描述
在这里插入图片描述
4.人脸识别以及通过HDMI输出到显示屏控制。
在这里插入图片描述
在这里插入图片描述
5.协处理器
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

第二天:基于FPGA的SOC软硬件开发流程(一)

1.AXI4总线:lite:利用该总线实现对led灯的控制。
在这里插入图片描述
在这里插入图片描述
说明:上面的masterinterface是站在ARM角度,slaveinterface是站在ip核角度。AR channel表示在该总线下ARM对ip进行都地址操作(ARM传地址给IP),Rd channel表示将该地址下的数据从IP核返回给ARM。AW channel表示ARM对ip核进行写地址操作,Wr channel表示ARM对ip核进行写数据操作。Wr resp表示完成写数据写操作后,ip核对ARM的响应(可忽略)。(上面所描述的也是这种握手型)。
代码:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2019/08/08 17:16:14
// Design Name: 
// Module Name: a31
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


`timescale 1ns / 1ps

module axi_gpio_my
(
    input S_AXI_ACLK,
    input S_AXI_ARESETN,
    
    inout [3:0]gpio,
    
    //AR channel
    input S_AXI_ARVALID,
    output S_AXI_ARREADY,
    input [4-1:0]S_AXI_ARADDR,
    input [2:0]S_AXI_ARPROT,

    //Rd channel
    output [32-1:0]S_AXI_RDATA,
    output [1:0]S_AXI_RRESP,
    output S_AXI_RVALID,
    input S_AXI_RREADY,

    //AW channel
    input S_AXI_AWVALID,
    output S_AXI_AWREADY,
    input [4-1:0]S_AXI_AWADDR,
    input [2:0]S_AXI_AWPROT,

    //Wr channel
    input [32-1:0]S_AXI_WDATA,
    input S_AXI_WVALID,
    output S_AXI_WREADY,
    input [4-1:0]S_AXI_WSTRB,//4'b1111. 4'b0011   

    //Wr Resp
    output [1:0]S_AXI_BRESP,
    output S_AXI_BVALID,
    input S_AXI_BREADY
);

assign S_AXI_BRESP=2'b0;
reg axi_bvalid;
assign S_AXI_BVALID=axi_bvalid;
always @(posedge S_AXI_ACLK or negedge S_AXI_ARESETN)
if(~S_AXI_ARESETN)
    axi_bvalid<=1'b0;
else
    if(S_AXI_WVALID&S_AXI_WREADY)
        axi_bvalid<=1'b1;
    else
        if(S_AXI_BREADY)
            axi_bvalid<=1'b0;

reg [1:0]addr_word_w;
wire [1:0]addr_word_w_comb;
always @(posedge S_AXI_ACLK or negedge S_AXI_ARESETN)
if(~S_AXI_ARESETN)
    addr_word_w<=0;
else
    if(S_AXI_AWVALID&S_AXI_AWREADY)
        addr_word_w<=S_AXI_AWADDR[3:2];
        
assign addr_word_w_comb=(S_AXI_AWVALID&S_AXI_AWREADY)?S_AXI_AWADDR[3:2]:addr_word_w;
assign S_AXI_AWREADY=1'b1;

reg [3:0]reg0;
reg [3:0]reg1;
wire [3:0]reg2;

reg wphase;
always @(posedge S_AXI_ACLK or negedge S_AXI_ARESETN)
if(~S_AXI_ARESETN)
    wphase<=0;
else
    if(S_AXI_AWVALID&S_AXI_AWREADY)
        wphase<=1;
    else
        if(S_AXI_WVALID&S_AXI_WREADY)
            wphase<=0;

assign S_AXI_WREADY=wphase;
always @(posedge S_AXI_ACLK or negedge S_AXI_ARESETN)
if(~S_AXI_ARESETN)
begin
    reg0<=0;
    reg1<=0;
end
else
    if(S_AXI_WVALID&S_AXI_WREADY)
    case(addr_word_w_comb)
        2'd0:begin if(S_AXI_WSTRB[0]) reg0<=S_AXI_WDATA[3:0];end
        2'd1:begin if(S_AXI_WSTRB[0]) reg1<=S_AXI_WDATA[3:0];end
    endcase
    
//reg [1:0]addr_word_r;
//wire [1:0]addr_word_r_comb;
//always @(posedge S_AXI_ACLK or negedge S_AXI_ARESETN)
//if(~S_AXI_ARESETN)
//    addr_word_r<=0;
//else
//    if(S_AXI_ARVALID&S_AXI_ARREADY)
//        addr_word_r<=S_AXI_ARADDR[3:2];

//assign addr_word_r_comb=(S_AXI_ARVALID&S_AXI_ARREADY)?S_AXI_ARADDR[3:1]:addr_word_r;
assign S_AXI_ARREADY=1'b1;

assign S_AXI_RRESP=2'b0;
reg [32-1:0]rdata;
assign S_AXI_RDATA=rdata;
reg rvalid;
assign S_AXI_RVALID=rvalid;

always @(posedge S_AXI_ACLK or negedge S_AXI_ARESETN)
if(~S_AXI_ARESETN)
    begin rvalid<=1'b0;rdata<=32'b0;end
else
    if(S_AXI_ARVALID&S_AXI_ARREADY)
    begin
        rvalid<=1'b1;
        case(S_AXI_ARADDR[3:2])
            2'd0:rdata<={28'b0,reg0};
            2'd1:rdata<={28'b0,reg1};
            2'd2:rdata<={28'b0,reg2};
            2'd3:rdata<=0;
        endcase
    end
    else
        if(S_AXI_RVALID&S_AXI_RREADY)
            rvalid<=1'b0;

assign gpio[3]=reg1[3]?reg0[3]:1'bz;
assign gpio[2]=reg1[2]?reg0[2]:1'bz;
assign gpio[1]=reg1[1]?reg0[1]:1'bz;
assign gpio[0]=reg1[0]?reg0[0]:1'bz;

assign reg2=gpio;
//assign reg2[2]=gpio[2];

//IOBUF IOBUF_1
//(
//    .I(reg0[1]),
//    .T(~reg1[1]),
//    .O(reg2[1]),
//    .IO(gpio[1])
//);

//IOBUF IOBUF_0
//(
//    .I(reg0[0]),
//    .T(~reg1[0]),
//    .O(reg2[0]),
//    .IO(gpio[0])
//);

endmodule

代码解析:实现了利用AXI lite总线,ARM对led灯的控制。reg1中存放的是有关GPIO是输出还是输入的方向寄存器控制。如果是输出方向的则置1,输入状态就变为高阻态。然后寄存器0表示的是利用输出的GPIO控制灯亮灭的寄存器,1表示亮,0表示灭。寄存器2记录这四个GPIO的状态。地址0,4,8分别表示寄存器0,1,2。ARM上地址是以四为单位变化。握手时只有valid和ready信号都为高时,才有效。只有在读或写完地址之后,才能进行读写数据。然后将上述设计电路打包封装成IP核。

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

约束条件。
block设计
在这里插入图片描述
为了对该ip核进行控制,需要将生成的IP核与zynq主控连起来,然后外加ILA产看波形。最后进行综合,布线生成Bit,hwh文件导入板子中。就可以在jupter notebook中完成并控制了。
在这里插入图片描述
2.利用AXI4 lite实现串口的ip核设计与控制
在这里插入图片描述
利用ARM对串口(设计的IP核)进行读写数据时,由于串口收发数据速度,以及读写串口的速度存在很大差异。因此外加缓冲队列来减小差异,减小读写出错的问题。
代码:
串口收发实现的总模块(ip核设计的):

`timescale 1ns / 1ps

module uart_my
(
    input S_AXI_ACLK,
    input S_AXI_ARESETN,
    
    input RXD,
    output TXD,
    
    //AR channel
    input S_AXI_ARVALID,
    output S_AXI_ARREADY,
    input [3-1:0]S_AXI_ARADDR,
    input [2:0]S_AXI_ARPROT,

    //Rd channel
    output [32-1:0]S_AXI_RDATA,
    output [1:0]S_AXI_RRESP,
    output S_AXI_RVALID,
    input S_AXI_RREADY,

    //AW channel
    input S_AXI_AWVALID,
    output S_AXI_AWREADY,
    input [3-1:0]S_AXI_AWADDR,
    input [2:0]S_AXI_AWPROT,

    //Wr channel
    input [32-1:0]S_AXI_WDATA,
    input S_AXI_WVALID,
    output S_AXI_WREADY,
    input [4-1:0]S_AXI_WSTRB,   

    //Wr Resp
    output [1:0]S_AXI_BRESP,
    output S_AXI_BVALID,
    input S_AXI_BREADY
);

assign S_AXI_BRESP=2'b0;
reg axi_bvalid;
assign S_AXI_BVALID=axi_bvalid;
always @(posedge S_AXI_ACLK or negedge S_AXI_ARESETN)
if(~S_AXI_ARESETN)
    axi_bvalid<=1'b0;
else
    if(S_AXI_WVALID&S_AXI_WREADY)
        axi_bvalid<=1'b1;
    else
        if(S_AXI_BREADY)
            axi_bvalid<=1'b0;

assign S_AXI_ARREADY=1'b1;
assign S_AXI_AWREADY=1'b1;

wire u_tx_fifo_dout_vld;
wire u_tx_fifo_dout_rdy;
wire [7:0]u_tx_fifo_dout;

reg w_phase;
always @(posedge S_AXI_ACLK or negedge S_AXI_ARESETN)
if(~S_AXI_ARESETN)
    w_phase<=1'b0;
else
    if(S_AXI_AWVALID & S_AXI_AWREADY)
        w_phase<=1'b1;
    else
        if(S_AXI_WVALID & S_AXI_WREADY)
            w_phase<=1'b0;

wire u_tx_fifo_vld;
wire u_tx_fifo_rdy;
assign u_tx_fifo_vld=S_AXI_WVALID&w_phase;
assign S_AXI_WREADY=u_tx_fifo_rdy&w_phase;

hs_fifo_64_8 u_tx_fifo
(
    .clk(S_AXI_ACLK),
    .rst_n(S_AXI_ARESETN),
    
    .din_vld(u_tx_fifo_vld),
    .din_rdy(u_tx_fifo_rdy),
    .din(S_AXI_WDATA[7:0]),
    
    .dout_vld(u_tx_fifo_dout_vld),
    .dout_rdy(u_tx_fifo_dout_rdy),
    .dout(u_tx_fifo_dout)
);

uart_send u_uart_send
(
    .clk(S_AXI_ACLK),      //100 MHz
    .rst_n(S_AXI_ARESETN),
    
    .dat_vld(u_tx_fifo_dout_vld),
    .dat_rdy(u_tx_fifo_dout_rdy),
    .dat(u_tx_fifo_dout),
    
    .TXD(TXD)
);

wire u_uart_recv_dout_vld;
wire [7:0]u_uart_recv_dout;
uart_recv u_uart_recv
(
    .clk(S_AXI_ACLK),      //100MHz
    .rst_n(S_AXI_ARESETN),
    
    .RXD(RXD),
    
    .dat_vld(u_uart_recv_dout_vld),
    .dat(u_uart_recv_dout)
);

reg flag;
always @(posedge S_AXI_ACLK or negedge S_AXI_ARESETN)
if(~S_AXI_ARESETN)
    flag<=1'b0;
else
    if(S_AXI_ARVALID & S_AXI_ARREADY)
        flag<=1'b1;
    else
        if(S_AXI_RVALID & S_AXI_RREADY)
            flag<=1'b0;

wire u_rx_fifo_dout_vld;//S_AXI_RVALID
wire u_rx_fifo_dout_rdy;//S_AXI_RREADY
assign S_AXI_RVALID = u_rx_fifo_dout_vld&flag;
assign u_rx_fifo_dout_rdy = S_AXI_RREADY&flag;

hs_fifo_64_8 u_rx_fifo
(
    .clk(S_AXI_ACLK),
    .rst_n(S_AXI_ARESETN),
    
    .din_vld(u_uart_recv_dout_vld),
    .din_rdy(),
    .din(u_uart_recv_dout),
    
//    .din_vld(u_tx_fifo_dout_vld),
//    .din_rdy(u_tx_fifo_dout_rdy),
//    .din(u_tx_fifo_dout),
    
    .dout_vld(u_rx_fifo_dout_vld),
    .dout_rdy(u_rx_fifo_dout_rdy),
    .dout(S_AXI_RDATA[7:0])
);

assign S_AXI_RRESP=2'b0;
assign S_AXI_RDATA[31:8]=0;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值