当前位置:   article > 正文

FPGA模块——SPI接口设计_fpga构建spi接口

fpga构建spi接口

SPI基础代码模版

user输入: valid信号 , 要输出的值
输出 :一个周期读valid , 读到的值
在这里插入图片描述

module spi_drive#(
    parameter                           P_DATA_WIDTH        = 8 ,
                                        P_READ_DATA_WIDTH   = 8 , 
                                        P_CPOL              = 0 ,
                                        P_CPHL              = 0 
)(                  
    input                               i_clk               ,
    input                               i_rst               ,

    output                              o_spi_clk           ,
    output                              o_spi_cs            ,
    output                              o_spi_mosi          ,
    input                               i_spi_miso          ,

    input   [P_DATA_WIDTH - 1 :0]       i_user_data         ,
    input                               i_user_valid        ,
    output                              o_user_ready        ,

    output  [P_READ_DATA_WIDTH - 1:0]   o_user_read_data    ,
    output                              o_user_read_valid   
);

reg                                 ro_spi_clk          ;
reg                                 ro_spi_cs           ;
reg                                 ro_spi_mosi         ;
reg                                 ro_user_ready       ;
reg  [P_DATA_WIDTH - 1:0]           r_user_data         ;
reg                                 r_run               ;
reg  [15:0]                         r_cnt               ;
reg                                 r_spi_cnt           ;
reg  [P_READ_DATA_WIDTH - 1:0]      ro_user_read_data   ;
reg                                 ro_user_read_valid  ;
reg                                 r_run_1d            ;
/***************wire******************/
wire                                w_user_active       ;
wire                                w_run_negedge       ;



/***************assign****************/
assign o_spi_clk            = ro_spi_clk            ;
assign o_spi_cs             = ro_spi_cs             ;
assign o_spi_mosi           = ro_spi_mosi           ;
assign o_user_ready         = ro_user_ready         ;
assign o_user_read_data     = ro_user_read_data     ;
assign o_user_read_valid    = ro_user_read_valid    ;
assign w_run_negedge        = !r_run & r_run_1d     ;

/***************always****************/
assign w_user_active = i_user_valid & o_user_ready;

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_user_ready <='d1;
    else if(w_user_active)
        ro_user_ready <= 'd0;
    else if(w_run_negedge)
        ro_user_ready <= 'd1;
    else 
        ro_user_ready <= ro_user_ready;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_user_data <= 'd0;
    else if(w_user_active)
        r_user_data <= i_user_data;
    else if(r_spi_cnt)
        r_user_data <= r_user_data << 1;
    else 
        r_user_data <= r_user_data;    
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_run <= 'd0;
    else if(r_spi_cnt && r_cnt == 7)
        r_run <= 'd0;
    else if(w_user_active)
        r_run <= 'd1;
    else 
        r_run <= r_run;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_run_1d <= 'd0;
    else
        r_run_1d <= r_run;
end
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_cnt <= 'd0;
    else if(r_spi_cnt && r_cnt == 7)
        r_cnt <= 'd0;
    else if(r_spi_cnt)
        r_cnt <= r_cnt + 1;
    else 
        r_cnt <= r_cnt;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_spi_cnt <= 'd0;
    else if(r_run)
        r_spi_cnt <= r_spi_cnt + 1;
    else 
        r_spi_cnt <= 'd0;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_spi_clk <= P_CPOL;
    else if(r_run)
        ro_spi_clk <= ~ro_spi_clk;
    else 
        ro_spi_clk <= P_CPOL; 
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_spi_cs <= 'd1;
    else if(w_user_active)
        ro_spi_cs <= 'd0;
    else if(!r_run)
        ro_spi_cs <= 'd1;
    else 
        ro_spi_cs <= ro_spi_cs;
end


always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_spi_mosi <= 'd0;
    else if(w_user_active)
        ro_spi_mosi <= i_user_data[P_DATA_WIDTH - 1];
    else if(r_spi_cnt)
        ro_spi_mosi <= r_user_data[P_DATA_WIDTH - 2];
    else 
        ro_spi_mosi <= ro_spi_mosi;
end     

always@(posedge ro_spi_clk,posedge i_rst)
begin
    if(i_rst)
        ro_user_read_data <= 'd0;
    
    else
        ro_user_read_data <= {ro_user_read_data[P_DATA_WIDTH - 2 : 0],i_spi_miso};
    
