基于PYNQ的AD采集系统

  • 系统概述
  • AN706的控制
  • SPI通讯
  • AXI4-LITE总线
  • 打包IP核
  • 建立PYNQ工程
  • 编写SDK程序
  • 上板验证
  • 代码下载地址

系统概述

打算用PYNQ-Z2开发板做MMC变化器的控制,遇到的第一个问题就是做MMC控制需要采集大量的电容电压、电流信号。但是考虑到XILINX官方的PYNQ-Z2开发板管脚很少,所以使用另一块XLINX的FPGA(SPANTAN-6)接两片黑金的AN706AD进行数据采集,通过SPI协议把采集到的数据从SPI从机传输到位于PYNQ开发板上的SPI主机上。最后通过AXI4-Lite总线传输到ARM核上。系统的总图如下:

AN706的控制

关于AN706AD的控制,这里直接使用黑金官方的例程就可以了,就是注意去理解其时序,如下图所示:

直接上代码:

module ad7606(input          clk,input          rst_n,input [15:0]   ad_data,    input          ad_busy,    input          first_datoutput [2:0]   ad_os,      output reg     ad_cs,      output reg     ad_rd,      output reg     ad_reset,   output reg     ad_convstab,output reg [15:0] ad_ch1,output reg [15:0] ad_ch2,output reg [15:0] ad_ch3,output reg [15:0] ad_ch4,output reg [15:0] ad_ch5,output reg [15:0] ad_ch6,output reg [15:0] ad_ch7,output reg [15:0] ad_ch8,output reg ad_finish);
reg [15:0]  cnt;
reg [5:0] i;
reg [3:0] state;           parameter IDLE=4'd0;
parameter AD_CONV=4'd1;
parameter Wait_1=4'd2;
parameter Wait_busy=4'd3;
parameter READ_CH1=4'd4;
parameter READ_CH2=4'd5;
parameter READ_CH3=4'd6;
parameter READ_CH4=4'd7;
parameter READ_CH5=4'd8;
parameter READ_CH6=4'd9;
parameter READ_CH7=4'd10;
parameter READ_CH8=4'd11;
parameter READ_DONE=4'd12; assign ad_os=3'b000;
always@(posedge clk)      begin                    if(cnt<16'hffff) begincnt<=cnt+1;       ad_reset<=1'b1;   end                 else                ad_reset<=1'b0;   end
always @(posedge clk)                       begin                                      if (ad_reset==1'b1) begin                 state<=IDLE;                            ad_ch1<=0;                              ad_ch2<=0;                              ad_ch3<=0;                              ad_ch4<=0;                              ad_ch5<=0;                              ad_ch6<=0;                              ad_ch7<=0;                              ad_ch8<=0;                              ad_cs<=1'b1;                            ad_rd<=1'b1;                            ad_convstab<=1'b1;                      i<=0;                                   ad_finish<=1'b0;                        end                                       else begin                                case(state)                             IDLE: begin                             ad_cs<=1'b1;                           ad_rd<=1'b1;                           ad_convstab<=1'b1;                     if(i==20) begin                        i<=0;                                 state<=AD_CONV;                       end                                    else                                   i<=i+1'b1;                            end                                     AD_CONV: begin                          if(i==2) begin                       i<=0;                                 state<=Wait_1;                        ad_convstab<=1'b1;                    ad_finish<=1'b0;                      end                                    else begin                             i<=i+1'b1;                            ad_convstab<=1'b0;                    end                                    end                                     Wait_1: begin                           if(i==5) begin                         i<=0;                                 state<=Wait_busy;                     end                                    else                                   i<=i+1'b1;                            end                                     Wait_busy: begin                        if(ad_busy==1'b0) begin                i<=0;                                 state<=READ_CH1;                      end                                    end                                     READ_CH1: begin                         ad_cs<=1'b0;                           if(i==3) begin                         ad_rd<=1'b1;                          i<=0;                                 ad_ch1<=ad_data;                      state<=READ_CH2;                      end                                    else begin                             ad_rd<=1'b0;                          i<=i+1'b1;                            end                                    end                                     READ_CH2: begin                         if(i==3) begin                         ad_rd<=1'b1;                          i<=0;                                 ad_ch2<=ad_data;                      state<=READ_CH3;                      end                                    else begin                             ad_rd<=1'b0;                          i<=i+1'b1;                            end                                    end                                     READ_CH3: begin                         if(i==3) begin                         ad_rd<=1'b1;                          i<=0;                                 ad_ch3<=ad_data;                      state<=READ_CH4;                      end                                    else begin                             ad_rd<=1'b0;                          i<=i+1'b1;                            end                                    end                                     READ_CH4: begin                         if(i==3) begin                         ad_rd<=1'b1;                          i<=0;                                 ad_ch4<=ad_data;                      state<=READ_CH5;                      end                                    else begin                             ad_rd<=1'b0;                          i<=i+1'b1;                            end                                    end                                     READ_CH5: begin                         if(i==3) begin                         ad_rd<=1'b1;                          i<=0;                                 ad_ch5<=ad_data;                      state<=READ_CH6;                      end                                    else begin                             ad_rd<=1'b0;                          i<=i+1'b1;                            end                                    end                                     READ_CH6: begin                         if(i==3) begin                         ad_rd<=1'b1;                          i<=0;                                 ad_ch6<=ad_data;                      state<=READ_CH7;                      end                                    else begin                             ad_rd<=1'b0;                          i<=i+1'b1;                            end                                    end                                     READ_CH7: begin                         if(i==3) begin                         ad_rd<=1'b1;                          i<=0;                                 ad_ch7<=ad_data;                      state<=READ_CH8;                      end                                    else begin                             ad_rd<=1'b0;                          i<=i+1'b1;                            end                                    end                                     READ_CH8: begin                         if(i==3) begin                         ad_rd<=1'b1;                          i<=0;                                 ad_ch8<=ad_data;                      state<=READ_DONE;                     end                                    else begin                             ad_rd<=1'b0;                          i<=i+1'b1;                            end                                    end                                     READ_DONE:begin                         ad_rd<=1'b1;                          ad_cs<=1'b1;                          state<=IDLE;                          ad_finish<=1'b1;                      end                                     default: state<=IDLE;                   endcase                                 end                                     end                                        endmodule                                                       

这里在黑金官方的代码的基础上加入了ad_finish这个输出信号,目的是每次AD读完8个通道的值后告知SPI从机可以进行数据传输了。

SPI通讯

在两个FPGA之间的通讯,准备采用SPI模式,但是因为数据的流动方向只是从SPANTAN-6流向PYNQ-Z2,所以在这里对SPI通讯协议进行了修改。首先在传统的4线SPI模式中,去掉MOSI这根线,其次为了在传输时加大传输速度,把MISO的数据位宽改为16位,与AD输出的位宽相同。传输时遵从在时钟的下降沿从机准备好需要传输的数据,在时钟的上升沿主机采集数据。
下面直接上代码:

从机
//下降沿发送数据
module SPI_SLAVE
(                                                                         input clk,                                                            input rst_n,                                                          input CS_N,                                                           input SCK,                                                            input tx_en,   //                                                     output reg [15:0]MISO,                                                input [16*16-1:0] txd_data
);
//---------------------spi_slaver send data---------------------------
reg [3:0] txd_state;
always@(negedge SCK or negedge rst_n)
begin                                                                     if(!rst_n)                                                            begin                                                             txd_state <= 1'b0;                                            MISO<=0;                                                      end                                                               else if(!CS_N)                                                        begin                                                             case(txd_state)                                               4'd0:begin                                                MISO <= txd_data[255:240];                        txd_state <= 4'd1;                                end                                                 4'd1:begin                                                MISO <= txd_data[239:224];                        txd_state <= 4'd2;                                end                                                 4'd2:begin                                                MISO <= txd_data[223:208];                        txd_state <= 4'd3;                                end                                                 4'd3:begin                                                MISO <= txd_data[207:192];                        txd_state <= 4'd4;                                end                                                 4'd4:begin                                                MISO <= txd_data[191:176];                        txd_state <= 4'd5;                                end                                                 4'd5:begin                                                MISO <= txd_data[175:160];                        txd_state <= 4'd6;                                end                                                 4'd6:begin                                                MISO <= txd_data[159:144];                        txd_state <= 4'd7;                                end                                                 4'd7:begin                                                MISO <= txd_data[143:128];                        txd_state <= 4'd8;                                end                                                 4'd8:begin                                                MISO <= txd_data[127:112];                        txd_state <= 4'd9;                                end                                                 4'd9:begin                                                MISO <= txd_data[111:96];                         txd_state <= 4'd10;                               end                                                 4'd10:begin                                               MISO <= txd_data[95:80];                          txd_state <= 4'd11;                               end                                                 4'd11:begin                                               MISO <= txd_data[79:64];                          txd_state <= 4'd12;                               end                                                 4'd12:begin                                               MISO <= txd_data[63:48];                          txd_state <= 4'd13;                               end                                                 4'd13:begin                                               MISO <= txd_data[47:32];                          txd_state <= 4'd14;                               end                                                 4'd14:begin                                               MISO <= txd_data[31:16];                          txd_state <= 4'd15;                               end                                                 4'd15:begin                                               MISO <= txd_data[15:0];                           txd_state <= 4'd0;                                end                                                 default: ;                                                endcase                                                       end
end                                                                       endmodule                                                                 
主机
//上升沿发送数据
module SPI_MASTER
(                                                                                                       input clk,//100M                                                                                    input rst_n,                                                                                        input rx_en,                                                                                        output rx_done,                                                                                     output reg [16*16-1:0]data_out,                                                                     input [15:0]MISO,                                                                                   output reg SCK,                                                                                     output reg CS_N
);                                                                                                      reg [6:0]i;
reg rx_en_r;
reg rx_done_r;
reg [5:0]rxd_state;
always @(posedge clk or negedge rst_n)
if(~rst_n)
begin                                                                                                   rxd_state<=5'b0;                                                                                    CS_N<=1'b1;                                                                                         SCK<=1'b1;                                                                                          rx_done_r<=1'b0;                                                                                    data_out<=0;                                                                                        i<=7'b0;
end
else
begin                                                                                                   if(rx_en_r)                                                                                         begin                                                                                               CS_N<=1'b0;                                                                                     case(rxd_state)                                                                                 6'd0,6'd2,6'd4,6'd6,6'd8,6'd10,6'd12,6'd14,6'd16,6'd18,6'd20,6'd22,6'd24,6'd26,6'd28,6'd30: begin                                                                                       if(i==100)                                                                              begin                                                                                   SCK<=1'b0;                                                                          i<=0;                                                                               rxd_state<=rxd_state+1'b1;                                                          end                                                                                     else                                                                                    i<=i+1;                                                                             rx_done_r<=1'b0;                                                                    end                                                                                         6'd1://接收第15位                                                                               begin                                                                                       if(i==100)                                                                              begin                                                                                   SCK<=1'b1;                                                                          rxd_state<=rxd_state+1'b1;                                                          rx_done_r<=1'b0;                                                                    data_out[255:240]<=MISO;                                                            i<=0;                                                                               end                                                                                     else                                                                                    i<=i+1;                                                                             end                                                                                         6'd3://接收第14位                                                                               begin                                                                                       if(i==100)                                                                              begin                                                                                   SCK<=1'b1;                                                                          rxd_state<=rxd_state+1'b1;                                                          rx_done_r<=1'b0;                                                                    data_out[239:224]<=MISO;                                                            i<=0;                                                                               end                                                                                     else                                                                                    i<=i+1;                                                                             end                                                                                         6'd5://接收第13位                                                                               begin                                                                                       if(i==100)                                                                              begin                                                                                   SCK<=1'b1;                                                                          rxd_state<=rxd_state+1'b1;                                                          rx_done_r<=1'b0;                                                                    data_out[223:208]<=MISO;                                                            i<=0;                                                                               end                                                                                     else                                                                                    i<=i+1;                                                                             end                                                                                         6'd7://接收第12位                                                                               begin                                                                                       if(i==100)                                                                              begin                                                                                   SCK<=1'b1;                                                                          rxd_state<=rxd_state+1'b1;                                                          rx_done_r<=1'b0;                                                                    data_out[207:192]<=MISO;                                                            i<=0;                                                                               end                                                                                     else                                                                                    i<=i+1;                                                                             end                                                                                         6'd9://接收第11位                                                                               begin                                                                                       if(i==100)                                                                              begin                                                                                   SCK<=1'b1;                                                                          rxd_state<=rxd_state+1'b1;                                                          rx_done_r<=1'b0;                                                                    data_out[191:176]<=MISO;                                                            i<=0;                                                                               end                                                                                     else                                                                                    i<=i+1;                                                                             end                                                                                         6'd11://接收第10位                                                                              begin                                                                                       if(i==100)                                                                              begin                                                                                   SCK<=1'b1;                                                                          rxd_state<=rxd_state+1'b1;                                                          rx_done_r<=1'b0;                                                                    data_out[175:160]<=MISO;                                                            i<=0;                                                                               end                                                                                     else                                                                                    i<=i+1;                                                                             end                                                                                         6'd13://接收第9位                                                                               begin                                                                                       if(i==100)                                                                              begin                                                                               SCK<=1'b1;                                                                          rxd_state<=rxd_state+1'b1;                                                          rx_done_r<=1'b0;                                                                    data_out[159:144]<=MISO;                                                            i<=0;                                                                               end                                                                                 else                                                                                    i<=i+1;                                                                             end                                                                                         6'd15://接收第8位                                                                               begin                                                                                       if(i==100)                                                                              begin                                                                                   SCK<=1'b1;                                                                          rxd_state<=rxd_state+1'b1;                                                          rx_done_r<=1'b0;                                                                    data_out[143:128]<=MISO;                                                            i<=0;                                                                               end                                                                                     else                                                                                    i<=i+1;                                                                             end                                                                                         6'd17://接收第7位                                                                               begin                                                                                       if(i==100)                                                                              begin                                                                                   SCK<=1'b1;                                                                          rxd_state<=rxd_state+1'b1;                                                          rx_done_r<=1'b0;                                                                    data_out[127:112]<=MISO;                                                            i<=0;                                                                               end                                                                                     else                                                                                    i<=i+1;                                                                             end                                                                                         6'd19://接收第6位                                                                               begin                                                                                       if(i==100)                                                                              begin                                                                                   SCK<=1'b1;                                                                          rxd_state<=rxd_state+1'b1;                                                          rx_done_r<=1'b0;                                                                    data_out[111:96]<=MISO;                                                             i<=0;                                                                               end                                                                                     else                                                                                    i<=i+1;                                                                             end                                                                                         6'd21://接收第5位                                                                               begin                                                                                       if(i==100)                                                                              begin                                                                                   SCK<=1'b1;                                                                          rxd_state<=rxd_state+1'b1;                                                          rx_done_r<=1'b0;                                                                    data_out[95:80]<=MISO;                                                              i<=0;                                                                               end                                                                                     else                                                                                    i<=i+1;                                                                             end                                                                                         6'd23://接收第4位                                                                               begin                                                                                       if(i==100)                                                                              begin                                                                                   SCK<=1'b1;                                                                          rxd_state<=rxd_state+1'b1;                                                          rx_done_r<=1'b0;                                                                    data_out[79:64]<=MISO;                                                              i<=0;                                                                               end                                                                                     else                                                                                    i<=i+1;                                                                             end                                                                                         6'd25://接收第3位                                                                               begin                                                                                       if(i==100)                                                                              begin                                                                                   SCK<=1'b1;                                                                          rxd_state<=rxd_state+1'b1;                                                          rx_done_r<=1'b0;                                                                    data_out[63:48]<=MISO;                                                              i<=0;                                                                               end                                                                                     else                                                                                    i<=i+1;                                                                             end                                                                                         6'd27://接收第2位                                                                               begin                                                                                       if(i==100)                                                                              begin                                                                                   SCK<=1'b1;                                                                          rxd_state<=rxd_state+1'b1;                                                          rx_done_r<=1'b0;                                                                    data_out[47:32]<=MISO;                                                              i<=0;                                                                               end                                                                                     else                                                                                    i<=i+1;                                                                             end                                                                                         6'd29://接收第1位                                                                               begin                                                                                       if(i==100)                                                                              begin                                                                                   SCK<=1'b1;                                                                          rxd_state<=rxd_state+1'b1;                                                          rx_done_r<=1'b0;                                                                    data_out[31:16]<=MISO;                                                              i<=0;                                                                               end                                                                                     else                                                                                    i<=i+1;                                                                             end                                                                                         6'd31://接收第0位                                                                               begin                                                                                       if(i==100)                                                                              begin                                                                                   SCK<=1'b1;                                                                          rxd_state<=rxd_state+1;                                                             rx_done_r<=1'b1;                                                                    data_out[15:0]<=MISO;                                                               i<=0;                                                                               end                                                                                     else                                                                                    i<=i+1;                                                                             end                                                                                         6'd32:                                                                                      begin                                                                                       SCK<=1'b1;                                                                              rxd_state<=rxd_state+1'b1;                                                              rx_done_r<=1'b1;                                                                        end                                                                                         default:                                                                                    begin                                                                                       rxd_state<=6'd0;                                                                        end                                                                                         endcase                                                                                         end
end                                                                                                     //上升沿检测
reg btn1;
reg btn2;
always @(posedge clk or negedge rst_n)
if(~rst_n)
begin                                                                                                   btn1 <= 1'b0;                                                                                        btn2 <= 1'b0;
end
else
begin                                                                                                   btn1  <= rx_done;                                                                                    btn2  <= btn1;
end
wire done=btn1 & ~btn2;                                                                                 always @(posedge clk or negedge rst_n)
if(~rst_n)                                                                                              rx_en_r<=1'b0;
else                                                                                                    if(rx_en)                                                                                           rx_en_r<=1'b1;                                                                                  else                                                                                                if(done)                                                                                        rx_en_r<=1'b0;                                                                              assign rx_done=rx_done_r;                                                                               

因为偶数状态的逻辑都一样,所以可以合并起来。这里为了方便ARM核通过AXI4总线对主机SPI模块进行控制和读取,加入了rx_en和rx_done两个信号。当rx_en置1时,启动SPI传输。当rx_done置1时,表示SPI传输完成,有了这两个信号就可以很方便的使用ARM的定时器定时读取AD值。具体原理可以结合仿真时序进行理解。

AXI4-LITE总线

在基于zynq架构的Xilinx的FPGA上,PS(ARM核)和PL(可编程逻辑部分)的通讯都是基于AXI4总线的。因为要传输的数据量不大,就16个寄存器中的数据(分别对应于16个AD通道),所以就使用了AXI4-LITE总线,而没有使用AXI4-HP总线。这个总线总结起来就是地址先达,数据随后。就是不管是读寄存器还是写寄存器都要先送地址,然后才能读(写)数据。

具体的总线原理可以参考这篇文章:AXI4总线。需要注意的是LITE总线是不支持突发传输的。

下面直接上基于AXI4-LITE总线的AD寄存器代码:

module axi_reg
(                                                                                     input clk,                                                                        input rst_n,                                                                      //AR channel                                                                      input S_AXI_ARVALID,                                                              output S_AXI_ARREADY,                                                             input [6: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 [6: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,                                                               //from ad fifo                                                                    input [16*16-1:0]ad_data,                                                         input data_vld,                                                                   //cmd to SPI_master                                                               input rx_done,   //最好放在一个叫做done 的寄存器里                                             output rx_en     //rx_en=start
);                                                                                    //内部寄存器                                                                               //start reg0
reg done_r;       //reg1
reg [15:0]ad1;    //reg2
reg [15:0]ad2;    //reg3
reg [15:0]ad3;    //reg4
reg [15:0]ad4;    //reg5
reg [15:0]ad5;    //reg6
reg [15:0]ad6;    //reg7
reg [15:0]ad7;    //reg8
reg [15:0]ad8;    //reg9
reg [15:0]ad9;    //reg10
reg [15:0]ad10;   //reg11
reg [15:0]ad11;   //reg12
reg [15:0]ad12;   //reg13
reg [15:0]ad13;   //reg14
reg [15:0]ad14;   //reg15
reg [15:0]ad15;   //reg16
reg [15:0]ad16;   //reg17                                                             wire start;                                                                           always @(posedge clk or negedge rst_n)
if(~rst_n)
begin                                                                                 done_r<=0;                                                                        ad1<=0;                                                                           ad2<=0;                                                                           ad3<=0;                                                                           ad4<=0;                                                                           ad5<=0;                                                                           ad6<=0;                                                                           ad7<=0;                                                                           ad8<=0;                                                                           ad9<=0;                                                                           ad10<=0;                                                                          ad11<=0;                                                                          ad12<=0;                                                                          ad13<=0;                                                                          ad14<=0;                                                                          ad15<=0;                                                                          ad16<=0;
end
else
begin                                                                                 done_r<=rx_done;                                                                  if(data_vld)                                                                      begin                                                                             ad1<=ad_data[15:0];                                                           ad2<=ad_data[31:16];                                                          ad3<=ad_data[47:32];                                                          ad4<=ad_data[63:48];                                                          ad5<=ad_data[79:64];                                                          ad6<=ad_data[95:80];                                                          ad7<=ad_data[111:96];                                                         ad8<=ad_data[127:112];                                                        ad9<=ad_data[143:128];                                                        ad10<=ad_data[159:144];                                                       ad11<=ad_data[175:160];                                                       ad12<=ad_data[191:176];                                                       ad13<=ad_data[207:192];                                                       ad14<=ad_data[223:208];                                                       ad15<=ad_data[239:224];                                                       ad16<=ad_data[255:240];                                                       end
end
/**********************************AXI4_LITE****************************************/
//写应答
assign S_AXI_BRESP=2'b0;
reg axi_bvalid;
assign S_AXI_BVALID=axi_bvalid;
always @(posedge clk or negedge rst_n)
if(~rst_n)                                                                            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 [4:0]addr_word_w;
wire [4:0]addr_word_w_comb;
always @(posedge clk or negedge rst_n)
if(~rst_n)                                                                            addr_word_w<=0;
else                                                                                  if(S_AXI_AWVALID & S_AXI_AWREADY)                                                 addr_word_w<=S_AXI_AWADDR[6:2];                                               assign addr_word_w_comb=(S_AXI_AWVALID & S_AXI_AWREADY)?S_AXI_AWADDR[6:2]:addr_word_w;
assign S_AXI_AWREADY=1'b1;//S_AXI_AWVALID&S_AXI_WVALID;
//保障写完地址后再写数据
reg w_phase;
always @(posedge clk or negedge rst_n)
if(~rst_n)                                                                            w_phase<=1'b0;
else                                                                                  if(S_AXI_AWVALID & S_AXI_AWREADY)                                                 w_phase<=1;                                                                   else                                                                              if(S_AXI_WVALID & S_AXI_WREADY)                                               w_phase<=0;                                                               assign S_AXI_WREADY=w_phase;
//读地址,数据
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 clk or negedge rst_n)
if(~rst_n)
begin                                                                                 rvalid<=1'b0;                                                                     rdata<=32'b0;
end
else                                                                                  if(S_AXI_ARVALID & S_AXI_ARREADY)                                                 begin                                                                             rvalid<=1'b1;                                                                        case(S_AXI_ARADDR[6:2])                                                             1:rdata<={31'b0,done_r};                                                           2:rdata<={31'b0,ad1};                                                              3:rdata<={31'b0,ad2};                                                              4:rdata<={31'b0,ad3};                                                              5:rdata<={31'b0,ad4};                                                              6:rdata<={31'b0,ad5};                                                              7:rdata<={31'b0,ad6};                                                              8:rdata<={31'b0,ad7};                                                              9:rdata<={31'b0,ad8};                                                              10:rdata<={31'b0,ad9};                                                             11:rdata<={31'b0,ad10};                                                            12:rdata<={31'b0,ad11};                                                            13:rdata<={31'b0,ad12};                                                            14:rdata<={31'b0,ad13};                                                            15:rdata<={31'b0,ad14};                                                            16:rdata<={31'b0,ad15};                                                            17:rdata<={31'b0,ad16};                                                            default:rdata<=32'b0;                                                              endcase                                                                              end                                                                               else                                                                              if(S_AXI_RVALID&S_AXI_RREADY)                                                  rvalid<=1'b0;                                                                      assign start=S_AXI_WVALID & S_AXI_WREADY & (addr_word_w_comb==0) & S_AXI_WDATA[0];
assign rx_en=start;
endmodule                                                                             

这里在设计时每个寄存器都设计为了32位的,而AD数据只有16位的,所以需要对高位补零。这么设计的原因主要是为了方便地利用地址的[6:2]位确定到底是哪个寄存器(地址的1位,对应于数据的16位),方便SDK软件程序的编写。

打包IP核

需要注意的是需要在AD寄存器模块和SPI主机模块之间加一个FIFO进行数据缓存,FIFO的深度设置为1即可。FIFO采用同步FIFO,且输出输入端口利用握手信号(data_in_rdy,data_in_vld,data_out_rdy,data_out_vld)进行控制。其中data_in_rdy直接置1,data_in_vld由rx_done控制,data_out_rdy直接置1,data_out_vld接到axi_reg模块的data_vld。

最后编写顶层模块(AD),打包成IP核(AD_0)。在顶层模块中需要例化SPI_MASTER、fifo、axi_reg模块。如何打包自定义的IP核可以参考这里。需要注意的是前面的代码已经满足AXI4总线的规范,所以可以自动生成AXI4接口,不需要其他操作。

建立PYNQ工程

建立好的PYNQ系统图如图所示:

如何建工程可以参考这里。
注意,把比特流文件和硬件文件导入Jupyter Notebook就可以使用PYTHON编写驱动和算法了,但是本文为了方便,使用SDK裸机开发。

编写SDK程序

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xil_io.h"                               #define AD_BASEADDR XPAR_AD_0_BASEADDR            u32 *rdata;
u32 *rdata1;
u32 *rdata2;
u32 *rdata3;
u32 *rdata4;
u32 *rdata5;
u32 *rdata6;
u32 *rdata7;
u32 *rdata8;
u32 *rdata9;
u32 *rdata10;
u32 *rdata11;
u32 *rdata12;
u32 *rdata13;
u32 *rdata14;
u32 *rdata15;
u32 *rdata16;                                     void wirte_ad(int reg, u32 data)
{                                                 Xil_Out32(AD_BASEADDR+reg*4, data);
}                                                 void read_ad(int reg, u32 *data)
{                                                 u32 x;                                          float y;                                        *data=Xil_In32(AD_BASEADDR+reg*4);              x=*data&0x7fff;//提取低15位的数据位,16位为符号位y=(float)(x)*5/32758;                           printf("read reg%d,data:%f\r\n",reg,y);
}                                                 void read_ad_reg1(int reg, u32 *data)
{                                                 *data=Xil_In32(AD_BASEADDR+reg*4);
}                                                 int main()
{                                                 init_platform();                              print("Hello World\n\r");                     while(1)                                      {                                             //kick of run                                 wirte_ad(0,1);                                read_ad_reg1(1,rdata);                        while(*rdata!=1)//等待SPI传输完成                              {                                             read_ad_reg1(1,rdata);                      }                                             read_ad(2,rdata1);                            read_ad(3,rdata2);                            read_ad(4,rdata3);                            read_ad(5,rdata4);                            read_ad(6,rdata5);                            read_ad(7,rdata6);                            read_ad(8,rdata7);                            read_ad(9,rdata8);                            read_ad(10,rdata9);                           read_ad(11,rdata10);                          read_ad(12,rdata11);                          read_ad(13,rdata12);                          read_ad(14,rdata13);                          read_ad(15,rdata14);                          read_ad(16,rdata15);                          read_ad(17,rdata16);                          }                                             cleanup_platform();                           return 0;
}

上板验证

注意,在两块FPGA烧写好程序后,需要对从机的FPGA进行复位(按一下rst_n信号连接的那个按键)才可以进行可靠传输。
演示图如图所示:

把3.3V接到了第一片AD的第6输入通道,可以看到对应的串口输出的reg7的值为3.3V,实验成功。(reg1为SPI的done信号,reg2存放第一片AD第一个通道的值,所以第一片AD的第6输入通道的值存放在reg7)注意:AD的悬空电压为1.7V.

代码下载地址

https://download.csdn.net/download/qq_34329669/11975542

基于PYNQ的AD采集系统相关推荐

  1. 基于FPGA的数据采集系统

    目录 一.理论基础 二.核心程序 三.测试结果 一.理论基础 数据采集是指将模拟量采集转换成数字量后,再由计算机进行存储.处理.显示或打印的过程,相应的系统称为数据采集系统.随着科技进步,人们对数据采 ...

  2. 基于互联网的温度采集系统

    1 绪论... 1 1.1 课题背景... 1 1.2 研究内容... 1 1.3 发展前景... 1 1.4 研究意义... 2 2. 开发平台介绍... 2 2.1 开发环境... 2 2.2 操 ...

  3. 基于pynq的数字识别神经网络加速器设计

    文章目录 基于pynq的数字识别神经网络加速器设计 软件部分 1. 全连接神经网络: 2. 卷积神经网络搭建: 3. 文件格式转换: 硬件部分 1. MNIST的硬件实现思路 2. 代码编写与硬件综合 ...

  4. 基于JAVA水质监测数据采集系统计算机毕业设计源码+数据库+lw文档+系统+部署

    基于JAVA水质监测数据采集系统计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVA水质监测数据采集系统计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目架构:B/S架构 ...

  5. 基于 PYNQ 的 AXI 总线主从控制编写(ddr3的读写)

    菜鸟一枚,最近也学习了关于 AXI 总线的相关知识.基于 PYNQ 编写了一个简单的 AXI 主从控制(牵涉到 DDR3 的读写). 设计目的 设计出以下一个通过 AXI 总线连接的简单片上系统.包含 ...

  6. 基于MQTT的数据采集系统

    基于MQTT的数据采集系统 1.实验目的 本次研究推出一款实用的轻量型智能家居系统,本系统采用STM32为主控芯片,将MQTT通信协议移植到STM32中,将其作为一个MQTTClient.该系统的核心 ...

  7. stm32ad测量范围_基于STM32F103内部AD测量电池电压

    STM32的ADC介绍: STM32 拥有 1~3 个 ADC ( STM32F101/102系列只有1个ADC),这些ADC可以独立使用,也可以使用双重模式(提高采样率).STM32 的 ADC 是 ...

  8. 基于PYNQ的深度学习模型设计与实现

    本人其实做过一段基于ZYNQ的FPGA加速开发,但是后面不了了之了,也不太清楚脉动阵列发展到什么程度了,还有不断从ISE(CHIPSCOPE),到VIVADO(ILA,也包含SG,SDK套件)以及对应 ...

  9. 基于单片机的数据采集系统

    摘 要:本文以AT89C51单片机为核心,设计一个基于单片机的数据采集系统.系统可以采集16路模拟量,精度为12位,16路开关量和2路脉冲量,并将采集到的数据每隔一分钟通过串口发送到PC机. 关键字: ...

最新文章

  1. 这是一份非常全面的开源数据集!
  2. Kafka监控架构设计
  3. github服务器停止响应,如何解决“git pull,致命:无法访问'https://github.com ... \':服务器空回复”...
  4. Linux 系统启动流程图/系统初始化流程图
  5. 程序员福利各大平台免费接口,非常适用
  6. linux文本文件和win文本文件的格式互换
  7. mysql视图应用_MySQL视图的概念与实际应用
  8. ORACLE HANDBOOK系列之十:字符集、编码以及Oracle的那些事
  9. 学习 Message(13): 解析 TWMMouse.Keys 参数
  10. 消费者价格研究中的数据分析
  11. JAVA MIDP_Java MIDP2.1和JAVA MIDP2.0的本质区别是什么啊?
  12. Program Library HOWTO(2)
  13. RaspberryPI 3b 技术总结(包括Linux)
  14. JAVA 线程池的分析和使用
  15. Kotlin习惯用语和编码风格[转自Kotlin中文文档]
  16. Notepad++删除空白行
  17. 美妆护肤做短视频,利用选题策划来涨粉?
  18. 20222817《Linux内核原理与分析》第五周作业
  19. Ansible playbook
  20. matlab-基础 复数 实部、虚部、模、共轭、辐角

热门文章

  1. 《自然-机器智能》:神经形态技术可使大型深度学习网络节能16倍
  2. ST MCSDK 初探
  3. BUFF:iPad真的能当砧板用
  4. 量子计算机需要mK温度工作吗,格林函数法分析冷槽离子量子计算机中的温度效应.pdf...
  5. Got a packet bigger than 'max_allowed_packet' bytes 问题的解决方法
  6. 在宜家兼职收银员创收
  7. 容联云聚客SCRM如何破SCRM保险应用困局
  8. 1米*1米*1米*1米*1米等于什么?
  9. 96道前端面试题,作出的职业规划建议
  10. 脸上有酒窝,脖子后有痣,胸前有颗痣,此三种人不能错过