Verilog SPI从属数据到并行总线

时间:2016-03-14 21:31:21

标签: verilog spi slave

非常与Verilog一起使用,并花费了大量时间来解决此问题。我非常感谢您给我的任何建议/反馈!

我有这块Verilog SPI从代码,它从SPI读取200位数据并将其存储在多维数组中。我已经建立了一个测试平台,它似乎正常工作。数据恰好是SID(Commodore 64声音接口设备)的寄存器信息,SID有25个寄存器,在音乐播放时以50Hz的频率更新。因为更新到SID这么慢,我没有预料到竞争条件,但最终我想在我的设计中建立一个FIFO缓冲器...无论如何,SPI总线将非常快,因为我正在获取数据来自ESP8266,它可以为原始的SPI总线提供时钟 80MHz的。

更新代码

module spi_slave(
    input ss,
    input sclk,
    input mosi,
    input read_en,
    input [4:0] addr,
    output [7:0] data,
    output reg data_rdy = 1'b0
    );

reg [7:0] data_in;  
reg [7:0] bit_cnt = 8'd0;  
reg [7:0] sid_reg [24:0];   // store all SID registers

assign data = (read_en) ? sid_reg[addr] : 8'b0;

    always @(posedge sclk) begin
        if (!ss) begin
            data_in = {data_in[6:0], mosi}; // shift left
            bit_cnt = bit_cnt + 1;  
            if (!(bit_cnt % 8)) begin   // if # bits in is divisable by 8 we just got a full byte
                sid_reg[(bit_cnt/8)-1] <= data_in;  // store the current value 
                if (bit_cnt == 8'd200) bit_cnt <= 8'd0;  // once we reach 25 bytes reset the counter
            end
        end
    end

    always @(posedge ss or posedge read_en) begin
        if(!bit_cnt) data_rdy = 1;  // let the bus module know it's time to assert data
        if(read_en) data_rdy = 0;  // when read starts turn off ready
    end

endmodule

我正在使用一个同样以1MHz计时SID的CPLD我还有另一个模块,它采用CPLD的20MHz时钟并对其进行适当分频。一旦我从SPI读取了200位数据,我需要在每个SID时钟周期将其发送到SID的并行地址和数据总线一个寄存器。

我计划实现一些代码,因此SPI模块可以采用addr和输出数据(模仿25字节ROM),以及输出寄存器'data_rdy',当数据准备就绪时将其设置为1。然后我写一个模块来读取每个字节并将其写入SID总线。这听起来合乎逻辑吗?如果这是解决问题的最佳方法,我正在努力。如果不是,你会怎么攻击这个?谢谢!

编辑以下是我编写的将数据写入SID总线的代码。我刚刚开始工作,但有一大堆编译器警告,我不明白......我广泛使用last_data寄存器,有人可以解释我是否应该担心这个?

WARNING:Xst:1710 - FF/Latch <last_data_9_0> (without init value) has a constant value of 0 in block <glue>. This FF/Latch will be trimmed during the optimization process.

模块:

    module sid_glue(
    input clk,
    input sid_clk,
    output sid_cs, // active low
    output reg sid_rw = 1'b1, // write low
    input data_rdy,
    output reg [4:0] addr = 4'b0,
    input [7:0] data, // incoming frame data from SPI
    output reg read_en = 1'b0,
    output reg [4:0] sid_addr = 5'b0,
    output reg [7:0] sid_data = 8'b0
    );

    reg [7:0] last_data [24:0];
    reg write_en = 1'b0; 

    // sync sid_clk to the FPGA clock using a 2-bit shift register
    reg [1:0] sid_clk_r;  always @(posedge clk) sid_clk_r <= {sid_clk_r[0], sid_clk};
    wire sid_clk_risingedge = (sid_clk_r==2'b01);  
    wire sid_clk_fallingedge = (sid_clk_r==2'b10);  

    // same for data ready, just need to detect pos edge
    reg [1:0] data_rdy_r;  always @(posedge clk) data_rdy_r <= {data_rdy_r[0], data_rdy};
    wire data_rdy_posedge = (data_rdy_r==2'b01);

    assign sid_cs = sid_rw; // tied together for now (we don't need read atm)

    always @(posedge clk) begin

        if ((write_en || data_rdy_posedge) && sid_clk_risingedge) begin
            if (!write_en) write_en <= 1'b1;
            read_en = 1;
            if ((data != last_data[addr]) || last_data[addr] === 8'bX) begin // don't write the data if it hasn't changed
                sid_addr = addr;    // put the address on the SID addr lines
                sid_data = data;   // data on the data line
                sid_rw = 0;
                last_data[addr] <= data; // copy data to the buffer for compare next time
           end
        end

        else if (write_en && sid_clk_fallingedge) begin
            sid_rw = 1;
            read_en = 0;
            addr = addr + 1;    // move to the next address
            if (addr == 25) begin write_en <= 0; addr = 5'b0; end // disable writes and reset counter
        end

    end

endmodule

0 个答案:

没有答案