end

always@(posedge i_clk,posedge i_rst) 
begin
    if(i_rst)
        ro_user_read_valid <= 'd0;
    else if(r_spi_cnt && r_cnt == 7)
        ro_user_read_valid <= 'd1;
    else 
        ro_user_read_valid <= 'd0;
end

endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173

1. SPI协议与芯片交互接口

实际上就是加入了(芯片命令cmd + 寄存器地址) 的数据。读写操作的位数可以由spi控制器来控制,用于完成各种spi协议芯片的读写任务。

读数据
在这里插入图片描述

写数据
在这里插入图片描述

module spi_drive#(
    parameter                           P_DATA_WIDTH        = 8 ,
                                        P_OP_LEN            = 32,
                                        P_READ_DATA_WIDTH   = 8 , 
                                        P_CPOL              = 0 ,
                                        P_CPHL              = 0 
)(                  
    input                               i_clk               ,//系统时钟
    input                               i_rst               ,//复位
    
    //spi驱动
    output                              o_spi_clk           ,//spi的clk
    output                              o_spi_cs            ,//spi的片选
    output                              o_spi_mosi          ,//spi的主机输出
    input                               i_spi_miso          ,//spi的从机输入
    
    //操作通道
    input   [P_OP_LEN - 1 :0]           i_user_op_data      ,//操作数据(命令8bit+地址24bit)
    input   [1 :0]                      i_user_op_type      ,//操作类型(读、写、指令)
    input   [15:0]                      i_user_op_len       ,//操作数据的长 32  或   8
    input   [15:0]                      i_user_clk_len      ,//时钟周期
    //握手信号
    input                               i_user_op_valid     ,//用户的有效信号
    output                              o_user_op_ready     ,//用户的准备信号
    //与上层交互通道
    input   [P_DATA_WIDTH - 1 :0]       i_user_write_data   ,//写的数据
    output                              o_user_write_req    ,//写数据请求
    
    //输出结果通道
    output  [P_READ_DATA_WIDTH - 1:0]   o_user_read_data    ,//读到的数据
    output                              o_user_read_valid    //读数据有效
);


//3个状态:  命令/读/写
/***************parameter*************/
localparam                              P_OP_TYPE_INS   =   0,
                                        P_OP_READ       =   1,
                                        P_OP_WRITE      =   2;


/***************reg*******************/
reg                                 ro_spi_clk          ;
reg                                 ro_spi_cs           ;
reg                                 ro_spi_mosi         ;
reg                                 ro_user_ready       ;
reg  [P_OP_LEN - 1:0]               r_user_op_data      ;
reg  [1 :0]                         r_user_op_type      ;
reg  [15:0]                         r_user_op_len       ;
reg  [15:0]                         r_user_clk_len      ;
reg  [P_DATA_WIDTH - 1:0]           r_user_data         ;
reg                                 r_run               ;
reg  [15:0]                         r_cnt               ;
reg                                 r_spi_cnt           ;
reg  [P_READ_DATA_WIDTH - 1:0]      ro_user_read_data   ;
reg                                 ro_user_read_valid  ;
reg                                 r_run_1d            ;
reg                                 ro_user_write_req   ;
reg                                 ro_user_write_req_1d;
reg  [15:0]                         r_write_cnt         ;
reg  [P_DATA_WIDTH - 1 :0]          r_user_write_data   ;
reg  [15:0]                          r_read_cnt          ;

/***************wire******************/
wire                                w_user_active       ;
wire                                w_run_negedge       ;

/***************component*************/

/***************assign****************/
assign o_spi_clk            = ro_spi_clk            ;
assign o_spi_cs             = ro_spi_cs             ;
assign o_spi_mosi           = ro_spi_mosi           ;
assign o_user_op_ready      = ro_user_ready         ;
assign o_user_read_data     = ro_user_read_data     ;
assign o_user_read_valid    = ro_user_read_valid    ;
assign w_run_negedge        = !r_run & r_run_1d     ;
assign o_user_write_req     = ro_user_write_req     ;

/***************always****************/
assign w_user_active = i_user_op_valid & o_user_op_ready;

//控制准备信号
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_user_ready <='d1;
    else if(w_user_active)
        ro_user_ready <= 'd0;
    else if(w_run_negedge)
        ro_user_ready <= 'd1;
    else 
        ro_user_ready <= ro_user_ready;
