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