SPI interface explanation based on FPGA -- flash M25P28 as an example

Keywords: sublime

flash M25P128 read operation


The content of our experiment is to read a byte of flash data. The system diagram is as follows:

The hardware and software environments used are:
Hardware: Zircon A4plus development board
Software: quartus II 13.1
From the technical manual, we can get the following information:

From the above information, we can get:
1. A read instruction operation can read the entire flash data.
2. The time sequence used is still SPI time sequence

Sequence diagram design

In the same way, we also change the erasure sequence of flash to some extent as follows:

The time sequence picture here is a little disorderly, but I believe that students can learn with the foundation in front. Next, go straight to the code.

The writing of flash read module

The tradition here doesn't talk nonsense. It goes directly to the code:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : nnzhang1996@foxmail.com
// Website      : 
// Module Name  : flash_read.v
// Create Time  : 2020-01-09 12:52:26
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module flash_read(
    input                   sclk            ,
    input                   rst_n           ,
    input                   key_flag        ,
    output  reg             cs_n            ,
    output  reg             sck             ,
    output  reg             sdi             ,
    input                   sdo             ,
    output  reg     [ 7:0]  data_out        , 
    output  reg             data_flag       
);

 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
parameter   READ_INST   =   8'h03           ;
parameter   READ_ADDR   =   24'h00_03_21    ;