end

//操作总线,锁存USER的数据指令
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        r_user_op_type <= 'd0;
        r_user_op_len  <= 'd0;
        r_user_clk_len <= 'd0;
    end else if(w_user_active) begin
        r_user_op_type <= i_user_op_type;
        r_user_op_len  <= i_user_op_len ;
        r_user_clk_len <= i_user_clk_len;
    end else begin 
        r_user_op_type <= r_user_op_type;
        r_user_op_len  <= r_user_op_len ;
        r_user_clk_len <= r_user_clk_len;
    end   
end

//激活后, 锁存操作数据
//下降沿, spi数据并转串
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_user_op_data <= 'd0;
    else if(w_user_active)
        r_user_op_data <= i_user_op_data;//指令8bit + 24bit地址
    else if(r_spi_cnt)//spi输出时,并转
        r_user_op_data <= r_user_op_data << 1;
    else 
        r_user_op_data <= r_user_op_data;
end

//run总线运行标志
//下降沿+spi的clk周期到达指定值 ,停止
//激活后,运行
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_run <= 'd0;
    else if(r_spi_cnt && r_cnt == r_user_clk_len - 1)
        r_run <= 'd0;
    else if(w_user_active)
        r_run <= 'd1;
    else 
        r_run <= r_run;
end

// run 打拍 获得下降沿
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_run_1d <= 'd0;
    else
        r_run_1d <= r_run;
end

//spi时钟周期计数
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_cnt <= 'd0;
    else if(r_spi_cnt && r_cnt == r_user_clk_len - 1)
        r_cnt <= 'd0;
    else if(r_spi_cnt)
        r_cnt <= r_cnt + 1;
    else 
        r_cnt <= r_cnt;
end

//spi时钟计数,用于判断上升/下降沿
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_spi_cnt <= 'd0;
    else if(r_run)
        r_spi_cnt <= r_spi_cnt + 1;
    else 
        r_spi_cnt <= 'd0;
end

//spi时钟信号,run就开始翻转
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_spi_clk <= P_CPOL;
    else if(r_run)
        ro_spi_clk <= ~ro_spi_clk;
    else 
        ro_spi_clk <= P_CPOL; 
end

//spi片选信号  ,激活就片选
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_spi_cs <= 'd1;
    else if(w_user_active)
        ro_spi_cs <= 'd0;
    else if(!r_run)
        ro_spi_cs <= 'd1;
    else 
        ro_spi_cs <= ro_spi_cs;
end

//spi输出引脚
//1. 输出操作数据
//2. 输出要写出去的数据
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_spi_mosi <= 'd0;
    else if(w_user_active)//输出操作数据 最高位 指令+地址
        ro_spi_mosi <= i_user_op_data[P_OP_LEN - 1];//operation
    else if(r_spi_cnt && r_cnt < r_user_op_len - 1)//依次输出操作数据次高位 
        ro_spi_mosi <= r_user_op_data[P_OP_LEN - 2];
    else if(r_user_op_type == P_OP_WRITE && r_spi_cnt)//串行输出写数据
        ro_spi_mosi <= r_user_write_data[7];
    else 
        ro_spi_mosi <= ro_spi_mosi;
end     

//
//2.(上升沿 + 周期计数器到P_OP_LEN -2  ||写数据计数==15  )   &&   写状态   
//    因为r_cnt是基于spi_clk(系统时钟/2)来计数的,!r_spi_cnt是作为i_clk时钟位置的判断   
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_user_write_req <= 'd0;
    else if(r_cnt >= r_user_clk_len - 5)
        ro_user_write_req <= 'd0;
    else if(((!r_spi_cnt && r_cnt == P_OP_LEN-2) || r_write_cnt == 15) &&  r_user_op_type == P_OP_WRITE )  
        ro_user_write_req <= 'd1;
    else 
        ro_user_write_req <= 'd0;
end

// 获得延时1个周期的写请求信号
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_user_write_req_1d <= 'd0;
    else 
        ro_user_write_req_1d <= ro_user_write_req;
end

// 1.用延时一个周期的写请求信号(此时外部数据已经更新),来锁存输入的要写的数据
// 2.spi_clk的下降沿 位移数据
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_user_write_data <= 'd0;
    else if(ro_user_write_req_1d)
        r_user_write_data <= i_user_write_data;
    else if(r_spi_cnt)
        r_user_write_data <= r_user_write_data << 1;
    else 
        r_user_write_data <= r_user_write_data;
