Enviando señales SPI a la Memoria Flash a través del controlador verilog FPGA, pero sin recibir nada de ella, ¿por qué sucede?

1

Como proyecto escolar, quiero escribir un controlador muy simple para una memoria flash en una placa IC. El chip FPGA es Altera 5CEFA4F23C8 y el flash es MX25L3206E.

Hice un esfuerzo para producir las señales SCLK, SI y otras que el chip necesita a través de verilog, respetando el tiempo, etc. Concebí el controlador como una máquina de estados finitos que supone generar las señales SPI en orden.

He cargado el sistema en la placa pero no está recibiendo nada de SO, como pensé que haría de forma automática.

Estoy usando un módulo "similar a un banco de pruebas" que produce el control, la dirección y las señales de datos de avalon, como escritura, lectura y dirección, para una futura implementación en un protocolo de comunicación de Avalon más grande, SoC.

Estoy agregando el código que escribo para su referencia.

    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

El módulo superior es este

        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

Elcódigoseejecutabásicamentecomoseesperaba(queyosepa)comosepuedeverenlasegundaimagenadjunta,peroestoyrecibiendoeste"1" desde el pin SO desde el principio del tiempo sin cambios, así que no puedo recoger los datos "supuestamente" de SO.

¿alguna idea sobre esto? Chip podría estar funcionando mal?

    
pregunta user176257

1 respuesta

0

Me pregunto por qué su rastro no tiene señalización SI. Una memoria Flash SPI no es un dispositivo simple, necesita verificación de estado y probablemente algunos comandos de selección de modo para comenzar a operar. ¿Dónde está CS # en tus huellas? ¿Qué es el estado de HOLD #? De la hoja de datos:

  

OPERACIÓN DEL DISPOSITIVO

     

1.Antes de emitir un comando, se debe verificar el registro de estado para asegurarse de que el dispositivo esté listo para la operación prevista.

     

2.Cuando se ingresa un comando incorrecto en este dispositivo, ingresa en el modo de espera y permanece en el modo de espera hasta el siguiente flanco descendente de CS #. En   modo de espera, el pin SO del dispositivo es High-Z. El CS #   el tiempo de caída debe seguir las especificaciones de tCHCL.

     

3.Cuando se ingresa el comando correcto en este dispositivo, ingresa en modo activo y permanece en modo activo hasta el próximo aumento de CS #   borde. El tiempo de subida de CS # debe seguir las especificaciones de tCLCH.

     

4. Los datos de entrada se bloquean en el borde ascendente del reloj serial (SCLK) y los datos se desplazan en el borde descendente de SCLK. La diferencia de   El modo serie 0 y el modo 3 se muestran en la Figura 1.

     

5.Para las siguientes instrucciones: RDID, RDSR, RDSCUR, READ, FAST_READ, RDSFDP, DREAD, RES y REMS, la instrucción modificada   La secuencia es seguida por una secuencia de salida de datos. Después de cualquier bit de datos   siendo desplazado, el CS # puede ser alto. Para el siguiente   instrucciones: WREN, WRDI, WRSR, SE, BE, CE, PP, RDP, DP,   ENSO, EXSO y WRSCUR, el CS # debe ir alto exactamente en el byte   límite; De lo contrario, la instrucción será rechazada y no   ejecutado.

     

6. Si bien se está realizando una operación de registro de estado de escritura, programa o borrado, se descuida el acceso a la matriz de memoria y   no afectará la operación actual del registro de estado de escritura,   Programa, Borrar

¿Qué comando estás enviando a tu chip de memoria?

    
respondido por el Ale..chenski

Lea otras preguntas en las etiquetas