【ADC&FPGA】基于ZCU102+FMCJESDADC1的数据采集项目之篇(5):补充AXI SPI设计

本篇目的

上一篇中,简述中搭建PS工程的概貌。但其中AD9250_SPI_TOP如何设计和集成,一笔带过。思来想去,还是补充描述些AD9250_SPI_TOP的设计。

设计思路

AD9250_SPI_TOP功能简单来说,就是把AXI的配置转成SPI时序。

其中AXI4Lite到APB的转换是使用xilinx自带的AXI APB Bridge模块。为什么要先转APB呢,因为APB转寄存器读写时序最为简单。

SPI Master模块就是把APB地址读写操作转为为SPI MST时序。

对于写操作,

  • 规定[31:24]为DevID,不同设备的映射关系如下:
  localparam  FMC27X_CPLD     = 8'h00;
  localparam  FMC27X_AD9517   = 8'h84;
  localparam  FMC27X_AD9250_0 = 8'h80;
  localparam  FMC27X_AD9250_1 = 8'h81;
  localparam  FMC27X_AD9129_0 = 8'h82;
  localparam  FMC27X_AD9129_1 = 8'h83;
  • 规定[19:8]为Addr,如对地址0x001进行写操作。
  • 规定[7:0]为Wdata,即写数据。

例如:写值0x80000018为配置AD9250-0芯片的0x000地址,配置值为0x18.

对于读操作,需要先写0x008,再回读0x010,数据在回读的低8bit.

参考代码

AD9250_SPI_AXI.V

//--====================================================================================--//
// Copyright (C) 2024 funnydigitalworld. All rights reserved.
// This confidential and proprietary software may be used only as authorized 
// by a licensing agreement from funnydigitalworld(funnydigitalworld@outlook.com).
// The entire notice above must be reproduced on all authorized copies.
//
// FILENAME     : .\ad9250_spi_axi.v
// MODULE       : AD9250_SPI_AXI
// AUTHOR       : (Wechat:funnydigitalworld)/(QQ:2702272533)
// EMAIL        : funnydigitalworld@outlook.com
// DATE:        : 2024-04-15 00:15:06
// VERSION      : v1.0
// DESCRIPTION  : 
//
// CHANGE LOG   :
// @2024-04-15 00:15:06 : create this file (by funnydigitalworld)
//
//--====================================================================================--//

module AD9250_SPI_AXI
    (
        input                     s_axi_aclk        , //(IW:  1)  
        input                     s_axi_aresetn     , //(IW:  1)  
        input           [7 :0]    spi_rdata         , //(IW:  8)  
        input                     spi_ready         , //(IW:  1)  
        input           [6 :0]    s_axi_awaddr      , //(IW:  7)  
        input                     s_axi_awvalid     , //(IW:  1)  
        input           [31:0]    s_axi_wdata       , //(IW: 32)  
        input           [3 :0]    s_axi_wstrb       , //(IW:  4)  
        input                     s_axi_wvalid      , //(IW:  1)  
        input                     s_axi_bready      , //(IW:  1)  
        input           [6 :0]    s_axi_araddr      , //(IW:  7)  
        input                     s_axi_arvalid     , //(IW:  1)  
        input                     s_axi_rready      , //(IW:  1)  
        output  reg               spi_tran_start    , //(OR:  1)  
        output  reg               spi_rewn_flag     , //(OR:  1)  
        output  reg     [7 :0]    spi_demux_head    , //(OR:  8)  
        output  wire    [12:0]    spi_inst_addr     , //(OW: 13)  
        output  reg     [7 :0]    spi_write_data    , //(OR:  8)  
        output  wire              s_axi_awready     , //(OW:  1)  
        output  wire              s_axi_wready      , //(OW:  1)  
        output  wire    [1 :0]    s_axi_bresp       , //(OW:  2)  
        output  wire              s_axi_bvalid      , //(OW:  1)  
        output  wire              s_axi_arready     , //(OW:  1)  
        output  wire    [31:0]    s_axi_rdata       , //(OW: 32)  
        output  wire    [1 :0]    s_axi_rresp       , //(OW:  2)  
        output  wire              s_axi_rvalid        //(OW:  1)  
    );