end

//写请求后 r_write_cnt 写计数 0 ~ 15   用于下次产生写请求
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_write_cnt <= 'd0;
    else if(r_write_cnt == 15 || ro_spi_cs)
        r_write_cnt <= 'd0;
    else if(ro_user_write_req || r_write_cnt)
        r_write_cnt <= r_write_cnt + 1;
    else 
        r_write_cnt <= r_write_cnt;
end
/*--------------------------读---------------------------------*/
//完成命令+地址的指令后,读数据
always@(posedge ro_spi_clk,posedge i_rst)
begin
    if(i_rst)
        ro_user_read_data <= 'd0;
    else if(r_cnt >= r_user_op_len )
        ro_user_read_data <= {ro_user_read_data[P_READ_DATA_WIDTH - 2 : 0],i_spi_miso};
    else 
        ro_user_read_data <= ro_user_read_data;
end

// 完成了命令+地址的指令后,读计数 0 ~ 8
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_read_cnt <= 'd0;
    else if(r_read_cnt == P_READ_DATA_WIDTH || ro_spi_cs)
        r_read_cnt <= 'd0;
    else if(r_spi_cnt && r_cnt >= r_user_op_len - 0 && r_user_op_type == P_OP_READ)
        r_read_cnt <= r_read_cnt + 1;
    else 
        r_read_cnt <= r_read_cnt;
end

//读数据有效信号
always@(posedge i_clk,posedge i_rst) 
begin
    if(i_rst)
        ro_user_read_valid <= 'd0;
    else if(r_spi_cnt && r_read_cnt == P_READ_DATA_WIDTH - 1 && r_user_op_type == P_OP_READ)
        ro_user_read_valid <= 'd1;
    else 
        ro_user_read_valid <= 'd0;
end

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303

2. SPI协议的控制器(状态机)

连续读出存在FIFO中的数据
握手信号

module flash_ctrl#(
    parameter                           P_DATA_WIDTH        = 8 ,//数据位宽
                                        P_OP_LEN            = 32,//指令长度
                                        P_READ_DATA_WIDTH   = 8 ,//读数据位宽
                                        P_CPOL              = 0 ,//空闲时时钟状态
                                        P_CPHL              = 0  //采集数据时钟沿
)(
    input                               i_clk                   ,//用户时钟
    input                               i_rst                   ,//用户复位

    /*--------用户接口--------*/    
    input  [1 :0]                       i_operation_type        ,//操作类型
    input  [23:0]                       i_operation_addr        ,//操作地址
    input  [8 :0]                       i_operation_num         ,//限制用户每次最多写256字节
    input                               i_operation_valid       ,//操作握手有效
    output                              o_operation_ready       ,//操作握手准备

    input  [P_DATA_WIDTH - 1 :0]        i_write_data            ,//写数据
    input                               i_write_sop             ,//写数据-开始信号
    input                               i_write_eop             ,//写数据-结束信号
    input                               i_write_valid           ,//写数据-有效信号

    output [P_DATA_WIDTH - 1 :0]        o_read_data             ,//读数据
    output                              o_read_sop              ,//读数据-开始信号
    output                              o_read_eop              ,//读数据-结束信号
    output                              o_read_valid            ,//读数据-有效信号

    /*--------驱动接口--------*/    
    output   [P_OP_LEN - 1 :0]          o_user_op_data          ,//操作数据(指令8bit+地址24bit)
    output   [1 :0]                     o_user_op_type          ,//操作类型(读、写、指令)
    output   [15:0]                     o_user_op_len           ,//操作数据的长度32、8
    output   [15:0]                     o_user_clk_len          ,//时钟周期
    output                              o_user_op_valid         ,//用户的有效信号
    input                               i_user_op_ready         ,//用户的准备信号

    output  [P_DATA_WIDTH - 1 :0]       o_user_write_data       ,//写数据
    input                               i_user_write_req        ,//写数据请求

    input   [P_READ_DATA_WIDTH - 1:0]   i_user_read_data        ,//读数据
    input                               i_user_read_valid        //读数据有效
);

/***************function**************/

/***************parameter*************/
//用户接口操作类型
localparam                          P_TYPE_CLEAR    =   0   ,
                                    P_TYPE_WRITE    =   1   ,
                                    P_TYPE_READ     =   2   ;