reg                 [ 4:0]  cnt_32          ;
reg                 [ 2:0]  cnt_state       ;
reg                 [ 1:0]  cnt_4           ;
reg                 [ 4:0]  bit_cnt         ;


 
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        cs_n                <=      1'b1;
    else if(key_flag == 1'b1)
        cs_n                <=      1'b0;
    else if(cnt_32 == 'd31 && cnt_state == 'd6)
        cs_n                <=      1'b1;
    else
        cs_n                <=      cs_n;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        cnt_32              <=      5'd0;
    else if(cnt_32 == 'd31)
        cnt_32              <=      5'd0;
    else if(cs_n == 1'b0)
        cnt_32              <=      cnt_32 + 1'b1; 
    else
        cnt_32              <=      5'd0;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        cnt_state           <=      3'd0;
    else if(cnt_state == 'd6 && cnt_32 == 'd31)
        cnt_state           <=      3'd0;
    else if(cnt_32 == 'd31)
        cnt_state           <=      cnt_state + 1'b1;
    else
        cnt_state           <=      cnt_state;
        
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        cnt_4               <=      2'd0;
    else if(cnt_state >= 'd1 && cnt_state <= 'd5) 
        cnt_4               <=      cnt_4 + 1'b1;
    else
        cnt_4               <=      2'd0;
        
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        sck                 <=      1'b0;
    else if(cnt_4 == 'd0)
        sck                 <=      1'b0;
    else if(cnt_4 == 'd2)
        sck                 <=      1'b1;
    else
        sck                 <=      sck;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        sdi                 <=      1'b0;
    else if(cnt_32 == 'd31 && cnt_state == 'd4)
        sdi                 <=      1'b0;
    else if(cnt_4 == 'd0 && cnt_state == 'd1)
        sdi                 <=     READ_INST[7-bit_cnt];  
    else if(cnt_4 == 'd0 &&cnt_state >= 3'd2 && cnt_state <= 3'd4)
        sdi                 <=     READ_ADDR[23-bit_cnt];
    else
        sdi                 <=      sdi;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        bit_cnt             <=      5'd0;
    else if(cnt_32 == 'd30 && cnt_state == 3'd1)
        bit_cnt             <=      5'd0;
    else if(cnt_32 == 'd30 && cnt_state == 3'd4)
        bit_cnt             <=      5'd0;
    else if(cnt_4 == 'd2 && cnt_state >= 3'd1 && cnt_state <= 3'd4)
        bit_cnt             <=      bit_cnt + 1'b1; 
    else
        bit_cnt             <=      bit_cnt;
        
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        data_out            <=      8'd0; 
    else if(cnt_4 == 'd2 && cnt_state == 3'd5)
        data_out            <=      {data_out[6:0],sdo};
    else if(cnt_32 == 'd31 && cnt_state == 'd6)
        data_out            <=      8'd0;
    else 
        data_out            <=      data_out;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        data_flag           <=      1'b0;
    else if(cnt_state == 'd5 && cnt_32 == 'd30)
        data_flag           <=      1'b1;
    else
        data_flag           <=      1'b0;

endmodule

Combined with the timing chart and manual information, I believe you can easily understand the above code writing.

Code of flash read test module

In order to facilitate the students to debug the code, the test code of the module is directly given here:

`timescale 1ns / 1ps
`define     CLOCK   20
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : nnzhang1996@foxmail.com
// Website      : 
// Module Name  : flash_earse_tb.v
// Create Time  : 2020-01-08 19:57:13
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module flash_read_tb();

reg                     sclk             ;
reg                     rst_n            ;
reg                     key_flag         ;
wire                    cs_n             ;
wire                    sck              ;
wire                    sdi              ;
wire            [ 7:0]  data_out         ; 
wire                    data_flag        ;

initial begin
    sclk                <=          1'b0;
    rst_n               <=          1'b0;
    key_flag            <=          1'b0;
    #(100*`CLOCK)
    rst_n               <=          1'b1;
    #(100*`CLOCK)
    key_flag            <=          1'b1;
    #(`CLOCK)
    key_flag            <=          1'b0;
    #(1000*`CLOCK)
    key_flag            <=          1'b1;
    #(`CLOCK)
    key_flag            <=          1'b0;
end
always      #(`CLOCK/2)     sclk    <=      ~sclk;

flash_read flash_read_inst(
    .sclk               (sclk               ),
    .rst_n              (rst_n              ),
    .key_flag           (key_flag           ),
    .cs_n               (cs_n               ),
    .sck                (sck                ),
    .sdi                (sdi                ),
    .sdo                (1'b1               ),
    .data_out           (data_out           ), 
    .data_flag          (data_flag          )
);

endmodule

Code for other modules

In order to facilitate the students to use the code directly, here we copy all the codes as follows, and the whole project can also be taken by the group itself:
key module code:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : nnzhang1996@foxmail.com
// Website      : 
// Module Name  : key.v
// Create Time  : 2020-01-05 13:49:36
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module key(
    input                       sclk            ,
    input                       rst_n           ,
    input                       key             ,
    output  reg                 key_o       
);
 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
parameter       IDLE        =       4'b0001     ;    
parameter       S1          =       4'b0010     ;
parameter       S2          =       4'b0100     ;
parameter       S3          =       4'b1000     ;

reg                 [ 3:0]      state           ;
reg                 [ 9:0]      cnt             ;
reg                             key_r1          ;
reg                             key_r2          ;
reg                             key_r3          ;
reg                             nege_flag       ;
reg                             pose_flag       ;
 
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/
always @(posedge sclk)
    key_r1          <=      key;

always @(posedge sclk)
    key_r2          <=      key_r1;

always @(posedge sclk)
    key_r3          <=      key_r2;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        nege_flag       <=      1'b0;
    else if(key_r3 == 1'b1 && key_r2 == 1'b0)
        nege_flag       <=      1'b1;
    else
        nege_flag       <=      1'b0;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        pose_flag       <=      1'b0;
    else if(key_r3 == 1'b0 && key_r2 == 1'b1) 
        pose_flag       <=      1'b1;
    else
        pose_flag       <=      1'b0;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        state           <=      IDLE;
    else case(state)
        IDLE    :   if(nege_flag == 1'b1)
                        state           <=      S1;
                    else
                        state           <=      IDLE;                        
        S1      :   if(cnt == 10'd999)
                        state           <=      S2;
                    else if(pose_flag == 1'b1)
                        state           <=      IDLE;
                    else
                        state           <=      S1;                        
        S2      :   if(pose_flag == 1'b1)
                        state           <=      S3;
                    else
                        state           <=      S2;                        
        S3      :   if(cnt == 10'd999)
                        state           <=      IDLE;
                    else if(nege_flag == 1'b1)
                        state           <=      S2;
                    else
                        state           <=      S3;
                        
        default :   state           <=      IDLE;
    endcase

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        cnt             <=      10'd0;
    else if(state != S1 && state != S3)
        cnt             <=      10'd0;
    else
        cnt             <=      cnt + 1'b1;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        key_o           <=      1'b0;
    else if(state == S1 && cnt == 10'd999) 
        key_o           <=      1'b1;
    else
        key_o           <=      1'b0;

endmodule

top module:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : nnzhang1996@foxmail.com
// Website      : 
// Module Name  : top.v
// Create Time  : 2020-01-08 21:18:52
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module top(
    input                   sclk            ,
    input                   rst_n           ,
    input                   key             ,
    output  wire            cs_n            ,
    output  wire            sck             ,
    output  wire            sdi             ,
    input                   sdo             ,
    output  reg     [ 7:0]  led
);
 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
wire                        key_flag        ;
wire                [ 7:0]  data_out        ; 
wire                        data_flag       ;

 
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        led             <=      8'd0;
    else if(data_flag == 1'b1)
        led             <=      data_out;
    else
        led             <=      led;

key key_inst(
    .sclk                   (sclk                   ),
    .rst_n                  (rst_n                  ),
    .key                    (~key                   ),
    .key_o                  (key_flag               )
);

flash_read flash_read_inst(
    .sclk                   (sclk                   ),
    .rst_n                  (rst_n                  ),
    .key_flag               (key_flag               ),
    .cs_n                   (cs_n                   ),
    .sck                    (sck                    ),
    .sdi                    (sdi                    ),
	.sdo                    (sdo                    ),
    .data_out               (data_out               ), 
    .data_flag              (data_flag              )
);

endmodule 

experimental result

The experimental result here is that we read the data written in flash in the previous article and display it on the led. The experimental results prove the correctness of our flash reading and writing operations.

Concluding remarks

Creation is not easy. Students who think the article is helpful can collect some praise and support. (projects are also in the group) students who have any opinions on the article or need to communicate further can join the following group:

Published 11 original articles, won praise 2, visitors 318
Private letter follow

Posted by dcace on Fri, 10 Jan 2020 22:10:46 -0800