• FPGA project : flash_continue_write


    本实验学习了通过spi通信协议,驱动flash;完成连续写操作。

    连续写:

    本质上还是页编程指令,两种连续写的方式:

    1,每次只写1byte的数据。

    2,每次写满1页数据,计算剩余数据够不够写满1页,并计算地址。

    本实验采取方案一。

    模块框图:

    状态机: 

     时序图:

    代码:

    只放spi模块。 

    1. module spi (
    2. input wire sys_clk ,
    3. input wire sys_rst_n ,
    4. input wire key_flag ,
    5. input wire miso ,
    6. output reg cs_n ,
    7. output reg sck ,
    8. output reg mosi ,
    9. output reg po_flag ,
    10. output wire [7:0] po_data
    11. );
    12. // localparam define 一般状态机的状态定义用局部参数就可以。
    13. localparam IDLE = 4'b0001 ,
    14. INSTRUCT = 4'b0010 ,
    15. READ = 4'b0100 ,
    16. SEND = 4'b1000 ;
    17. // parameter define 指令,计数器最大值,用全局参数定义。
    18. parameter COMD_REA = 8'h03 , // comd_read
    19. ADDR_SEC = 8'h00 , // address_secter 扇区地址
    20. ADDR_PAG = 8'h00 , // address_page 页地址(行地址)
    21. ADDR_BYT = 8'hc8 , // assress_byte 字节地址
    22. NUM_COMD = 4'd4 ; // 用来记录在指令状态传递指令和地址byte数量
    23. parameter CNT_MAX_BYTE = 11'd260 , // 4 + 要读出的数据。例如: 4 + 256
    24. CNT_MAX_SEND = 20'd53000 ;
    25. // reg signal define
    26. reg [3:0] state_c ;
    27. reg [3:0] state_n ;
    28. reg cnt_20_ns ;
    29. reg [2:0] cnt_bit ;
    30. reg [10:0] cnt_byte ;
    31. reg flag_b ; // flag_byte
    32. reg flagBreg ;
    33. reg flag_R_S ; // flag_byte
    34. reg flag_RSr ;
    35. reg [7:0] datInFifo ; // data_in_fifo
    36. reg flag_data ; // flag_data 采样标志信号
    37. reg flaInFifo ; // flag_in_fifo
    38. reg [19:0] cnt_send ; // uart_tx模块发送1byte数据的等待时间。
    39. reg flaSenEnd ; // 计数器cnt_send计数到CNT_MAX_SEND - 2 拉高一个时钟周期,
    40. reg flag_out_fifo_reg ;
    41. // wire signal define
    42. wire empty ;
    43. wire full ;
    44. wire flaOutFif ; // flag_out_fifo
    45. wire [9:0] usedw ; // fifo中存储的数据量
    46. wire IDLEtoINSTRUCT ;
    47. wire INSTRUCTto_READ ;
    48. wire READtoSEND ;
    49. wire SENDtoIDLE ;
    50. /**********************************************************************/
    51. // // reg signal describe
    52. /*******状态机采用三段式描述*******/
    53. // reg [3:0] state_c ;
    54. // reg [3:0] state_n ;
    55. always @(posedge sys_clk or negedge sys_rst_n) begin
    56. if(~sys_rst_n)
    57. state_c <= IDLE ;
    58. else
    59. state_c <= state_n ;
    60. end
    61. always @(*) begin
    62. case (state_c)
    63. IDLE : if(IDLEtoINSTRUCT)
    64. state_n <= INSTRUCT ;
    65. else
    66. state_n <= IDLE ;
    67. INSTRUCT : if(INSTRUCTto_READ)
    68. state_n <= READ ;
    69. else
    70. state_n <= INSTRUCT ;
    71. READ : if(READtoSEND)
    72. state_n <= SEND ;
    73. else
    74. state_n <= READ ;
    75. SEND : if(SENDtoIDLE)
    76. state_n <= IDLE ;
    77. else
    78. state_n <= SEND ;
    79. default: state_n <= IDLE ;
    80. endcase
    81. end
    82. assign IDLEtoINSTRUCT = (state_c == IDLE ) && (key_flag) ;
    83. assign INSTRUCTto_READ = (state_c == INSTRUCT) && (flagBreg) ; // 指令的的最后1byte发送完毕
    84. assign READtoSEND = (state_c == READ ) && (flag_RSr) ; // 读完想要的最后1byte
    85. assign SENDtoIDLE = (state_c == SEND ) && (flaSenEnd && empty) ;
    86. // reg cnt_20_ns ;
    87. always @(posedge sys_clk or negedge sys_rst_n) begin
    88. if(~sys_rst_n)
    89. cnt_20_ns <= 1'b0 ;
    90. else if(state_c == INSTRUCT || state_c == READ)
    91. cnt_20_ns <= cnt_20_ns + 1'b1 ;
    92. else if(state_c != INSTRUCT || state_c != READ)
    93. cnt_20_ns <= 1'b0 ;
    94. else
    95. cnt_20_ns <= 1'b0 ;
    96. end
    97. // reg [2:0] cnt_bit ;
    98. always @(posedge sys_clk or negedge sys_rst_n) begin
    99. if(~sys_rst_n)
    100. cnt_bit <=3'd0 ;
    101. else
    102. case (state_c)
    103. IDLE : cnt_bit <=3'd0 ;
    104. INSTRUCT: if(!cnt_20_ns && sck && cnt_bit == 7)
    105. cnt_bit <= 3'd0 ;
    106. else if(!cnt_20_ns && sck)
    107. cnt_bit <= cnt_bit + 1'b1 ;
    108. READ : if(!cnt_20_ns && sck && cnt_bit == 7)
    109. cnt_bit <= 3'd0 ;
    110. else if(!cnt_20_ns && sck)
    111. cnt_bit <= cnt_bit + 1'b1 ;
    112. SEND : cnt_bit <=3'd0 ;
    113. default : cnt_bit <=3'd0 ;
    114. endcase
    115. end
    116. // reg [10:0] cnt_byte ;
    117. always @(posedge sys_clk or negedge sys_rst_n) begin
    118. if(~sys_rst_n)
    119. cnt_byte <= 4'd0 ;
    120. else if(cnt_bit == 7 && cnt_byte == CNT_MAX_BYTE - 1 && !cnt_20_ns && sck)
    121. cnt_byte <= 4'd0 ;
    122. else if(cnt_bit == 7 && !cnt_20_ns && sck)
    123. cnt_byte <= cnt_byte + 1'b1 ;
    124. else
    125. cnt_byte <= cnt_byte ;
    126. end
    127. // reg flag_R_S ;
    128. // reg flag_b ;
    129. always @(posedge sys_clk or negedge sys_rst_n) begin
    130. if(~sys_rst_n) begin
    131. flag_b <= 1'b0 ;
    132. flag_R_S <= 1'b0 ;
    133. end
    134. else
    135. case (state_c)
    136. IDLE : begin
    137. flag_b <= 1'b0 ;
    138. flag_R_S <= 1'b0 ;
    139. end
    140. INSTRUCT: begin
    141. if((cnt_byte == NUM_COMD - 1) && (cnt_bit == 7) && !cnt_20_ns && sck)
    142. flag_b <= 1'b1 ;
    143. else
    144. flag_b <= flag_b ;
    145. flag_R_S <= 1'b0 ;
    146. end
    147. READ : begin
    148. if(cnt_byte == NUM_COMD)
    149. flag_R_S <= 1'b0 ;
    150. else if((cnt_byte == CNT_MAX_BYTE - 1) && (cnt_bit == 7) && !cnt_20_ns && sck)
    151. flag_R_S <= 1'b1 ;
    152. flag_b <= 1'b0 ;
    153. end
    154. SEND : begin
    155. flag_b <= 1'b0 ;
    156. flag_R_S <= 1'b0 ;
    157. end
    158. default : begin
    159. flag_b <= 1'b0 ;
    160. flag_R_S <= 1'b0 ;
    161. end
    162. endcase
    163. end
    164. // reg flagBreg ;
    165. // reg flag_RSr ;
    166. always @(posedge sys_clk or negedge sys_rst_n) begin
    167. if(~sys_rst_n)
    168. flagBreg <= 1'b0 ;
    169. else
    170. flagBreg <= flag_b ;
    171. end
    172. always @(posedge sys_clk or negedge sys_rst_n) begin
    173. if(~sys_rst_n)
    174. flag_RSr <= 1'b0 ;
    175. else
    176. flag_RSr <= flag_R_S ;
    177. end
    178. // reg [7:0] datInFifo ; // data_in_fifo
    179. always @(posedge sys_clk or negedge sys_rst_n) begin
    180. if(~sys_rst_n)
    181. datInFifo <= 1'b0 ;
    182. else if(flag_data)
    183. datInFifo <= {datInFifo[6:0],miso}; // 读flash中数据,先传的低位{miso,datInFifo[7:1]}。
    184. else
    185. datInFifo <= datInFifo ;
    186. end
    187. // reg flag_data ; // flag_data 采样标志信号
    188. always @(posedge sys_clk or negedge sys_rst_n) begin
    189. if(~sys_rst_n)
    190. flag_data <= 1'b0 ;
    191. else if(state_c == READ) begin
    192. if(cnt_20_ns && !sck)
    193. flag_data <= 1'b1 ;
    194. else
    195. flag_data <= 1'b0 ;
    196. end else begin
    197. flag_data <= 1'b0 ;
    198. end
    199. end
    200. // reg flaInFifo ; // flag_in_fifo
    201. always @(posedge sys_clk or negedge sys_rst_n) begin
    202. if(~sys_rst_n)
    203. flaInFifo <= 1'b0 ;
    204. else if(state_c == READ && cnt_bit == 7 && flag_data)
    205. flaInFifo <= 1'b1 ;
    206. else
    207. flaInFifo <= 1'b0 ;
    208. end
    209. // reg [19:0] cnt_send ; // uart_tx模块发送1byte数据的等待时间。
    210. always @(posedge sys_clk or negedge sys_rst_n) begin
    211. if(~sys_rst_n)
    212. cnt_send <= 20'd0 ;
    213. else
    214. if(state_c == SEND) begin
    215. if(cnt_send == CNT_MAX_SEND - 1)
    216. cnt_send <= 20'd0 ;
    217. else
    218. cnt_send <= cnt_send + 1'b1 ;
    219. end
    220. else
    221. cnt_send <= 20'd0 ;
    222. end
    223. // reg flag_out_fifo_reg ;
    224. always @(posedge sys_clk or negedge sys_rst_n) begin
    225. if(~sys_rst_n)
    226. flag_out_fifo_reg <= 1'b0 ;
    227. else if(flaSenEnd && !empty)
    228. flag_out_fifo_reg <= 1'b1 ;
    229. else
    230. flag_out_fifo_reg <= 1'b0 ;
    231. end
    232. // reg flaSenEnd ;
    233. always @(posedge sys_clk or negedge sys_rst_n) begin
    234. if(~sys_rst_n)
    235. flaSenEnd <= 1'b0 ;
    236. else if(cnt_send == CNT_MAX_SEND - 2)
    237. flaSenEnd <= 1'b1 ;
    238. else
    239. flaSenEnd <= 1'b0 ;
    240. end
    241. // output signal describe
    242. // cs_n ,
    243. always @(posedge sys_clk or negedge sys_rst_n) begin
    244. if(~sys_rst_n)
    245. cs_n <= 1'b1 ;
    246. else
    247. case (state_c)
    248. IDLE : if(key_flag)
    249. cs_n <= 1'b0 ;
    250. else
    251. cs_n <= cs_n ;
    252. INSTRUCT: cs_n <= cs_n ;
    253. READ : cs_n <= cs_n ;
    254. SEND : cs_n <= 1'b1 ;
    255. default : cs_n <= 1'b1 ;
    256. endcase
    257. end
    258. // sck ,
    259. always @(posedge sys_clk or negedge sys_rst_n) begin
    260. if(~sys_rst_n)
    261. sck <= 1'b0 ;
    262. else
    263. case (state_c)
    264. IDLE : sck <= 1'b0 ;
    265. INSTRUCT: if(cnt_20_ns)
    266. sck <= ~sck ;
    267. else
    268. sck <= sck ;
    269. READ : if(cnt_20_ns)
    270. sck <= ~sck ;
    271. else
    272. sck <= sck ;
    273. SEND : sck <= 1'b0 ;
    274. default : sck <= 1'b0 ;
    275. endcase
    276. end
    277. // mosi ,
    278. always @(posedge sys_clk or negedge sys_rst_n) begin
    279. if(~sys_rst_n) begin
    280. mosi <= 1'b0 ;
    281. end else begin
    282. case (state_c)
    283. IDLE : mosi <= 1'b0 ;
    284. INSTRUCT: case (cnt_byte)
    285. 0 : if(cnt_bit == 0)
    286. mosi <= COMD_REA[7] ;
    287. else if(cnt_20_ns && sck)
    288. mosi <= COMD_REA[7 - cnt_bit] ;
    289. else
    290. mosi <= mosi ;
    291. 1 : if(cnt_bit == 0)
    292. mosi <= ADDR_SEC[7] ;
    293. else if(cnt_20_ns && sck)
    294. mosi <= ADDR_SEC[7 - cnt_bit] ;
    295. else
    296. mosi <= mosi ;
    297. 2 : if(cnt_bit == 0)
    298. mosi <= ADDR_PAG[7] ;
    299. else if(cnt_20_ns && sck)
    300. mosi <= ADDR_PAG[7 - cnt_bit] ;
    301. else
    302. mosi <= mosi ;
    303. 3 : if(cnt_bit == 0)
    304. mosi <= ADDR_BYT[7] ;
    305. else if(cnt_20_ns && sck)
    306. mosi <= ADDR_BYT[7 - cnt_bit] ;
    307. else
    308. mosi <= mosi ;
    309. default : mosi <= 1'b0 ;
    310. endcase
    311. READ : mosi <= 1'b0 ;
    312. SEND : mosi <= 1'b0 ;
    313. default : mosi <= 1'b0 ;
    314. endcase
    315. end
    316. end
    317. // po_flag ,
    318. always @(posedge sys_clk or negedge sys_rst_n) begin
    319. if(~sys_rst_n)
    320. po_flag <= 1'b0 ;
    321. else
    322. po_flag <= flag_out_fifo_reg ;
    323. end
    324. // wire [7:0] po_data ;// 直接连接到fifo的输出端口。
    325. // */
    326. /***********************例化FIFO***************************************/
    327. assign flaOutFif = flag_out_fifo_reg ;
    328. fifo_1024x8 fifo_1024x8_inst(
    329. .clock ( sys_clk ) ,
    330. .data ( datInFifo ) ,
    331. .rdreq ( flaOutFif ) ,
    332. .wrreq ( flaInFifo ) ,
    333. .empty ( empty ) ,
    334. .full ( full ) ,
    335. .q ( po_data ) ,
    336. .usedw ( usedw )
    337. );
    338. endmodule

    仿真波形: 

    上版验证成功。

  • 相关阅读:
    vue2 过滤器 自定义指令
    细说GaussDB(DWS)复杂多样的资源负载管理手段
    STL容器——vector
    如何实现torch.arange的tensor版本
    HTML静态网页成品作业(HTML+CSS)——家乡广州介绍设计制作(5个页面)
    【无标题】
    JavaScript 72 JavaScript vs jQuery 72.4 JavaScript jQuery HTML DOM
    密码学·常用网址
    文心一言 vs GPT-4 —— 全面横向比较
    智能物料运输小车设计与实现
  • 原文地址:https://blog.csdn.net/Meng_long2022/article/details/133864293