//SPI总线驱动器操作类型
localparam                          P_OP_TYPE_INS   =   0,
                                    P_OP_READ       =   1,
                                    P_OP_WRITE      =   2;

//状态机状态
localparam                          P_IDLE          =   0   ,
                                    P_RUN           =   1   ,
                                    P_W_EN          =   2   ,
                                    P_W_INS         =   3   ,
                                    P_W_DATA        =   4   ,
                                    P_R_INS         =   5   ,
                                    P_R_DATA        =   6   ,
                                    P_CLEAR         =   7   ,
                                    P_BUSY          =   8   ,
                                    P_BUSY_CHECK    =   9   ,
                                    P_BUSY_WAIT     =   10  ;
/***************port******************/             

/***************mechine***************/
//状态机
reg  [7 :0]                         r_st_current        ;
reg  [7 :0]                         r_st_next           ;
reg  [7 :0]                         r_st_cnt            ;


/***************reg*******************/
reg  [1 :0]                         ri_operation_type   ;
reg  [23:0]                         ri_operation_addr   ;
reg  [8 :0]                         ri_operation_num    ;
reg  [P_DATA_WIDTH - 1 :0]          ri_write_data       ;
reg                                 ri_write_sop        ;
reg                                 ri_write_eop        ;
reg                                 ri_write_valid      ;
reg                                 r_user_ready_1d     ;
reg  [P_OP_LEN - 1 :0]              ro_user_op_data     ;
reg  [1 :0]                         ro_user_op_type     ;
reg  [15:0]                         ro_user_op_len      ;
reg  [15:0]                         ro_user_clk_len     ;
reg                                 ro_user_op_valid    ;
reg  [P_DATA_WIDTH - 1 :0]          ri_user_read_data   ;
reg                                 ri_user_read_valid  ;
reg                                 ro_operation_ready  ;
reg  [7 :0]                         ro_read_data        ;
reg                                 ro_read_sop         ;
reg                                 ro_read_eop         ;
reg                                 ro_read_valid       ;
reg                                 r_fifo_read_rden    ;
reg                                 r_fifo_read_rden_1d ;
reg                                 r_fifo_read_pos     ;
reg                                 r_fifo_read_emp_1d  ;
reg                                 r_fifo_read_wren    ;

/***************wire******************/
wire                                w_operation_active  ;
wire                                w_user_ready_pos    ;
wire                                w_spi_drive_act     ;
wire                                w_fifo_read_empty   ;
wire [7 :0]                         w_read_data         ;

/***************component*************/

//输入:用户写入想要 写进外设的数据
//输出:spi请求数据的时候,输出要写的数据
    FLASH_CTRL_FIFO_DATA FLASH_CTRL_FIFO_DATA_U0 (
    .clk      (i_clk              ),  
    .srst     (i_rst              ),  
    .din      (ri_write_data      ),  
    .wr_en    (ri_write_valid     ),  
    .rd_en    (i_user_write_req   ),  
    .dout     (o_user_write_data  ),  
    .full     (), 
    .empty    ()  
    );

//输入:spi读到的数据,写进去
//输出:用户要读取数据的时候,输出 
    FLASH_CTRL_FIFO_DATA FLASH_CTRL_FIFO_DATA_READ_U0 (
    .clk      (i_clk              ), 
    .srst     (i_rst              ), 
    .din      (ri_user_read_data  ), 
    .wr_en    (r_fifo_read_wren   ), 
    .rd_en    (r_fifo_read_rden   ), 
    .dout     (w_read_data        ), 
    .full     (),    
    .empty    (w_fifo_read_empty  )  
    );


/***************assign****************/
assign w_operation_active   = i_operation_valid & o_operation_ready ;
assign w_user_ready_pos     = r_user_ready_1d & i_user_op_ready     ;
assign o_user_op_data       = ro_user_op_data                       ;
assign o_user_op_type       = ro_user_op_type                       ;
assign o_user_op_len        = ro_user_op_len                        ;
assign o_user_clk_len       = ro_user_clk_len                       ;
assign o_user_op_valid      = ro_user_op_valid                      ;
assign o_operation_ready    = ro_operation_ready                    ;
assign w_spi_drive_act      = o_user_op_valid & i_user_op_ready     ;
// assign o_read_data          = ro_read_data                          ; 
assign o_read_sop           = ro_read_sop                           ; 
assign o_read_eop           = ro_read_eop                           ; 
assign o_read_valid         = ro_read_valid                         ; 
assign o_read_data          = ro_read_data                          ;