//--=======================================================--//
//                   INTERNAL DECLARATION
//--=======================================================--//

//-=========(SI_BEG:PARA)==========-//


//-==========(SI_BEG:REG)==========-//
reg     [31:0]    axi_cfg_h00        ; //(R: 32) 
reg     [31:0]    axi_cfg_h0c        ; //(R: 32) 
reg               axi_rd_latch       ; //(R:  1) 
reg               m_apb_pready       ; //(R:  1) 
reg               cfg_wr             ; //(R:  1) 
reg               cfg_rd             ; //(R:  1) 
reg     [6 :0]    cfg_addr           ; //(R:  7) 
reg     [31:0]    cfg_wdat           ; //(R: 32) 
reg     [31:0]    m_apb_prdata       ; //(R: 32) 
reg               wait_spi_en        ; //(R:  1) 
reg               cfg_ready          ; //(R:  1) 
reg     [11:0]    spi_offset_addr    ; //(R: 12) 

//-=========(SI_BEG:WIRE)==========-//
wire              setup_phase        ; //(W:  1) 
wire              apb_oper_done      ; //(W:  1) 
wire              m_apb_pwrite       ; //(W:  1) 
wire              m_apb_penable      ; //(W:  1) 
wire              m_apb_psel         ; //(W:  1) 
wire    [6 :0]    m_apb_paddr        ; //(W:  7) 
wire    [31:0]    m_apb_pwdata       ; //(W: 32) 


//--=======================================================--//
//                   MAIN SOURCE CODE
//--=======================================================--//
axi4lite_apb_bridge U_AXI4LITE_APB 
(
  .s_axi_aclk     (s_axi_aclk     ),        // input wire s_axi_aclk
  .s_axi_aresetn  (s_axi_aresetn  ),        // input wire s_axi_aresetn
  .s_axi_awaddr   (s_axi_awaddr   ),        // input wire [6 : 0] s_axi_awaddr
  .s_axi_awvalid  (s_axi_awvalid  ),        // input wire s_axi_awvalid
  .s_axi_awready  (s_axi_awready  ),        // output wire s_axi_awready
  .s_axi_wdata    (s_axi_wdata    ),        // input wire [31 : 0] s_axi_wdata
  .s_axi_wvalid   (s_axi_wvalid   ),        // input wire s_axi_wvalid
  .s_axi_wready   (s_axi_wready   ),        // output wire s_axi_wready
  .s_axi_bresp    (s_axi_bresp    ),        // output wire [1 : 0] s_axi_bresp
  .s_axi_bvalid   (s_axi_bvalid   ),        // output wire s_axi_bvalid
  .s_axi_bready   (s_axi_bready   ),        // input wire s_axi_bready
  .s_axi_araddr   (s_axi_araddr   ),        // input wire [6 : 0] s_axi_araddr
  .s_axi_arvalid  (s_axi_arvalid  ),        // input wire s_axi_arvalid
  .s_axi_arready  (s_axi_arready  ),        // output wire s_axi_arready
  .s_axi_rdata    (s_axi_rdata    ),        // output wire [31 : 0] s_axi_rdata
  .s_axi_rresp    (s_axi_rresp    ),        // output wire [1 : 0] s_axi_rresp
  .s_axi_rvalid   (s_axi_rvalid   ),        // output wire s_axi_rvalid
  .s_axi_rready   (s_axi_rready   ),        // input wire s_axi_rready
  .m_apb_paddr    (m_apb_paddr    ),        // output wire [6 : 0] m_apb_paddr
  .m_apb_psel     (m_apb_psel     ),        // output wire [0 : 0] m_apb_psel
  .m_apb_penable  (m_apb_penable  ),        // output wire m_apb_penable
  .m_apb_pwrite   (m_apb_pwrite   ),        // output wire m_apb_pwrite
  .m_apb_pwdata   (m_apb_pwdata   ),        // output wire [31 : 0] m_apb_pwdata
  .m_apb_pready   (m_apb_pready   ),        // input wire [0 : 0] m_apb_pready
  .m_apb_prdata   (m_apb_prdata   ),        // input wire [31 : 0] m_apb_prdata
  .m_apb_pslverr  (m_apb_pslverr  )         // input wire [0 : 0] m_apb_pslverr
);


