0

I am a newbie in FPGA domain and trying to learn as I develop my own verilog code. As Part of it I was trying to implement a SPI slave on icestick FPGA. Below is my code. IN this code for testing purposes I am sending value 137 constantly on miso pin. I am sampling the sck pin at FPGA clock (100MHz) to detect positive and negative edge and then tx-ing and rx-ing data on negative and positive edge respectively. For testing I am using arduino as 2MHz SPI master. I am not receiving 137 consistently. Out of 100 I am getting one or two SPI values correctly. I am sure there are metastability issues. Could someone have a look at code below and tell me what and where I am not programming things properly.

module top(
input        CLK,
input        spi_ss,
input        spi_clk,
input        spi_mosi,
output       spi_miso
);

localparam PARAM_CPHA   = 0;
localparam PARAM_CPOL   = 0;
localparam WAIT_TIME    = 13500000;

wire sysclk;
wire locked;
pll myPLL (.clock_in(CLK), .global_clock(sysclk), .locked(locked));

reg [5:0]  val          = 0;
wire       m_CPHA       = PARAM_CPHA;
wire       m_CPOL       = PARAM_CPOL;  
wire m_spi_clk = (m_CPOL == 0) ? spi_clk : ~spi_clk;
reg m_spi_clk_lvl      = 0;   
reg m_last_spi_clk_lvl = 0;   
reg m_spi_clk_sync  = 0;
reg m_spi_ss_sync   = 0;

reg m_spi_rise_event = 0;
reg m_spi_fall_event = 0;

reg m_spi_rx_bit;
reg m_spi_tx_bit;

reg [3:0] m_spi_rx_index = 7;
reg [3:0] m_spi_tx_index = 7;

reg [7:0] m_spi_rx_byte;
reg [7:0] m_spi_tx_byte = 137;
reg m_spi_ss;


assign spi_miso = m_spi_tx_bit;



    always @(posedge sysclk) begin
    m_spi_ss_sync <= spi_ss;
    m_spi_ss      <= m_spi_ss_sync;
    /* check if ss signal is low */
    if( m_spi_ss == 0 ) begin
        /* sample spi clock for positive edge and negative edge detection */
        m_spi_clk_sync <= spi_clk;
        m_spi_clk_lvl  <= m_spi_clk_sync;  
        /* detect positive edge/rise event */ 
        if( ( m_spi_clk_lvl == 1 ) && ( m_last_spi_clk_lvl == 0 ) ) begin
            m_spi_rise_event <= 1;
        end
        /* detect negative edge/fall event */
        if( ( m_spi_clk_lvl == 0 ) && ( m_last_spi_clk_lvl == 1 ) ) begin
            m_spi_fall_event <= 1;
        end
        /* Store current sampled value of clock in last sampled value */
        m_last_spi_clk_lvl <= m_spi_clk_lvl;
        //if rise event has happend on SPI clock the scan mosi data from data input; 
        if( m_spi_rise_event == 1 ) begin
            m_spi_rx_bit                  <= spi_mosi;
            m_spi_rx_byte[m_spi_rx_index] <= m_spi_rx_bit;
            m_spi_rise_event <= 0;
            m_spi_rx_index <= m_spi_rx_index - 1;

            if( m_spi_rx_index == 0 ) begin
                m_spi_rx_index <= 7;
            end
        end
        //if fall event has happend on SPI clock the put data on miso; 
        if( m_spi_fall_event == 1 ) begin
            m_spi_tx_bit     <= m_spi_tx_byte[m_spi_tx_index];
            m_spi_fall_event <= 0;
            m_spi_tx_index   <= m_spi_tx_index - 1;
            if( m_spi_tx_index == 0 ) begin
                m_spi_tx_index <= 7;
            end
        end
    end
    end

endmodule

Thanks in advance

Ravi
  • 9
  • 3
  • 1
    `m_spi_rise_event` and `m_spi_fall_event` are going to be delayed by 1 sysclk cycle which seems unnecessary, but also shouldn't be a problem if sysclk is 50 times as fast as spi_clk. Consider that *all* `<=` assignments occur at the end of the clock cycle (in this cases sysclk) – user253751 Jul 15 '23 at 17:33
  • You are correct. Observing outputs at simulation shows everything is delayed by a clock. As you stated it should not be a problem if the SPI clok speed is significantly slower than FPGA clock speed. – Ravi Jul 15 '23 at 18:40
  • although I can't really pinpoint any *problem* here I can see a bunch of unnecessary complexity - mostly, you are delaying things by unnecessary extra clock cycles and forming memory registers that aren't really needed. For example if m_spi_fall_event isn't set to either 0 or 1 then it will maintain its last set value (which I know is 0, but the compiler doesn't). – user253751 Jul 15 '23 at 22:17
  • here's another possible issue: the TX/RX index doesn't get reset to 7 when the master starts a transaction – user253751 Jul 15 '23 at 22:17
  • The indices (m_spi_rx_index and m_spi_tx_index) should be reset (to 7) when the bus is idle (ss not asserted). Have you simulated this verilog code? Also, for CPHA0 and CPOL0, the first bit of data should appear on MISO shortly after ss is asserted (if you intend to read 8 bits right away). The master will sample MISO on the first rising edge following SS assertion. – Troutdog Jul 20 '23 at 20:01

0 Answers0