/***************always****************/
//状态机跳转
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_st_current <= P_IDLE;
    else
        r_st_current <= r_st_next;
end

//跳转条件
always@(*)
begin
    case(r_st_current)
        P_IDLE          : r_st_next = w_operation_active    ? P_RUN    : P_IDLE    ;                //空闲状态,用户激活时跳转
        P_RUN           : r_st_next = ri_operation_type  == P_TYPE_READ ? P_R_INS  : P_W_EN     ;   //开始运行状态机,读/写
        P_W_EN          : r_st_next = w_spi_drive_act       ? 
                                      ri_operation_type  == P_TYPE_WRITE ? P_W_INS : P_CLEAR         //判断是写数据还是擦除
                                      : P_W_EN    ;//写使能状态
        P_W_INS         : r_st_next = w_spi_drive_act       ? P_W_DATA : P_W_INS   ;                //写数据指令状态
        P_W_DATA        : r_st_next = i_user_op_ready       ? P_BUSY   : P_W_DATA  ;                //写数据
        P_R_INS         : r_st_next = w_spi_drive_act       ? P_R_DATA : P_R_INS   ;                //读数据指令状态
        P_R_DATA        : r_st_next = i_user_op_ready       ? P_BUSY   : P_R_DATA  ;                //读数据
        P_CLEAR         : r_st_next = w_spi_drive_act       ? P_BUSY   : P_CLEAR   ;                
        P_BUSY          : r_st_next = w_spi_drive_act       ? P_BUSY_CHECK : P_BUSY  ;              //读状态寄存器
        P_BUSY_CHECK    : r_st_next = ri_user_read_valid    ? 
                                      i_user_read_data[0]   ? P_BUSY_WAIT : P_IDLE  
                                      : P_BUSY_CHECK        ;                                       //根据返回的状态值,判断是否繁忙
        P_BUSY_WAIT     : r_st_next = r_st_cnt == 255       ? P_BUSY       : P_BUSY_WAIT ;          //等待255个周期,重启读忙
        default         : r_st_next = P_W_EN; 
    endcase
end  

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_st_cnt <= 'd0;
    else if(r_st_current != r_st_next)
        r_st_cnt <= 'd0;
    else 
        r_st_cnt <= r_st_cnt + 1;