//--=========================================---
always@(posedge s_axi_aclk or negedge s_axi_aresetn)
begin
    if(s_axi_aresetn == 1'b0)
        m_apb_pready <= 1'b1 ;
    else if(setup_phase)
        m_apb_pready <= 1'b0 ;
    else if(apb_oper_done)
        m_apb_pready <= 1'b1 ;
end   

assign setup_phase = m_apb_psel & (~m_apb_penable);

always@(posedge s_axi_aclk or negedge s_axi_aresetn)
begin
    if(s_axi_aresetn == 1'b0)
    begin
        cfg_addr <= 7'b0  ;
        cfg_wdat <= 32'b0 ;
        cfg_wr   <= 1'b0  ;
        cfg_rd   <= 1'b0  ;
    end
    else if(setup_phase)
    begin
        cfg_addr <= m_apb_paddr  ;
        cfg_wdat <= m_apb_pwdata ;    
        cfg_wr   <= m_apb_pwrite ;
        cfg_rd   <=~m_apb_pwrite ;        
    end
    else
    begin
        cfg_wr   <= 1'b0  ;
        cfg_rd   <= 1'b0  ;
    end    
end    

//--SPI Control--
always@(posedge s_axi_aclk or negedge s_axi_aresetn)
begin
    if(s_axi_aresetn == 1'b0)
    begin
        spi_demux_head  <= 8'h80  ;
        spi_offset_addr <= 12'h00 ;
        spi_write_data  <= 8'h00  ;
    end
    else if((cfg_addr == 7'h04 || cfg_addr == 7'h08) & cfg_wr)
    begin
        spi_demux_head  <= cfg_wdat[31:24] ;
        spi_offset_addr <= cfg_wdat[19:8]  ;
        spi_write_data  <= cfg_wdat[7:0]   ;
    end
end

assign spi_inst_addr = {1'b0,spi_offset_addr};

always@(posedge s_axi_aclk or negedge s_axi_aresetn)
begin
    if(s_axi_aresetn == 1'b0)
        spi_rewn_flag <= 1'b1 ;
    else if((cfg_addr == 7'h04) & cfg_wr)
        spi_rewn_flag <= 1'b0 ;
    else if((cfg_addr == 7'h10) & cfg_rd)
        spi_rewn_flag <= 1'b1 ;
end

always@(posedge s_axi_aclk or negedge s_axi_aresetn)
begin
    if(s_axi_aresetn == 1'b0)
        spi_tran_start <= 1'b0 ;
    else if((cfg_addr == 7'h04) & cfg_wr)
        spi_tran_start <= 1'b1 ;
    else if((cfg_addr == 7'h10) & cfg_rd)
        spi_tran_start <= 1'b1 ;
    else 
        spi_tran_start <= 1'b0 ;
end

always@(posedge s_axi_aclk or negedge s_axi_aresetn)
begin
    if(s_axi_aresetn == 1'b0)
    begin
        axi_cfg_h00 <= 32'haabbccdd ;
        axi_cfg_h0c <= 32'h12345678 ;
    end
    else if(cfg_wr)
    begin
        case(cfg_addr)
            7'h00: axi_cfg_h00 <= cfg_wdat ;
            7'h0c: axi_cfg_h0c <= cfg_wdat ;     
            default: ;
        endcase
    end
end

always@(posedge s_axi_aclk or negedge s_axi_aresetn)
begin
    if(s_axi_aresetn == 1'b0)
        m_apb_prdata <= 32'b0 ;
    else if(apb_oper_done)
    begin
        case(cfg_addr)
            8'h00: m_apb_prdata <= axi_cfg_h00 ;
            8'h04: m_apb_prdata <= {spi_demux_head[7:0],{3'b0,spi_rewn_flag,spi_offset_addr[11:0]},spi_write_data[7:0]} ;
            8'h08: m_apb_prdata <= {spi_demux_head[7:0],{3'b0,spi_rewn_flag,spi_offset_addr[11:0]},8'b0} ; 
            8'h0c: m_apb_prdata <= axi_cfg_h0c ;
            8'h10: m_apb_prdata <= {spi_demux_head[7:0],{3'b0,spi_rewn_flag,spi_offset_addr[11:0]},spi_rdata} ;
            
            default: m_apb_prdata  <= 32'b0;
        endcase
    end
end

always@(posedge s_axi_aclk or negedge s_axi_aresetn)
begin
    if(s_axi_aresetn == 1'b0)
        wait_spi_en <= 1'b0 ;
    else if((cfg_addr == 7'h04) & cfg_wr)
        wait_spi_en <= 1'b1 ;
    else if((cfg_addr == 7'h10) & cfg_rd)
        wait_spi_en <= 1'b1 ;
    else if(cfg_wr | cfg_rd)
        wait_spi_en <= 1'b0 ;
end

always@(posedge s_axi_aclk or negedge s_axi_aresetn)
begin
    if(s_axi_aresetn == 1'b0)
        cfg_ready <= 1'b0 ;
    else
        cfg_ready <= cfg_wr | cfg_rd ;
end

assign apb_oper_done = wait_spi_en ? spi_ready : cfg_ready ;


//--=======================================================--//
//                   MODULE INSTANTATION
//--=======================================================--//
//-====(INSTFILES)====-//

//-=========(SI_BEG:INST)==========-//



//--=======================================================--//
endmodule 

AD9250_SPI_MST.v

//--====================================================================================--//
// Copyright (C) 2024 funnydigitalworld. All rights reserved.
// This confidential and proprietary software may be used only as authorized 
// by a licensing agreement from funnydigitalworld(funnydigitalworld@outlook.com).
// The entire notice above must be reproduced on all authorized copies.
//
// FILENAME     : .\ad9250_spi_mst.v
// MODULE       : AD9250_SPI_MST
// AUTHOR       : (Wechat:funnydigitalworld)/(QQ:2702272533)
// EMAIL        : funnydigitalworld@outlook.com
// DATE:        : 2024-04-14 22:01:22
// VERSION      : v1.0
// DESCRIPTION  : 
//
// CHANGE LOG   :
// @2024-04-14 22:01:22 : create this file (by funnydigitalworld)
//
//--====================================================================================--//

module AD9250_SPI_MST
    (
        input                     clk               , //(IW:  1)  
        input                     rst_n             , //(IW:  1)  
        input                     spi_tran_start    , //(IW:  1)  
        input                     spi_rewn_flag     , //(IW:  1)  
        input           [7 :0]    spi_demux_head    , //(IW:  8)  
        input           [12:0]    spi_inst_addr     , //(IW: 13)  
        input           [7 :0]    spi_write_data    , //(IW:  8)  
        input                     spi_miso          , //(IW:  1)  
        output  reg               spi_clk           , //(OR:  1)  
        output  reg               spi_csn           , //(OR:  1)  
        output  wire              spi_mosi          , //(OW:  1)  
        output  reg     [7 :0]    spi_rdata         , //(OR:  8)  
        output  reg               spi_ready           //(OR:  1)  
    );

//--=======================================================--//
//                   INTERNAL DECLARATION
//--=======================================================--//

//-=========(SI_BEG:PARA)==========-//


//-==========(SI_BEG:REG)==========-//
reg     [3 :0]    spi_div_cnt        ; //(R:  4) 
reg               spi_tran_en        ; //(R:  1) 
reg     [7 :0]    spi_bit_cnt        ; //(R:  8) 
reg               spi_rcv_en         ; //(R:  1) 
reg     [32:0]    spi_tran_stream    ; //(R: 33) 


//-=========(SI_BEG:WIRE)==========-//
wire    [1 :0]    spi_word_len       ; //(W:  2) 
wire              spi_tran_done      ; //(W:  1) 
wire              spi_rise_ps        ; //(W:  1) 
wire              spi_fall_ps        ; //(W:  1) 


//--=======================================================--//
//                   MAIN SOURCE CODE
//--=======================================================--//

parameter SPI_RISE_CNT = 4'd7 ;
parameter SPI_FALL_CNT = 4'd3 ;


assign spi_word_len = 2'b00 ; //2'B00: 1 Byte Mode. 2'B01: 2 Byte Mode. ...

//--==================================--
// Gen SPI Clock
//--==================================--

always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        spi_tran_en <= 1'b0 ;
    else if(spi_tran_start)
        spi_tran_en <= 1'b1 ;
    else if(spi_tran_done)
        spi_tran_en <= 1'b0 ;
end
    
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        spi_div_cnt <= 4'b0 ;
    else if(~spi_tran_en)
        spi_div_cnt <= 4'b0 ;
    else if(spi_div_cnt >= SPI_RISE_CNT)
        spi_div_cnt <= 4'b0 ;
    else
        spi_div_cnt <= spi_div_cnt + 4'b1 ;
end

assign spi_rise_ps =  (spi_div_cnt == SPI_RISE_CNT);
assign spi_fall_ps =  (spi_div_cnt == SPI_FALL_CNT);

always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        spi_bit_cnt <= 8'b0 ;
    else if(spi_tran_start)
        spi_bit_cnt <= 8'b0 ;
    else if(spi_fall_ps)
        spi_bit_cnt <= spi_bit_cnt + 8'b1 ;
end



assign spi_tran_done = (spi_bit_cnt >= 8'd33) & spi_rise_ps;
//assign spi_tran_done = (spi_bit_cnt >= 8'd33) & spi_fall_ps;
//CSB Gen
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        spi_clk <= 1'b1 ;
    else if(spi_tran_done)
        spi_clk <= spi_clk ;
    else if(spi_fall_ps)
        spi_clk <= 1'b0 ;
    else if(spi_rise_ps)
        spi_clk <= 1'b1 ;
    else if(~spi_tran_en)
        spi_clk <= 1'b1 ;
end

//SCLK
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        spi_csn <= 1'b1 ;
    else if(spi_tran_start)
        spi_csn <= 1'b0 ;
    else if(spi_tran_done)
        spi_csn <= 1'b1 ;
end

always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        spi_tran_stream <= {1'b1,8'b0,16'b0,8'b0} ;
    else if(spi_tran_start &  (spi_rewn_flag == 1'b0))
        spi_tran_stream <= {1'b1,spi_demux_head[7:0],{1'b0,spi_word_len[1:0],spi_inst_addr[12:0]},spi_write_data[7:0]} ;
    else if(spi_tran_start &  (spi_rewn_flag == 1'b1))    
        spi_tran_stream <= {1'b1,spi_demux_head[7:0],{1'b1,spi_word_len[1:0],spi_inst_addr[12:0]},8'b0} ;
    else if(spi_tran_en & spi_fall_ps)
        spi_tran_stream <= {spi_tran_stream[31:0],1'b1};
end

assign spi_mosi = spi_tran_stream[32] ;

//Read Data
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        spi_rcv_en <= 1'b0 ;
    else if(spi_tran_start &  (spi_rewn_flag == 1'b1))
        spi_rcv_en <= 1'b1 ;
    else if(spi_tran_done)
        spi_rcv_en <= 1'b0 ;
end


always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        spi_rdata <= 8'b0 ;
    else if(spi_tran_start)
        spi_rdata <= 1'b0 ;
    else if(spi_rcv_en & spi_rise_ps & (spi_bit_cnt >= 8'd25) & (spi_bit_cnt <= 8'd32))
        spi_rdata <= {spi_rdata[6:0],spi_miso} ;
end

always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        spi_ready <= 1'b0 ;
    else if(spi_tran_start)
        spi_ready <= 1'b0 ;
    //else if(spi_rcv_en & spi_rise_ps & (spi_bit_cnt >= 8'd32))
    else if(spi_rise_ps & (spi_bit_cnt == 8'd32))
        spi_ready <= 1'b1 ;
    else
        spi_ready <= 1'b0 ;
end

//--=======================================================--//
//                   MODULE INSTANTATION
//--=======================================================--//
//-====(INSTFILES)====-//

//-=========(SI_BEG:INST)==========-//



//--=======================================================--//
endmodule 

AXI APB Bridge IP配置

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值