初级会员 
	积分 103  
        金钱 103  
       注册时间 2021-1-30 
      在线时间 68 小时 
 
 
 
 
10 金钱
 本帖最后由 LJY344500 于 2021-3-13 16:43 编辑   
 
我看别的板子上spi flash的全擦除实验试着自己改一下,编译都没有问题,接到电脑上后串口助手不会显示数据,求大佬指点一下哪里出问题了 ,我把文件上传了,救救孩子 
 
顶层模块:  
module  spi 
( 
    input   wire    sys_clk     ,   //系统时钟,频率50MHz 
    input   wire    sys_rst_n   ,   //复位信号,低电平有效 
    input   wire    pi_key      ,   //按键输入信号 
 
 
    output  wire    txd            //输出 
); 
 
//********************************************************************// 
//****************** Parameter and Internal Signal *******************// 
//********************************************************************// 
//parameter define 
parameter   CNT_MAX =   20'd999_999;    //计数器计数最大值 
parameter   UART_BPS    =   14'd9600        ,   //比特率 
            CLK_FREQ    =   26'd50_000_000  ;   //时钟频率 
//wire  define 
wire         po_key  ; 
wire [7:0]   mosi_w  ; 
wire         sck_w  ; 
wire         cs_n_w ; 
//********************************************************************// 
//*************************** Instantiation **************************// 
//********************************************************************// 
//------------- key_filter_inst ------------- 
key_filter 
#( 
    .CNT_MAX    (CNT_MAX    )   //计数器计数最大值 
) 
key_filter_inst 
( 
    .sys_clk    (sys_clk    ),  //系统时钟,频率50MHz 
    .sys_rst_n  (sys_rst_n  ),  //复位信号,低电平有效 
    .key_in     (pi_key     ),  //按键输入信号 
 
    .key_flag   (po_key     )   //消抖后信号 
); 
 
//------------- flash_be_ctrl_inst ------------- 
master     master_inst 
( 
 
    .sys_clk    (sys_clk    ),  //系统时钟,频率50MHz 
    .sys_rst_n  (sys_rst_n  ),  //复位信号,低电平有效 
    .key        (po_key     ),  //按键输入信号 
 
    .sck        (sck_w        ),  //片选信号 
    .cs_n       (cs_n_w       ),  //串行时钟 
    .mosi       (mosi_w     )   //主输出从输入数据 
); 
 
slave 
#( 
    .UART_BPS    (UART_BPS  ),  //串口波特率 
    .CLK_FREQ    (CLK_FREQ  )   //时钟频率 
) 
slave_inst 
( 
    .cs_n_in    (cs_n_w       )   ,   //片选信号 
    .sck_in     (sck_w        )   ,   //串行时钟 
    .mosi_in    (mosi_w       )   ,   //主输出从输入数据 
          
         .txd        (txd          )    //输出 
); 
endmodule 
 
 
按键消抖模块:  
module  key_filter 
#( 
    parameter CNT_MAX = 20'd999_999 //计数器计数最大值 
) 
( 
    input   wire    sys_clk     ,   //系统时钟50Mhz 
    input   wire    sys_rst_n   ,   //全局复位 
    input   wire    key_in      ,   //按键输入信号 
 
    output  reg     key_flag        //key_flag为1时表示消抖后检测到按键被按下 
                                    //key_flag为0时表示没有检测到按键被按下 
); 
 
//********************************************************************// 
//****************** Parameter and Internal Signal *******************// 
//********************************************************************// 
//reg   define 
reg     [19:0]  cnt_20ms    ;   //计数器 
 
//********************************************************************// 
//***************************** Main Code ****************************// 
//********************************************************************// 
 
