用fpga控制ads1298的spi通信

用fpga来配置ads1298芯片对应寄存器的spi通信。用Verilog代码实现。最好有比较详细的注释

http://www.go-gddq.com/html/s124/2014-05/1222847.htm

可以给你一个SPI的控制程序,应该需要做点改进,比如读取数据的字节数定义什么的,可以参考这个
FPGA SPI加速度传感器教程

至于具体控制ADS1298芯片的逻辑流程要参考datasheet 85页的初始化流程表,上面那个教程里也有相似的代码,希望能帮到你

顶层接口定义,除了SPI接口外,控制接口有:

  • ready,上升沿代表传输开始
  • inst,读写指令,读是0x0B,写是0x0A
  • rdh_wrl,高电平代表读,低电平代表写。虽然根据inst可以判断读写,但以后可能存在一些其他应用,还是保留了这个控制引脚
  • reg_addr,寄存器地址
  • dout,写给设备的数据
  • din,设备传回的数据
  • din_valid,设备传回数据准备,高电平时代表传回的数据已经准备好了
module SPI_transmitter(
    input      clk,
    input      rst,

    // SPI port
    output reg CSN,
    output reg SCLK,
    output reg MOSI,
    input      MISO,

    // Control port
    input            ready,
    input      [7:0] inst,
    input            rdh_wrl,
    input      [7:0] reg_addr,
    input      [7:0] dout,
    output reg [7:0] din,
    output reg       din_valid
);

SPI时钟SCLK生成器,减缓20倍成5MHz

// SCK generator, 5MHz output
reg         SCLK_en;
reg         SCLK_d;
reg  [7:0]  SCLK_count;
wire        SCLK_posedge;
wire        SCLK_negedge;

always @(posedge clk or posedge rst) begin
    if(rst || ~SCLK_en) begin
        SCLK <= 1'b0;
        SCLK_count <= 8'd0;
    end
    else if(SCLK_en && (SCLK_count<8'd10)) begin
        SCLK_count <= SCLK_count + 8'd1;
    end
    else begin
        SCLK <= ~SCLK;
        SCLK_count <= 8'd0;
    end
end

监测SCLK的上升沿和下降沿

always @(posedge clk) begin
    SCLK_d <= SCLK;
end
assign SCLK_posedge = ({SCLK_d, SCLK}==2'b01) ? 1'b1 : 1'b0;
assign SCLK_negedge = ({SCLK_d, SCLK}==2'b10) ? 1'b1 : 1'b0;

监测ready的上升沿

// Ready rising edge detection
reg  ready_d;
wire ready_posedge;
always @(posedge clk) begin
    ready_d <= ready;
end
assign ready_posedge = ({ready_d, ready} == 2'b01) ? 1'b1 : 1'b0;

状态机配置

// State machine
reg  [3:0]  state;
reg  [3:0]  next_state;

parameter IDLE       = 4'd0;
parameter START      = 4'd1;
parameter INST_OUT   = 4'd2;
parameter ADDR_OUT   = 4'd3;
parameter WRITE_DATA = 4'd4;
parameter READ_DATA  = 4'd5;
parameter ENDING     = 4'd6;

reg  [6:0]  MISO_buf;
reg  [7:0]  MOSI_buf;
reg  [3:0]  MOSI_count;

always @(posedge clk or posedge rst) begin
    if(rst) begin
        state <= IDLE;
    end
    else begin
        state <= next_state;
    end
end

always @(posedge clk) begin
    case(state)
    IDLE: 
    begin   // IDLE state
        next_state <= START;
        MOSI <= 1'b0;
        CSN <= 1'b1;
        SCLK_en <= 1'b0;
        MOSI_buf <= inst;
        MOSI_count <= 4'd0;
        din <= 8'h00;
        din_valid <= 1'b0;
    end

当ready上升沿时,拉低CS,开启SCLK生成器,进入读写流程

    START:
    begin   // enable SCK and CS
        // start the process when ready rise, load instruction
        if(ready_posedge) begin
            next_state <= INST_OUT;
            CSN  <= 1'b0;
            SCLK_en <= 1'b1;
            MOSI_buf <= {inst[6:0], 1'b0};
            MOSI <= inst[7];
        end
    end

输出8位指令

    INST_OUT:
    begin   // send out instruction
        if(SCLK_negedge && (MOSI_count < 4'd7)) begin
            {MOSI, MOSI_buf} <= {MOSI_buf, 1'b0};
            MOSI_count <= MOSI_count + 4'd1;
        end
        else if(SCLK_negedge) begin
            {MOSI, MOSI_buf} <= {reg_addr, 1'b0};
            MOSI_count <= 4'd0;
            next_state <= ADDR_OUT;
        end
    end

输出8位地址,根据读写控制进入读数据流程或者写数据流程

    ADDR_OUT:
    begin   // send out register address
        if(SCLK_negedge && (MOSI_count < 4'd7)) begin
            {MOSI, MOSI_buf} <= {MOSI_buf, 1'b0};
            MOSI_count <= MOSI_count + 4'd1;
        end
        else if(SCLK_negedge) begin
            {MOSI, MOSI_buf} <= {dout, 1'b0};
            MOSI_count <= 4'd0;
            next_state <= (rdh_wrl) ? READ_DATA : WRITE_DATA;
        end
    end

读写数据流程,写完进入结尾。将来可能会加入多字节读写控制

    WRITE_DATA:
    begin   // send testing data out to flash
        if(SCLK_negedge && (MOSI_count < 4'd7)) begin
            {MOSI, MOSI_buf} <= {MOSI_buf, 1'b0};
            MOSI_count <= MOSI_count + 4'd1;
        end
        else if(SCLK_negedge) begin
            {MOSI, MOSI_buf} <= 9'h0;
            MOSI_count <= 4'd0;
            next_state <= ENDING;
        end
    end
    READ_DATA:
    begin   // get a byte
        if(SCLK_posedge && (MOSI_count < 4'd7)) begin
            MISO_buf <= {MISO_buf[5:0], MISO};
            MOSI_count <= MOSI_count + 4'd1;
        end
        else if(SCLK_posedge) begin
            MOSI_count <= 4'd0;
            next_state <= ENDING;
            din <= {MISO_buf, MISO};
            din_valid <= 1'b1;
        end
        else begin
            din_valid <= 1'b0;
        end
    end

结尾流程,一段时间后拉高CSN

    ENDING:
    begin   //disable SCK and CS
        if(SCLK_negedge) begin
            CSN <= 1'b1;
            next_state <= IDLE;
            SCLK_en <= 1'b0;
        end
    end
    endcase
end

endmodule