end
/*--------驱动逻辑--------*/
//第三段状态机
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ro_user_op_data  <= 'd0;
        ro_user_op_type  <= 'd0;
        ro_user_op_len   <= 'd0;
        ro_user_clk_len  <= 'd0;
        ro_user_op_valid <= 'd0;
    end else if(r_st_current == P_W_EN) begin           //发送写使能指令
        ro_user_op_data  <= {8'h06,8'h00,8'h00,8'h00};
        ro_user_op_type  <= P_OP_TYPE_INS;
        ro_user_op_len   <= 8;
        ro_user_clk_len  <= 8;
        ro_user_op_valid <= 'd1;
    end else if(r_st_current == P_W_INS) begin          //发送写数据指令
        ro_user_op_data  <= {8'h02,ri_operation_addr};
        ro_user_op_type  <= P_OP_WRITE;
        ro_user_op_len   <= 32;
        ro_user_clk_len  <= 32 + 8 * ri_operation_num;
        ro_user_op_valid <= 'd1;
    end else if(r_st_current == P_R_INS) begin          //发送读数据指令
        ro_user_op_data  <= {8'h03,ri_operation_addr};
        ro_user_op_type  <= P_OP_READ;
        ro_user_op_len   <= 32;
        ro_user_clk_len  <= 32 + 8 * ri_operation_num;
        ro_user_op_valid <= 'd1;
    end else if(r_st_current == P_CLEAR) begin          //发送擦除指令
        ro_user_op_data  <= {8'h20,ri_operation_addr};
        ro_user_op_type  <= P_OP_TYPE_INS;
        ro_user_op_len   <= 32;
        ro_user_clk_len  <= 32;
        ro_user_op_valid <= 'd1;
    end else if(r_st_current == P_BUSY) begin           //发送读状态-BUSY
        ro_user_op_data  <= {8'h05,24'd0};
        ro_user_op_type  <= P_OP_READ;
        ro_user_op_len   <= 8;
        ro_user_clk_len  <= 16;
        ro_user_op_valid <= 'd1;
    end else begin
        ro_user_op_data  <= ro_user_op_data;
        ro_user_op_type  <= ro_user_op_type;
        ro_user_op_len   <= ro_user_op_len ;
        ro_user_clk_len  <= ro_user_clk_len;
        ro_user_op_valid <= 'd0;
    end
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_user_ready_1d <= 'd0;
    else 
        r_user_ready_1d <= i_user_op_ready;
end

// 锁存读到的数据和有效信号
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_user_read_data  <= 'd0;
        ri_user_read_valid <= 'd0;
    end else begin
        ri_user_read_data  <= i_user_read_data  ;
        ri_user_read_valid <= i_user_read_valid ;
    end
end

/*--------用户逻辑--------*/
//握手激活,开始操作
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_operation_type <= 'd0;
        ri_operation_addr <= 'd0;
        ri_operation_num  <= 'd0;
    end else if(w_operation_active) begin
        ri_operation_type <= i_operation_type;
        ri_operation_addr <= i_operation_addr;
        ri_operation_num  <= i_operation_num ;
    end else  begin
        ri_operation_type <= ri_operation_type;
        ri_operation_addr <= ri_operation_addr;
        ri_operation_num  <= ri_operation_num ;
    end
end

//激活拉低准备信号
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_operation_ready <= 'd1;
    else if(r_st_next == P_IDLE)
        ro_operation_ready <= 'd1;
    else if(w_operation_active)   
        ro_operation_ready <= 'd0;
    else 
        ro_operation_ready <= ro_operation_ready;
end

//*------------------用户写入数据存入FIFO ------------------------*/
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_write_data  <= 'd0;
        ri_write_sop   <= 'd0;
        ri_write_eop   <= 'd0;
        ri_write_valid <= 'd0;
    end else begin 
        ri_write_data  <= i_write_data ;
        ri_write_sop   <= i_write_sop  ;
        ri_write_eop   <= i_write_eop  ;
        ri_write_valid <= i_write_valid;
    end
end

/*-----------------------从FIFO中读数据---------------------------------*/
//从FIFO中读数据使能开启
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) 
        r_fifo_read_rden <= 'd0;
    else if(w_fifo_read_empty)
        r_fifo_read_rden <= 'd0;
    else if(r_st_current == P_R_DATA && r_st_next != P_R_DATA)
        r_fifo_read_rden <= 'd1;
    else 
        r_fifo_read_rden <= r_fifo_read_rden;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) 
        r_fifo_read_rden_1d <= 'd0;
    else 
        r_fifo_read_rden_1d <= r_fifo_read_rden;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_fifo_read_pos <= 'd0;
    else 
        r_fifo_read_pos <= !r_fifo_read_rden_1d && r_fifo_read_rden;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_fifo_read_emp_1d <= 'd0;
    else
        r_fifo_read_emp_1d <= w_fifo_read_empty;
end

//开始fifo数据输出
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) 
        ro_read_sop <= 'd0;
    else if(r_fifo_read_pos)
        ro_read_sop <= 'd1;
    else
        ro_read_sop <= 'd0;
end

//结束fifo数据输出
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) 
        ro_read_eop <= 'd0;
    else if(w_fifo_read_empty && !r_fifo_read_emp_1d && ro_read_valid)
        ro_read_eop <= 'd1;
    else 
        ro_read_eop <= 'd0;
end 

//fifo读有效信号指示        
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) 
        ro_read_valid <= 'd0;
    else if(ro_read_eop)
        ro_read_valid <= 'd0;
    else if(r_fifo_read_pos)
        ro_read_valid <= 'd1;
    else 
        ro_read_valid <= ro_read_valid;
end
//从FIFO中读出的数据
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_read_data <= 'd0;
    else 
        ro_read_data <= w_read_data;
end

//---------------------------将读到的数据写入FIFO------------------------------*/
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_fifo_read_wren <= 'd0;
    else if(r_st_current == P_R_DATA)
        r_fifo_read_wren <= i_user_read_valid;
    else 
        r_fifo_read_wren <= 'd0;
end
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/829514
推荐阅读
相关标签
  

闽ICP备14008679号