//cnt_20ms:如果时钟的上升沿检测到外部按键输入的值为低电平时,计数器开始计数 
always@(posedge sys_clk or negedge sys_rst_n) 
    if(sys_rst_n == 1'b0) 
        cnt_20ms <= 20'b0; 
    else    if(key_in == 1'b1) 
        cnt_20ms <= 20'b0; 
    else    if(cnt_20ms == CNT_MAX && key_in == 1'b0) 
        cnt_20ms <= cnt_20ms; 
    else 
        cnt_20ms <= cnt_20ms + 1'b1; 
 
//key_flag:当计数满20ms后产生按键有效标志位 
//且key_flag在999_999时拉高,维持一个时钟的高电平 
always@(posedge sys_clk or negedge sys_rst_n) 
    if(sys_rst_n == 1'b0) 
        key_flag <= 1'b0; 
    else    if(cnt_20ms == CNT_MAX - 1'b1) 
        key_flag <= 1'b1; 
    else 
        key_flag <= 1'b0; 
 
endmodule 
 
主机发送:  
module  master 
( 
    input   wire            sys_clk     ,   //系统时钟,频率50MHz 
    input   wire            sys_rst_n   ,   //复位信号,低电平有效 
    input   wire            key         ,   //按键输入信号 
 
    output  reg             cs_n        ,   //片选信号 
    output  reg             sck         ,   //串行时钟 
    output  reg             mosi            //主输出从输入数据 
); 
 
//********************************************************************// 
//****************** Parameter and Internal Signal *******************// 
//********************************************************************// 
 
//parameter define 
parameter   IDLE    =   2'b01 ,   //初始状态 
            WR_EN   =   4'b10 ;  //写状态 
 
parameter   WR_EN_INST  =   8'b0000_0110;   //写使能指令 
 
 
//reg   define 
reg     [1:0]   cnt_byte;   //字节计数器,0-2计数 
reg     [1:0]   state   ;   //状态机状态,2个状态 
reg     [4:0]   cnt_clk ;   //系统时钟计数器,0-31循环计数 
reg     [1:0]   cnt_sck ;   //串行时钟计数器,0-3计数 
reg     [2:0]   cnt_bit ;   //比特计数器 
 
//********************************************************************// 
//***************************** Main Code ****************************// 
//********************************************************************// 
 
//cnt_clk:系统时钟计数器,用以记录单个字节,不用修改 
always@(posedge sys_clk or  negedge sys_rst_n) 
    if(sys_rst_n == 1'b0) 
        cnt_clk  <=  5'd0; 
    else    if(state != IDLE) 
        cnt_clk  <=  cnt_clk + 1'b1; 
 
//cnt_byte:记录输出字节个数和等待时间,ok 
always@(posedge sys_clk or  negedge sys_rst_n) 
    if(sys_rst_n == 1'b0) 
        cnt_byte    <=  3'd0; 
    else    if((cnt_clk == 5'd31) && (cnt_byte == 2'd2)) 
        cnt_byte    <=  3'd0; 
    else    if(cnt_clk == 31) 
        cnt_byte    <=  cnt_byte + 1'b1; 
 
//cnt_sck:串行时钟计数器,用以生成串行时钟,ok 
always@(posedge sys_clk or  negedge sys_rst_n) 
    if(sys_rst_n == 1'b0) 
        cnt_sck <=  2'd0; 
    else    if((state == WR_EN) && (cnt_byte == 1'b1)) //处于写状态并且字节计数器等于1,开始计数 
        cnt_sck <=  cnt_sck + 1'b1; 
 
//cs_n:片选信号,ok 
always@(posedge sys_clk or  negedge sys_rst_n) 
    if(sys_rst_n == 1'b0) 
        cs_n    <=  1'b1; 
    else    if(key == 1'b1) 
        cs_n    <=  1'b0; 
    else    if((cnt_byte == 3'd2) && (cnt_clk == 5'd31) && (state == WR_EN)) 
        cs_n    <=  1'b1; 
 
 
          
//sck:输出串行时钟 
always@(posedge sys_clk or  negedge sys_rst_n) 
    if(sys_rst_n == 1'b0) 
        sck <=  1'b0; 
    else    if(cnt_sck == 2'd0) 
        sck <=  1'b0; 
    else    if(cnt_sck == 2'd2) 
        sck <=  1'b1; 
 
//cnt_bit:高低位对调,控制mosi输出 
always@(posedge sys_clk or  negedge sys_rst_n) 
    if(sys_rst_n == 1'b0) 
        cnt_bit <=  3'd0; 
    else    if(cnt_sck == 2'd2) 
        cnt_bit <=  cnt_bit + 1'b1; 
 
//state:两段式状态机第一段,状态跳转,ok 
always@(posedge sys_clk or  negedge sys_rst_n) 
    if(sys_rst_n == 1'b0) 
        state   <=  IDLE; 
    else 
    case(state) 
        IDLE:   if(key == 1'b1) 
                state   <=  WR_EN; 
        WR_EN:  if((cnt_byte == 2'd2) && (cnt_clk == 5'd31)) 
                state   <=  IDLE; 
        default:    state   <=  IDLE; 
    endcase 
 
//mosi:两段式状态机第二段,逻辑输出 
always@(posedge sys_clk or  negedge sys_rst_n) 
    if(sys_rst_n == 1'b0) 
        mosi    <=  1'b0; 
    else    if((state == WR_EN) && (cnt_byte == 2'd2)) 
        mosi    <=  1'b0; 
    else    if((state == WR_EN) && (cnt_byte == 2'd1) && (cnt_sck == 5'd0)) 
        mosi    <=  WR_EN_INST[7 - cnt_bit];    //写使能指令 
 
 
endmodule 
 
 
从机模块:  
module  slave 
#( 
    parameter   UART_BPS    =   'd9600,         //串口波特率 
    parameter   CLK_FREQ    =   'd50_000_000    //时钟频率 
) 
( 
    input               cs_n_in        ,   //片选信号 
    input               sck_in         ,   //串行时钟 
    input   wire [7:0]  mosi_in        ,   //主输出从输入数据 
          
         output  reg         txd             //输出 
); 
 
reg[3:0] Data_State = 4'd0; 
 
parameter D7_State = 4'd0; 
parameter D6_State = 4'd1; 
parameter D5_State = 4'd2; 
parameter D4_State = 4'd3; 
parameter D3_State = 4'd4; 
parameter D2_State = 4'd5; 
parameter D1_State = 4'd6; 
parameter D0_State = 4'd7; 
 
always@(posedge sck_in) 
        if(cs_n_in == 1'b1) 
            txd <= 1'b1; //空闲状态时为高电平 
        else    if(cs_n_in == 1'b0) 
            case(Data_State) 
             D7_State:begin txd <= mosi_in[0]; Data_State<= D6_State;end 
             D6_State:begin txd <= mosi_in[1]; Data_State<= D5_State;end 
             D5_State:begin txd <= mosi_in[2]; Data_State<= D4_State;end 
             D4_State:begin txd <= mosi_in[3]; Data_State<= D3_State;end 
             D3_State:begin txd <= mosi_in[4]; Data_State<= D2_State;end 
             D2_State:begin txd <= mosi_in[5]; Data_State<= D1_State;end 
             D1_State:begin txd <= mosi_in[6]; Data_State<= D0_State;end 
                                 D0_State:begin txd <= mosi_in[7]; Data_State<= D7_State;end 
                default : txd <= 1'b1; 
            endcase 
 
          
endmodule 
 
 
我来回答