Skip to content

Instantly share code, notes, and snippets.

@buttercutter
Last active November 13, 2018 01:21
Show Gist options
  • Save buttercutter/04cc7eebc739fb21ba33c00a7ee589b6 to your computer and use it in GitHub Desktop.
Save buttercutter/04cc7eebc739fb21ba33c00a7ee589b6 to your computer and use it in GitHub Desktop.
SPI flash controller for Winbond W25Q32 flash
module SPI(clk, reset, data_valid, data_MOSI, data_ready, data_MISO, MISO, MOSI, clk_flash, CS_flash);
parameter MOSI_DATA_BITWIDTH = 8 + 24 + 256*8; // for page_program(02h)
parameter MISO_DATA_BITWIDTH = 8;
localparam INSTRUCTION_READ_DATA = 3; // Read Data (03h) instruction
input clk, reset;
input data_valid;
input [$clog2(MOSI_DATA_BITWIDTH)-1:0] data_MOSI; // data going into the slave (SPI flash)
output reg data_ready;
output reg [MISO_DATA_BITWIDTH-1:0] data_MISO; // data originating from slave (SPI flash)
input MISO;
output reg MOSI;
output clk_flash;
output reg CS_flash;
//output CS_flash = (reset) ? 1 : (in_index == 1 || out_index == 1) ? 0 : 1;
reg [($clog2(MISO_DATA_BITWIDTH)-1):0] in_index;
reg [($clog2(MOSI_DATA_BITWIDTH)-1):0] out_index;
assign clk_flash = clk;
always @(posedge clk)
begin
if(reset) begin
CS_flash <= 1;
end
else begin // 0 during SPI flash transaction, 1 during idling
if(data_valid) CS_flash <= 0; // CS is asserted low for writing of instruction and/or address to SPI slave (flash)
if((in_index == MISO_DATA_BITWIDTH) || ((out_index == MOSI_DATA_BITWIDTH + 1) && !read_en)) CS_flash <= 1; // SPI transaction finishes
end
end
always @(posedge clk)
begin
if(reset) begin
MOSI <= 1;
out_index <= 0;
end
else if(!CS_flash && (out_index <= MOSI_DATA_BITWIDTH)) begin // send data to slave (SPI flash) during the transaction
MOSI <= data_MOSI[out_index];
out_index <= out_index + 1'b1;
end
else out_index <= 0; // for next SPI transaction
end
reg read_en; // for Read Data (03h) instruction, slave will send out the data to master immediately after the 24-bit address, no waiting cycles are needed
always @(negedge clk)
begin
if(reset) begin
read_en <= 0;
end
else if((data_MOSI == INSTRUCTION_READ_DATA) && (out_index == MOSI_DATA_BITWIDTH)) begin
read_en <= 1;
end
else read_en <= 0; // for next SPI transaction
end
always @(negedge clk) // this SPI flash sends out its data on the falling edge, so this flash controller has to follow SPI flash spec
begin
if(reset) begin
data_ready <= 0;
data_MISO <= 0; // all zeroes
in_index <= 0; // the shift register 'data_MISO' stores the data starting from LSB
end
else begin
if(in_index == MISO_DATA_BITWIDTH) begin
data_ready <= 1; // data reading from slave is complete or finished now
in_index <= 0; // for next SPI transaction
end
else begin
data_ready <= 0;
if(CS_flash && read_en && !data_ready) begin // read data from slave (SPI flash) during the transaction
data_MISO[in_index] <= MISO;
in_index <= in_index + 1'b1;
end
end
end
end
endmodule
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment