EmbDev.net

Forum: FPGA, VHDL & Verilog Write a very simple controller for a flash memory in a IC board


Author: Pinellia C. (jesseyg)
Posted on:
Attached files:
  • preview image for 1.jpg
    1.jpg
    366 KB, 35 downloads
  • preview image for 2.jpg
    2.jpg
    410 KB, 38 downloads
  • preview image for 3.jpg
    3.jpg
    361 KB, 43 downloads

Rate this post
0 useful
not useful
As a school project I want to write a very simple controller for a flash 
memory in a IC board. The FPGA(Knowledge about FPGA: 
http://www.apogeeweb.net/article/67.html) chip is Altera 5CEFA4F23C8 and 
the flash is MX25L3206E.

I did an effort to produce the SCLK, SI and other signals that the chip 
needs through verilog, respecting the timing etc. I conceived the 
controller as a finite state machine that suppose to generate the SPI 
signals in order.

I have loaded the system to the board but it is not receiving anything 
from SO as I thought it would do automatically.

I'm using a "testbench-like" module that produce the avalon control, 
address and data signals like write, read and address, for a future 
implementation on a larger Avalon communication protocol SoC.

I'm adding the code I write for your reference.
    module FLASH_CTL (

 ////////////// avalon interface///////////////////

    input   wire [23:0] avalon_slave_address,
    input   wire [3:0]  avalon_slave_byteenable,    
    input   wire        avalon_slave_read,          //             .read
    input   wire        avalon_slave_write,         //             .write
    input   wire [31:0] avalon_slave_writedata,     //             .writedata
    input   wire        reset_sink_reset,           //   reset_sink.reset
    input   wire        clock_sink_clk,             // clock_sink_1.clk

    output wire [31:0]  avalon_slave_readdata,      //             .readdata
    output wire avalon_slave_readdatavalid, //             .readdatavalid
    output wire avalon_slave_waitrequest,   //             .waitrequest


//////////////// chip interface ///////////////////
    input wire SO,  
    output reg SI,
    output reg CS,
    output wire WP,
    output wire HOLD,
    output reg SCLK 
);

parameter ST_0 = 4'd0; parameter ST_1 = 4'd1; parameter ST_2 = 4'd2; parameter ST_3 = 4'd3;  
parameter ST_4 = 4'd4; parameter ST_5 = 4'd5; parameter ST_6 = 4'd6; parameter ST_7 = 4'd7;
parameter ST_8 = 4'd8; parameter ST_9 = 4'd9; parameter ST_10 = 4'd10; parameter ST_11 = 4'd11;

parameter wr_comm = 8'b0000_0010; // PROGRAM  0X02, write 0000_0010
parameter rd_comm = 8'b0000_0011; // PROGRAM  0X03, read 0000_0011


///////////////////////////////////////////////
parameter test_A = 8'b0001_1111;


reg [7:0] test_reg;


always@ (posedge  clock_sink_clk or negedge reset_sink_reset) begin
    if (~reset_sink_reset)
        test_reg <= 0;
    else 
        test_reg <= test_A;
end

////////////////////////////////////////////



reg [31:0] av_wrdata;
reg f_cyc_count, enable, rd_SO, f_bit_count, wr_mode, word_ak, clear_byte_c; 
reg av_rd7, av_rd6, av_rd5, av_rd4, av_rd3, av_rd2, av_rd1, av_rd0;
reg [3:0] state, nextstate;
reg [4:0] cyc_count, byte_count;
reg [7:0] comm_in, data_in, av_rd_byte1, av_rd_byte2, av_rd_byte3, av_rd_byte4;
reg [23:0] addr_in;
reg [4:0] bit_count;
wire [7:0] av_rd_buff;
reg [2:0] bytes_enabled;
wire burstcount, debugaccess; 

assign WP = 1;
assign HOLD = 1;
assign avalon_slave_waitrequest = ~ CS;
assign avalon_slave_readdatavalid = (CS && state >= 1 && wr_mode)? 1'b1:1'b0;
assign avalon_slave_readdata = {av_rd_byte1, av_rd_byte2, av_rd_byte3, av_rd_byte4};
assign av_rd_buff = {av_rd7, av_rd6, av_rd5, av_rd4, av_rd3, av_rd2, av_rd1, av_rd0}; 
assign burstcount = 0;
assign debugaccess = 0;


always@ (posedge  clock_sink_clk or negedge reset_sink_reset)begin
if (~reset_sink_reset)
    bytes_enabled <= 1;
else begin
    bytes_enabled <= bytes_enabled;
    case (avalon_slave_byteenable)
        4'b0001:    bytes_enabled <= 3'd0;
        4'b0011:    bytes_enabled <= 3'd1;
        4'b0111:    bytes_enabled <= 3'd2;
        4'b1111:    bytes_enabled <= 3'd3;
        default:    bytes_enabled <= bytes_enabled;
    endcase
end
end

always@ (posedge  clock_sink_clk or negedge reset_sink_reset)
if (~reset_sink_reset)
    state <= ST_0;
else 
    state <= nextstate;


always@ (*) begin
CS <= 0; SI <= 0; SCLK <= 0; f_bit_count <= 0; f_cyc_count <= 0; rd_SO <= 0; word_ak <= 0; clear_byte_c <= 0;
case (state)
ST_0:   begin
            if (enable) begin
            nextstate <= ST_1;
            CS <= 0;
            end
            else begin
            nextstate <= ST_0;
            CS <= 1;
            end
        end

ST_1:   begin
            SI <= 0;  // dont care
            SCLK <= 1;
            if (cyc_count == 10) begin
                    f_cyc_count <= 0;
                    nextstate <= ST_2;
            end
            else begin
                    f_cyc_count <= 1;
                    nextstate <= ST_1;
            end
        end

ST_2:   begin                                       ///// send command
            SI <= comm_in [7 - bit_count];
            SCLK <= 0;
            if (cyc_count == 10) begin
                    f_cyc_count <= 0;
                    nextstate <= ST_3;
            end
            else begin
                    f_cyc_count <= 1;
                    nextstate <= ST_2;
            end
        end

ST_3:   begin
            SI <= comm_in [7 - bit_count];
            SCLK <= 1;
            if (cyc_count == 10) begin
                f_cyc_count <= 0;
                f_bit_count <= 1;
                if (bit_count == 7) begin
                    nextstate <= ST_4;
                    word_ak <= 1;
                    clear_byte_c <= 1;
                end
                else begin
                    clear_byte_c <= 0;
                    nextstate = ST_2;
                    word_ak <= 0;
                end
            end
            else begin
                word_ak <= 0;
                f_bit_count <= 0;
                f_cyc_count <= 1;
                nextstate <= ST_3;
            end
        end

ST_4:   begin                                           ///// send address
            SI <= addr_in [23 - bit_count];
            SCLK <= 0;
            f_bit_count <= 0;
            if (cyc_count == 10) begin
                    f_cyc_count <= 0;
                    nextstate <= ST_5;
            end
            else begin
                    f_cyc_count <= 1;
                    nextstate <= ST_4;
            end
        end


ST_5:   begin
            SI <= addr_in [23 - bit_count];
            SCLK <= 1;
            if (cyc_count == 10) begin
                f_cyc_count <= 0;
                f_bit_count <= 1;
                if (bit_count == 23) begin
                    word_ak <= 1;
                    clear_byte_c <= 1;
                    if (wr_mode)
                    nextstate = ST_6;
                    else 
                    nextstate = ST_9;
                end
                else begin 
                    clear_byte_c <= 0;
                    nextstate = ST_4;
                    word_ak <= 0;
                end
            end
            else begin
                    word_ak <= 0;
                    f_cyc_count <= 1;
                    nextstate <= ST_5;
            end
        end

ST_6:   begin                                   /// write  
            SI <= data_in [7 - bit_count];
            SCLK <= 0;
            f_bit_count <= 0;
            if (cyc_count == 10) begin
                f_cyc_count <= 0;
                nextstate <= ST_7;
            end
            else begin
                f_cyc_count <= 1;
                nextstate <= ST_6;
            end
        end

ST_7:   begin
            SI <= data_in [7 - bit_count];      
            SCLK <= 1;
            if (cyc_count == 10) begin
                f_cyc_count <= 0;
                f_bit_count <= 1;
                if (bit_count == 7) begin
                    word_ak <= 1;
                    if (byte_count == bytes_enabled) begin
                        clear_byte_c <= 1;
                        nextstate <= ST_8;
                    end
                    else begin              
                        clear_byte_c <= 0;
                        nextstate <= ST_6;
                    end
                end
                else begin
                    clear_byte_c <= 0;
                    word_ak <= 0;
                    nextstate = ST_6;
                end
            end
            else begin
                clear_byte_c <= 0;
                word_ak <= 0;
                f_bit_count <= 0;
                f_cyc_count <= 1;
                nextstate <= ST_7;
            end
        end 

ST_8:   begin
            rd_SO <= 0;
            CS <= 1;
            if (cyc_count == 10) begin
                    f_cyc_count <= 0;
                    nextstate <= ST_0;
            end
            else begin
                    f_cyc_count <= 1;
                    nextstate <= ST_8;
            end
        end

///////     
ST_9:   begin
            rd_SO <= 0;                     // read 
            SI <= 0;
            SCLK <= 0;
            f_bit_count <= 0;
            if (cyc_count == 10) begin
                    f_cyc_count <= 0;
                    nextstate <= ST_10;
            end
            else begin
                    f_cyc_count <= 1;
                    nextstate <= ST_9;
            end
        end

ST_10:  begin
            rd_SO <= 1;
            SI <= 0;  // dont care
            SCLK <= 1;
            if (cyc_count == 10) begin
                f_cyc_count <= 0;
                f_bit_count <= 1;
                if (bit_count == 7) begin
                    word_ak <= 1;
                    if (byte_count == bytes_enabled) begin
                        clear_byte_c <= 1;
                        nextstate <= ST_11;
                    end
                    else begin              
                        clear_byte_c <= 0;
                        nextstate <= ST_9;
                    end
                end
                else begin
                    clear_byte_c <= 0;
                    word_ak <= 0;
                    nextstate = ST_9;
                end
            end
            else begin
                clear_byte_c <= 0;
                word_ak <= 0;
                f_bit_count <= 0;
                f_cyc_count <= 1;
                nextstate <= ST_10;
            end
        end


ST_11:  begin
            rd_SO <= 0;
            CS <= 1;
            if (cyc_count == 10) begin
                    f_cyc_count <= 0;
                    nextstate <= ST_0;
            end
            else begin
                    f_cyc_count <= 1;
                    nextstate <= ST_11;
            end
        end

default: begin
            CS <= 0; SI <= 0; SCLK <= 0; f_bit_count <= 0; f_cyc_count <= 0; nextstate <= ST_0;
            rd_SO <= 0; clear_byte_c <= 0;
         end
endcase
end

always@(posedge  clock_sink_clk or negedge reset_sink_reset)    begin
    if (~reset_sink_reset) begin
        av_rd7 <= 0; av_rd6 <= 0; av_rd5 <= 0; av_rd4 <= 0;
        av_rd3 <= 0;av_rd2 <= 0;av_rd1 <= 0;av_rd0 <= 0;
    end
    else if (rd_SO) begin
        av_rd7 <= av_rd7; av_rd6 <= av_rd6; av_rd5 <= av_rd5; av_rd4 <= av_rd4;
        av_rd3 <= av_rd3; av_rd2 <= av_rd2; av_rd1 <= av_rd1; av_rd0 <= av_rd0;     
        case (bit_count)
            0:  av_rd7 <= SO;
            1:  av_rd6 <= SO;
            2:  av_rd5 <= SO;
            3:  av_rd4 <= SO;
            4:  av_rd3 <= SO;
            5:  av_rd2 <= SO;
            6:  av_rd1 <= SO;
            7:  av_rd0 <= SO;
            default: begin 
                        av_rd7 <= av_rd7; av_rd6 <= av_rd6; av_rd5 <= av_rd5; av_rd4 <= av_rd4;
                        av_rd3 <= av_rd3; av_rd2 <= av_rd2; av_rd1 <= av_rd1; av_rd0 <= av_rd0;
                    end
        endcase
    end
    else if (CS && state >= 1) begin
        av_rd7 <= 0; av_rd6 <= 0; av_rd5 <= 0; av_rd4 <= 0;
        av_rd3 <= 0;av_rd2 <= 0;av_rd1 <= 0;av_rd0 <= 0; 
    end
    else begin
        av_rd7 <= av_rd7; av_rd6 <= av_rd6; av_rd5 <= av_rd5; av_rd4 <= av_rd4;
        av_rd3 <= av_rd3; av_rd2 <= av_rd2; av_rd1 <= av_rd1; av_rd0 <= av_rd0; 
    end

end     

////////////////////////////////////////////////////////////////////////////

always@(posedge  clock_sink_clk or negedge reset_sink_reset) begin      // DESASOCIAR BIT_COUNT DE CYCLE COUNTER
    if (~reset_sink_reset) 
        bit_count <= 0;
    else if (word_ak)
        bit_count <= 0; 
    else if (f_bit_count) 
        bit_count <= bit_count + 4'b1;
    else 
        bit_count <= bit_count;
end


always@(posedge  clock_sink_clk or negedge reset_sink_reset) begin
    if (~reset_sink_reset) 
        cyc_count <= 0;
    else if (f_cyc_count)
        cyc_count <= cyc_count + 4'b1;
    else 
        cyc_count <= 0;
end

always@(posedge  clock_sink_clk or negedge reset_sink_reset) begin
    if (~reset_sink_reset) 
        byte_count <= 0;
    else if (CS && state >= 1)
        byte_count <= 0;    
    else if (clear_byte_c)
        byte_count <= 0;    
    else if (word_ak)
        byte_count <= byte_count + 4'b1;
    else 
        byte_count <= byte_count;       
end     

//////////////// Controls enable from write and read /////////////////////

always@(posedge  clock_sink_clk or negedge reset_sink_reset) begin
    if (~reset_sink_reset)
        enable <= 0;
    else if (avalon_slave_write || avalon_slave_read)
        enable <= 1;
    else 
        enable <= 0;
end     

////// controls write vs read order, with priority write /////////////////

always@ (posedge  clock_sink_clk or negedge reset_sink_reset) begin
    if (~reset_sink_reset)
        wr_mode <= 0;
    else if (avalon_slave_write)
        wr_mode <= 1;
    else if (CS && state >= 1) 
        wr_mode <= 0;
    else 
        wr_mode <= wr_mode;
end     
///////////////////////////////////////////////////////////////////////

always@(posedge  clock_sink_clk or negedge reset_sink_reset) begin    
    if (~reset_sink_reset)
        comm_in <= rd_comm;
    else if (avalon_slave_write)             
        comm_in <= wr_comm;
    else if (avalon_slave_read)
        comm_in <= rd_comm;
    else 
        comm_in <= comm_in;
end

always@(posedge  clock_sink_clk or negedge reset_sink_reset) begin    
    if (~reset_sink_reset) 
        addr_in <= 0;
    else if (avalon_slave_write || avalon_slave_read )             
        addr_in <= avalon_slave_address;
    else  
        addr_in <= addr_in;
end 



always@(posedge  clock_sink_clk or negedge reset_sink_reset) begin    
    if (~reset_sink_reset) 
        av_wrdata <= 0;
    else if (avalon_slave_write || avalon_slave_read )             
        av_wrdata <= avalon_slave_writedata;
    else  
        av_wrdata <= av_wrdata;
end



always@(posedge  clock_sink_clk or negedge reset_sink_reset) begin    
    if (~reset_sink_reset) 
        data_in <= avalon_slave_writedata [7:0];
    else
    case (byte_count)              
        0:  data_in <= av_wrdata [7:0];
        1:  data_in <= av_wrdata[15:8];
        2:  data_in <= av_wrdata [23:16];
        3:  data_in <= av_wrdata [31:24];
        default: data_in <= av_wrdata [7:0];
    endcase

end 



///////// Gather all 4 bytes in 1 register ////////////////////////

always@(posedge  clock_sink_clk or negedge reset_sink_reset)    begin
    if (~reset_sink_reset) begin
        av_rd_byte1 <= 0; av_rd_byte2 <= 0; av_rd_byte3 <= 0; av_rd_byte4 <= 0;
    end
    else if (clear_byte_c && state >= ST_10) begin
        av_rd_byte1 <= av_rd_byte1; av_rd_byte2 <= av_rd_byte2; av_rd_byte3 <= av_rd_byte3; av_rd_byte4 <= av_rd_byte4;
        case (byte_count)
            0:  av_rd_byte1 <= av_rd_buff;
            1:  av_rd_byte2 <= av_rd_buff;
            2:  av_rd_byte3 <= av_rd_buff;
            3:  av_rd_byte4 <= av_rd_buff;
            default: begin 
                        av_rd7 <= av_rd7; av_rd6 <= av_rd6; av_rd5 <= av_rd5; av_rd4 <= av_rd4;
                        av_rd3 <= av_rd3; av_rd2 <= av_rd2; av_rd1 <= av_rd1; av_rd0 <= av_rd0;
                    end
        endcase
    end
    else if (CS && state >= 1) begin
        av_rd_byte1 <= 0; av_rd_byte2 <= 0; av_rd_byte3 <= 0; av_rd_byte4 <= 0;
    end
end


endmodule

The top module is this
       module FLASH_CTL_TOP (

        input   wire    sys_rst,           //   reset_sink.reset
        input   wire    sys_clk,             // clock_sink_1.clk

    //////////////// chip interface ///////////////////
        input wire SO,  
        output wire SI,
        output wire CS,
        output wire WP,
        output wire HOLD,
        output wire SCLK ,
        output reg led
    );


        reg [23:0]  avalon_slave_address;// avalon_slave.address    ?????????????????????????
        reg [3:0]   avalon_slave_byteenable;    //             .byteenable
        reg avalon_slave_read;          //             .read
        reg avalon_slave_write;         //             .write
        reg [31:0]  avalon_slave_writedata;     //             .writedata
        reg [14:0] tb_count;

        wire [31:0] avalon_slave_readdata;      //             .readdata
        wire avalon_slave_readdatavalid; //             .readdatavalid
        wire avalon_slave_waitrequest;   //             .waitrequest
        wire debugaccess, burstcount;

        assign burstcount = 0;
        assign debugaccess = 0;

        reg [31:0] led_counter;






/*
    flash_qsys u0  (
        .clk_clk             (sys_clk),             //   clk.clk
        .reset_reset_n       (sys_rst),       // reset.reset_n

        .end_cs              (CS),              //   end.cs
        .end_si              (SI),              //      .si
        .end_so              (SO),              //      .so
        .end_wp              (WP),              //      .wp
        .end_sclk            (SCLK),            //      .sclk
        .end_hold            (HOLD),            //      .hold

        .sobus_waitrequest   (avalon_slave_waitrequest),   // sobus.waitrequest
        .sobus_readdata      (avalon_slave_readdata),      //      .readdata
        .sobus_readdatavalid (avalon_slave_readdatavalid), //      .readdatavalid

        .sobus_burstcount    (burstcount),    //      .burstcount
        .sobus_writedata     (avalon_slave_writedata),     //      .writedata
        .sobus_address       (avalon_slave_address),       //      .address
        .sobus_write         (avalon_slave_write),         //      .write
        .sobus_read          (avalon_slave_read),          //      .read
        .sobus_byteenable    (avalon_slave_byteenable),    //      .byteenable
        .sobus_debugaccess   (debugaccess)    //      .debugaccess
    );

*/


FLASH_CTL FLASH_CTL_inst1 (
.SO (SO),
.SI (SI),
.CS(CS),
.WP(WP),
.HOLD(HOLD),
.SCLK(SCLK),

.avalon_slave_address (avalon_slave_address),
.avalon_slave_byteenable (avalon_slave_byteenable),   
.avalon_slave_read (avalon_slave_read),          
.avalon_slave_write (avalon_slave_write ),         
.avalon_slave_writedata (avalon_slave_writedata),    
.reset_sink_reset (sys_rst),          
.clock_sink_clk (sys_clk),            

.avalon_slave_readdata (avalon_slave_readdata),      
.avalon_slave_readdatavalid (avalon_slave_readdatavalid), 
.avalon_slave_waitrequest (avalon_slave_waitrequest)   

);  


always@(posedge sys_clk or negedge sys_rst) begin
    if (~sys_rst) begin
        led <= 1;
        led_counter <= 0;
    end
    else if (led_counter == 31'd100_000_000) begin
        led <= 0;
        led_counter <= led_counter + 16'b1;;
    end
    else if (led_counter == 31'd200_000_000) begin
        led <= 1;
        led_counter <= 0;
    end

    else begin
        led <= led; 
        led_counter <= led_counter + 16'b1;
    end
end



always@(posedge sys_clk  or negedge sys_rst) begin
    if (~sys_rst) begin
        avalon_slave_read <= 0;
        avalon_slave_write <= 0;
        avalon_slave_address <= 0;
        avalon_slave_writedata <= 0;
        avalon_slave_byteenable <= 0;
    end
    else if (tb_count == 200) begin
        avalon_slave_write <= 1;
        avalon_slave_read <= 0;
        avalon_slave_address <= 24'b0000_0000_0000_0000_0000_0011;  //// 24'b0000_0000_0000_0000_0000_0011
        avalon_slave_writedata <= 32'b1010_1010_1010_0000__0000_0000_0000_0011; //8'b1000_0101
        avalon_slave_byteenable <= 4'b1111;

    end
    else if (tb_count == 2000) begin
        avalon_slave_read <= 1;
        avalon_slave_write <= 0;
        avalon_slave_address <= 24'b0000_0000_0000_0000_0000_0011; //// 24'b0000_0000_0000_0000_0000_0011
        avalon_slave_writedata <= 32'b0000_0000_0000_0000__0000_0000_0000_0000; // 8'b0000_0000
        avalon_slave_byteenable <= 4'b1111;
    end
    else begin
        avalon_slave_byteenable <= 0;
        avalon_slave_read <= 0;
        avalon_slave_write <= 0;
        avalon_slave_address <= 0;
        avalon_slave_writedata <= 0;
    end
end

always@ (posedge sys_clk or negedge sys_rst) begin
    if (~sys_rst) 
        tb_count <= 0;
    else if (tb_count == 3000)
        tb_count <= tb_count;
    else 
        tb_count <= tb_count + 15'b1;
end 





endmodule

Attachment 1.jpg
Attachment 2.jpg
The code is basically running as expected (as far as I know) as it can 
be seen in the second attached imag, but I'm receiving this "1" from the 
SO pin from the beginning of the time without changes, so I'm not able 
to pick up the "supposedly" data from SO.

any thoughts about this? Chip might be malfunctioning?
Attachment 3.jpg

Reply

Entering an e-mail address is optional. If you want to receive reply notifications by e-mail, please log in.

Rules — please read before posting

  • Post long source code as attachment, not in the text
  • Posting advertisements is forbidden.

Formatting options

  • [c]C code[/c]
  • [avrasm]AVR assembler code[/avrasm]
  • [vhdl]VHDL code[/vhdl]
  • [code]code in other languages, ASCII drawings[/code]
  • [math]formula (LaTeX syntax)[/math]




Bild automatisch verkleinern, falls nötig
Note: the original post is older than 6 months. Please don't ask any new questions in this thread, but start a new one.