打印
[verilog]

3路AD7689采集程序求教

[复制链接]
2418|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
笑拥江山梦|  楼主 | 2016-4-17 18:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我将程序贴出一部分,求大神分析一下,初来乍到

module FPGA_AD7689_SPI (
//----------- Ports Declarations -----------------------------------------------
// 时钟和复位信号

        input               fpga_clk_i,         // 系统时钟
        input               adc_clk_i,          // AD转换时钟
        input               reset_i,            // 高电平复位信号
// IP 控制和 数据接口
        input               wr_data_n_i,        // 低电平信号来启动数据写入ADC
        input      [15:0]   data_i,             // 数据被写入ADC

        output reg [107:0]  data_channels_o1,    // FPGA从AD中读取数据
          output reg [107:0]  data_channels_o2,  
          output reg [107:0]  data_channels_o3,  
        output reg          data_rd_ready_o,    // 当其为高电平时,开始从ADC读取数据
        output reg          data_wr_ready_o,    // 用于ADC写状态信号: 0 - 正在写, 1 - 写完成

//  ADC 外部连接
        input               MISO_1,             // 主机输入,从机输出1
        output              MOSI_1,             // 主机输出,从机输入1
        output              SCK1,               // 串行数据时钟1
        output reg          SS1 ,               // 控制转换开始1
          input               MISO_2,             // 主机输入,从机输出2
        output              MOSI_2,             // 主机输出,从机输入2
        output              SCK2,               // 串行数据时钟2
        output reg          SS2 ,               // 控制转换开始2
          input               MISO_3,             // 主机输入,从机输出3
        output              MOSI_3,             // 主机输出,从机输入3
        output              SCK3,               // 串行数据时钟3
        output reg          SS3                 // 控制转换开始3
);


//----------- Local Parameters -------------------------------------------------

// 状态机
parameter IDLE              = 9'b000000001; // 起始状态
parameter START_CNV         = 9'b000000010; // 开始转换
parameter CONVERSION        = 9'b000000100; // 等待转换时间
parameter CNV_LOW           = 9'b000001000; // CNV 为低电平
parameter READ_DATA         = 9'b000010000; // 在忙busy信号之前读取数据
parameter SELECT_CHANNEL    = 9'b000100000; // 根据配置选择下一个状态
parameter SYNCHRONIZE_COM   = 9'b001000000; // state in which samples are referenced to COM pin
parameter SYNCHRONIZE_DIFF  = 9'b010000000; // 差分采样状态
parameter WAIT_CYCLE_END    = 9'b100000000; // 等待转换时间结束
localparam real      FPGA_CLK        = 12;  // MHz
localparam real      ADC_CYCLE_TIME  = 4;   // us
localparam real      ADC_CONV_TIME   = 2.2; // us

localparam integer    CYCLE_CNT       = (FPGA_CLK * ADC_CYCLE_TIME) - 3;    // 用于周期计数
localparam integer    CONV_CNT        = (FPGA_CLK * ADC_CONV_TIME) - 2 ;    // 用于转换计数


//----------- Registers Declarations寄存器声明 -------------------------------------------

// 状态机寄存器
reg [8:0]   present_state;  // 状态机的当前状态
reg [8:0]   next_state;     // 状态机的下一状态
reg         SCLK_en;        // 用于产生时钟信号,使能
reg [15:0]  tx_reg1;         // Transmitted data, as received from the CED1Z_interface module
reg [15:0]  tx_reg2;   
reg [15:0]  tx_reg3;   
reg [15:0]  tx_reg_d1;      // 发送数据寄存器1
reg [15:0]  tx_reg_d2;      // 发送数据寄存器2
reg [15:0]  tx_reg_d3;      // 发送数据寄存器3
reg [15:0]  rx_reg1;         // 接收数据寄存器
reg [15:0]  rx_reg2;
reg [15:0]  rx_reg3;
reg [31:0]  cycle_cnt;      // 测量周期时间寄存器
reg [31:0]  conv_cnt;       // 测量转换时间寄存器
reg [4:0]   sclk_cnt;       // 用于计数发送的时钟信号的寄存器
reg [1:0]   seq;            // 通道序列器,允许以IN0到IN[7:0]的方式扫描通道
reg [2:0]   inx;            // 通道选择寄存器,以二进制的方式选择输入通道
reg [2:0]   incc;           // 用于输入通道配置寄存器,选择差分、单端等
reg [2:0]   channel;        // Register used for keeping track of the channel acquired


//----------- Assign/Always 模块---------------------------------------------

assign SCK1           = SCLK_en ? adc_clk_i : 1'b0;   // clock is idle LOW
assign SCK2           = SCLK_en ? adc_clk_i : 1'b0;
assign SCK3           = SCLK_en ? adc_clk_i : 1'b0;
assign MOSI_1         = tx_reg_d1[13];              // send data from tx_reg_d register on the MOSI data line
assign MOSI_2         = tx_reg_d2[13];
assign MOSI_3         = tx_reg_d3[13];


always @(negedge adc_clk_i)     // ad7689 发送/接收数据
begin
    if (reset_i == 1'b1)
    begin
        rx_reg1      <= 16'h0;
        tx_reg_d1    <= 16'h0;
          rx_reg2      <= 16'h0;
        tx_reg_d2    <= 16'h0;
          rx_reg3      <= 16'h0;
        tx_reg_d3    <= 16'h0;
    end
    else if(SCLK_en == 1'b1)
    begin
        rx_reg1      <= { rx_reg1[14:0], MISO_1 };        // Receive data  利用拼接接收数据
        tx_reg_d1    <= { tx_reg_d1[14:0], 1'b0 };        // Send data   利用拼接发送数据
        rx_reg2      <= { rx_reg2[14:0], MISO_2 };
        tx_reg_d2    <= { tx_reg_d2[14:0], 1'b0 };
        rx_reg3      <= { rx_reg3[14:0], MISO_3 };
        tx_reg_d3    <= { tx_reg_d3[14:0], 1'b0 };

    end
    else if (present_state == IDLE)                     // 清除 rx_reg 寄存器
    begin
        rx_reg1      <= 16'h0;
          rx_reg2      <= 16'h0;
          rx_reg3      <= 16'h0;
    end
    else if (present_state == CONVERSION)              //更新 tx_reg_d 寄存器
    begin
        tx_reg_d1    <= {1'b0, tx_reg1[13], tx_reg1[13:0]};
          tx_reg_d2    <= {1'b0, tx_reg2[13], tx_reg2[13:0]};
          tx_reg_d3    <= {1'b0, tx_reg3[13], tx_reg3[13:0]};
    end
end

always @(negedge fpga_clk_i)            // Process for timing the conversion time
begin
    if (present_state == START_CNV)     // 在 START_CNV状态下复位计数器
    begin
        cycle_cnt   <= CYCLE_CNT;
        conv_cnt    <= CONV_CNT;
    end
    else
    begin
        if ( cycle_cnt != 0 )           // Decrease cycle counter
        begin
            cycle_cnt   <= cycle_cnt - 32'h1;
        end
        if ( conv_cnt != 0 )            // Decrease conversion counter
        begin
            conv_cnt    <= conv_cnt - 32'h1;
        end
    end
end

// 状态机 - 状态选择

always @( present_state, sclk_cnt, cycle_cnt, incc, conv_cnt )
begin

    next_state <= present_state;
    case(present_state)
        IDLE:
        begin
            next_state      <= START_CNV;
        end
        START_CNV:
        begin
            next_state      <= CONVERSION;
        end
        CONVERSION:
        begin
            if(conv_cnt == 32'b0)
            begin
                next_state  <= CNV_LOW;
            end
        end
        CNV_LOW:
        begin
            next_state      <= READ_DATA;
        end
        READ_DATA:
        begin
            if(sclk_cnt == 5'b0)
            begin
                next_state  <= SELECT_CHANNEL;
            end
        end
        SELECT_CHANNEL:                  //选择差分、伪差分、单端等
        begin
            if( incc == 3'b000 || incc == 3'b001 || incc == 3'b100 || incc == 3'b101)   // Configuration words with differential pairs
            begin
                next_state  <= SYNCHRONIZE_DIFF;
            end
            else
            begin
                next_state  <= SYNCHRONIZE_COM;
            end
        end
        SYNCHRONIZE_COM:
        begin
            next_state  <= WAIT_CYCLE_END;
        end
        SYNCHRONIZE_DIFF:
        begin
            next_state  <= WAIT_CYCLE_END;
        end
        WAIT_CYCLE_END:
        begin
            if (cycle_cnt == 32'b0)
            begin
                next_state  <= IDLE;
            end
        end
        default:
        begin
            next_state      <= IDLE;
        end
    endcase
end


// 状态机 - 输出选择

always @(negedge fpga_clk_i)
begin
    if(reset_i == 1'b1)
    begin
        present_state               <= IDLE;
        tx_reg1                      <= 16'h0000;
          tx_reg2                      <= 16'h0000;
          tx_reg3                      <= 16'h0000;
        data_channels_o1 [ 107:0]    <= 108'h0;
          data_channels_o2 [ 107:0]    <= 108'h0;
          data_channels_o3 [ 107:0]    <= 108'h0;
    end
    else
    begin
        present_state           <= next_state;
        case( present_state )
            IDLE:
            begin
                if (wr_data_n_i == 0)   // if a write has been performed from  CED1Z to ADCCFG register, update the configuration register on AD7689
                begin
                    tx_reg1                      <= data_i;
                          tx_reg2                      <= data_i;
                          tx_reg3                      <= data_i;
                    data_wr_ready_o             <= 1'b1;
                    channel                     <= 3'h5;
                    incc                        <= data_i[12:10];
                    inx                         <= data_i[9:7];
                    seq                         <= data_i[2:1];
                    data_channels_o1 [ 107:0]    <= 108'h0;
                          data_channels_o2 [ 107:0]    <= 108'h0;
                          data_channels_o3 [ 107:0]    <= 108'h0;
                end
                else
                begin                   // if no write has been performed, keep DIN low
                    tx_reg1      <= 16'h0;
                          tx_reg2      <= 16'h0;
                          tx_reg3      <= 16'h0;
                end
                SCLK_en         <= 1'b0;
                SS1             <= 1'b0;
                data_rd_ready_o <= 1'b0;
                sclk_cnt        <= 5'hf;
            end
            START_CNV:
            begin
                data_wr_ready_o <= 1'b0;
                SCLK_en         <= 1'b0;
                SS1             <= 1'b1;
                data_rd_ready_o <= 1'b0;
            end
            CONVERSION:                 // The CNV pin is kept high until EOC. Configuration without busy indicator
            begin
                data_wr_ready_o <= 1'b0;
                SCLK_en         <= 1'b0;
                SS1             <= 1'b1;
                data_rd_ready_o <= 1'b0;
            end
            CNV_LOW:
            begin
                data_wr_ready_o <= 1'b0;
                SCLK_en         <= 1'b0;
                SS1             <= 1'b0;
                data_rd_ready_o <= 1'b0;
            end
            READ_DATA:
            begin
                data_wr_ready_o <= 1'b0;
                SCLK_en         <= 1'b1;
                SS1             <= 1'b0;
                data_rd_ready_o <= 1'b0;
                if( sclk_cnt != 0 )
                begin
                    sclk_cnt    <= sclk_cnt - 5'h1;
                end
            end
            SELECT_CHANNEL:
            begin
                channel         <= channel + 3'h1;
                data_wr_ready_o <= 1'b0;
                SCLK_en         <= 1'b0;
                data_rd_ready_o <= 1'b0;
                SS1             <= 1'b0;
            end
            SYNCHRONIZE_COM: // Using 11 for channel sequencer on and 00 for channel sequencer disabled. 01 and 10 should not be used to configure the AD7689
            begin
                case( channel )
                    3'h0:
                    begin
                        data_channels_o1[107:10] <= rx_reg1;
                                data_channels_o2[107:10] <= rx_reg2;
                                data_channels_o3[107:10] <= rx_reg3;
                        if ( seq == 2'b11  && inx == 3'h0)
                        begin
                            data_rd_ready_o <= 1'b1;
                            channel         <= 3'h7;
                        end
                    end
                    3'h1:
                    begin
                        data_channels_o1[107:96] <= rx_reg1;
                                data_channels_o2[107:96] <= rx_reg2;
                                data_channels_o3[107:96] <= rx_reg3;
                        if ( seq == 2'b11 && inx == 3'h1)
                        begin
                            data_rd_ready_o <= 1'b1;
                            channel         <= 3'h7;
                        end
                    end
                    3'h2:
                    begin
                        data_channels_o1[95:80]  <= rx_reg1;
                                data_channels_o2[95:80]  <= rx_reg2;
                                data_channels_o3[95:80]  <= rx_reg3;
                        if (seq == 2'b11 && inx == 3'h2)
                        begin
                            data_rd_ready_o <= 1'b1;
                            channel         <= 3'h7;
                        end
                    end
                    3'h3:
                    begin
                        data_channels_o1[79:64]  <= rx_reg1;
                                data_channels_o2[79:64]  <= rx_reg2;
                                data_channels_o3[79:64]  <= rx_reg3;
                        if (seq == 2'b11 && inx == 3'h3)
                        begin
                            data_rd_ready_o <= 1'b1;
                            channel         <= 3'h7;
                        end
                    end
                    3'h4:
                    begin
                        data_channels_o1[63:48]  <= rx_reg1;
                                data_channels_o2[63:48]  <= rx_reg2;
                                data_channels_o3[63:48]  <= rx_reg3;
                        if (seq == 2'b11 && inx == 3'h4)
                        begin
                            data_rd_ready_o <= 1'b1;
                            channel         <= 3'h7;
                        end
                    end
                    3'h5:
                    begin
                        data_channels_o1[47:32]  <= rx_reg1;
                                data_channels_o2[47:32]  <= rx_reg2;
                                data_channels_o3[47:32]  <= rx_reg3;
                        if (seq == 2'b11 && inx == 3'h5)
                        begin
                            data_rd_ready_o <= 1'b1;
                            channel         <= 3'h7;
                        end
                    end
                    3'h6:
                    begin
                        data_channels_o1[31:16]  <= rx_reg1;
                                data_channels_o2[31:16]  <= rx_reg2;
                                data_channels_o3[31:16]  <= rx_reg3;
                        if (seq == 2'b11 && inx == 3'h6)
                        begin
                            data_rd_ready_o <= 1'b1;
                            channel         <= 3'h7;
                        end
                    end
                    default:
                    begin
                        data_channels_o1[15:0]   <= rx_reg1;
                                data_channels_o2[15:0]   <= rx_reg2;
                                data_channels_o3[15:0]   <= rx_reg3;
                        data_rd_ready_o         <= 1'b1;
                        channel                 <= 3'h7;
                    end
                endcase
                data_wr_ready_o <= 1'b0;
                SCLK_en         <= 1'b0;
                SS1             <= 1'b0;
            end
            SYNCHRONIZE_DIFF:
            begin
                case( channel )
                    3'h0:
                    begin
                        data_channels_o1[107:100] <= rx_reg1;
                                data_channels_o2[107:100] <= rx_reg2;
                                data_channels_o3[107:100] <= rx_reg3;
                        if (seq == 2'b11 && (inx == 3'h0 || inx == 3'h1))
                        begin
                            data_rd_ready_o <= 1'b1;
                            channel         <= 3'h7;
                        end
                    end
                    3'h1:
                    begin
                        data_channels_o1[107:96]  <= rx_reg1;
                                data_channels_o2[107:96]  <= rx_reg2;
                                data_channels_o3[107:96]  <= rx_reg3;
                        if ( seq == 2'b11 && (inx == 3'h2 || inx == 3'h3))
                        begin
                            data_rd_ready_o <= 1'b1;
                            channel         <= 3'h7;
                        end
                    end
                    3'h2:
                    begin
                        data_channels_o1[95:80]  <= rx_reg1;
                                data_channels_o2[95:80]  <= rx_reg2;
                                data_channels_o3[95:80]  <= rx_reg3;
                        if (seq == 2'b11 && (inx == 3'h4 || inx == 3'h5))
                        begin
                            data_rd_ready_o <= 1'b1;
                            channel         <= 3'h7;
                        end
                    end
                    3'h6:
                    begin
                        channel             <= 3'h6; //used to synchronnize channels after configuration change
                    end
                    default:
                    begin
                        data_channels_o1[79:64]  <= rx_reg1;
                                data_channels_o2[79:64]  <= rx_reg2;
                                data_channels_o3[79:64]  <= rx_reg3;
                        data_rd_ready_o         <= 1'b1;
                        channel                 <= 3'h7;
                    end
                endcase
                data_wr_ready_o <= 1'b0;
                SCLK_en         <= 1'b0;
                SS1             <= 1'b0;
            end
            WAIT_CYCLE_END:
            begin
                data_wr_ready_o <= 1'b0;
                SCLK_en         <= 1'b0;
                SS1             <= 1'b0;
                data_rd_ready_o <= 1'b0;
            end
        endcase
    end
end

endmodule








相关帖子

沙发
玄德| | 2016-4-18 21:28 | 只看该作者

看这个有点难度,
首先要熟悉AD芯片,其次。。。这么长代码。



使用特权

评论回复
板凳
笑拥江山梦|  楼主 | 2016-4-19 01:35 | 只看该作者
哎,好心酸

使用特权

评论回复
地板
wangjunjun2005| | 2020-1-2 10:36 | 只看该作者
这个代码可以用不?

使用特权

评论回复
5
qq958141863| | 2020-3-16 16:06 | 只看该作者
大佬,这个代码能用吗

使用特权

评论回复
6
jfnljfxc| | 2020-3-18 16:49 | 只看该作者
同上问

使用特权

评论回复
7
jfnljfxc| | 2020-3-18 16:50 | 只看该作者
用在啥项目上?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

17

帖子

1

粉丝