当前位置:   article > 正文

学习笔记之FPGA的SPI通讯_fpga spi

fpga spi
      FPGA由于 FPGA 是基于 SRAM 结构的,程序掉电后会丢失,所以需要一个外置 Flash 保存程序, FPGA 每次上电后去读取 Flash 中的配置程序,在 ALINX 开发板中,很多使用的是 SPI 接口的 nor flash,这种 flash 只需要 4 根 IO。FPGA 的配置 flash 是特殊的 IO,上电时工作,FPGA 要使用这些 IO 来读取 Flash,读取完成后释放这些 IO 交给用户使用。

1. SPI的基本知识

        SPI(Serial Peripheral Interface)是一种同步串行通信协议,通常用于在嵌入式系统中连接微控制器和外部设备。它允许微控制器与多个外设同时进行全双工通信,实现高速数据传输。SPI协议通常用于连接存储器芯片、传感器、显示屏、通信模块和其他外设。 

         SPI协议的基本工作原理如下:微控制器通过主设备选择(SS)引脚选择要与之通信的外设,并通过时钟信号(SCLK)同步数据传输。它还使用主输出主输入(MOSI)和主输入主输出(MISO)引脚进行双向数据传输。在传输过程中,主设备将数据位传输到外设的输入引脚,同时从外设的输出引脚读取数据位。

        SPI协议具有以下特点:

  • 简单灵活:SPI协议使用少量的引脚和简单的硬件电路,易于实现和调试。

  • 高速通信:由于采用同步传输方式,SPI协议可以实现高速数据传输,适用于实时应用。

  • 可靠性好:SPI协议具有错误检测和纠正机制,可以提供可靠的数据传输。

  • 多设备支持:SPI协议使用主从结构,一个主设备可以连接多个从设备,使得系统具备良好的扩展性。

        SPI协议的配置通常由以下参数确定:

  • 时钟极性(CPOL):确定时钟信号的空闲状态和活动状态。

  • 时钟相位(CPHA):确定数据采样的时机。

  • 数据位顺序:确定数据位的传输顺序,可以是最高位先传输(MSB-first)或最低位先传输(LSB-first)。

        在实际应用中,SPI协议根据不同的硬件平台和设备需求进行配置。通过正确配置参数,微控制器可以与外设进行可靠的通信和数据交换。

2. ADC读写实验

2.1 ADC128S022产品信息

        ADC128S022器件是一种低功耗、8通道CMOS 12位模数转换器,其转换吞吐量为50 ksps到200 ksps。该转换器是基于一个逐次逼近寄存器结构与一个内部跟踪和保持电路。它可以配置为在输入IN0到IN7接受多达8个输入信号。串行数据的输出是直接二进制,并兼容多种标准,如SPI, QSPI, MICROWIRE和许多常见的DSP串行接口。 ADC128S022可使用独立的模拟和数字电源。模拟电源(VA)的电压范围是2.7 V到5.25 V,数字电源(VD)的电压范围是2.7 V到V_{_{^{}}}A。使用3v或5v电源的正常功耗分别为1.2 mW和7.5 mW。当使用3v电源时,功耗为0.06µW;当使用5v电源时,功耗为0.25µW确保在-40°C至+105°C的扩展工业温度范围内运行。

 2.2 ADC128S022的时序图

        CS:片选信号,低电平表示选中。

        SCLK:输入时钟。

        DIN:串行输入,SCLK的上升沿进行采集。

        DOUT:转换输出,SCLK的下降沿进行数据输出。

2.3 实验代码

  1. module SPI(
  2. input clk,
  3. input rst_n,
  4. input start,
  5. input [2:0]channel,
  6. //========ADC128S022===========//
  7. output reg SCLK,
  8. output reg DIN,
  9. output reg CS_N,
  10. input DOUT,
  11. output reg done,
  12. output reg [11:0]data
  13. );
  14. reg en;
  15. reg [2:0]r_channel;
  16. reg [4:0]cnt;
  17. reg cnt_flag;
  18. reg [5:0]SCLK_CNT;
  19. reg [11:0]r_data;
  20. //==============写入通道===================//
  21. always@(posedge clk or negedge rst_n)begin
  22. if(!rst_n)
  23. r_channel <= 'd0;
  24. else if(start)
  25. r_channel <= channel;
  26. else
  27. r_channel <= r_channel;
  28. end
  29. //============转换使能信号==================//
  30. always@(posedge clk or negedge rst_n)begin
  31. if(!rst_n)
  32. en <= 1'b0;
  33. else if(start)
  34. en <= 1'b1;
  35. else if(done)
  36. en <= 1'b0;
  37. else
  38. en <= en;
  39. end
  40. //==================cnt=====================//
  41. always@(posedge clk or negedge rst_n)begin
  42. if(!rst_n)
  43. cnt <= 'd0;
  44. else if(en)begin
  45. if(cnt == 'd10)
  46. cnt <= 'd0;
  47. else
  48. cnt <= cnt + 1'b1;
  49. end
  50. else
  51. cnt <= 'd0;
  52. end
  53. //===================cnt_flag===============//
  54. always@(posedge clk or negedge rst_n)begin
  55. if(!rst_n)
  56. cnt_flag <= 1'b0;
  57. else if(cnt == 'd10)
  58. cnt_flag <= 1'b1;
  59. else
  60. cnt_flag <= 1'b0;
  61. end
  62. //===============SCLK_CNT===================//
  63. always@(posedge clk or negedge rst_n)begin
  64. if(!rst_n)
  65. SCLK_CNT <= 'd0;
  66. else if(en)begin
  67. if(cnt_flag && (SCLK_CNT == 'd33))
  68. SCLK_CNT <= 'd0;
  69. else if(cnt_flag)
  70. SCLK_CNT <= SCLK_CNT + 1'b1;
  71. else
  72. SCLK_CNT <= SCLK_CNT;
  73. end
  74. else
  75. SCLK_CNT <= 'd0;
  76. end
  77. //===========================================//
  78. always@(posedge clk or negedge rst_n)begin
  79. if(!rst_n)begin
  80. SCLK <= 1'b1;
  81. CS_N <= 1'b1;
  82. DIN <= 1'b1;
  83. end
  84. else if(en)begin
  85. if(cnt_flag)begin
  86. case(SCLK_CNT)
  87. 6'd0:begin CS_N <= 1'b0;end
  88. 6'd1:begin SCLK <= 1'b0;DIN <= 1'b0;end
  89. 6'd2:begin SCLK <= 1'b1;end
  90. 6'd3:begin SCLK <= 1'b0;end
  91. 6'd4:begin SCLK <= 1'b1;end
  92. //写入通道
  93. 6'd5:begin SCLK <= 1'b0;DIN <= r_channel[2];end
  94. 6'd6:begin SCLK <= 1'b1;end
  95. 6'd7:begin SCLK <= 1'b0;DIN <= r_channel[1];end
  96. 6'd8:begin SCLK <= 1'b1;end
  97. 6'd9:begin SCLK <= 1'b0;DIN <= r_channel[0];end
  98. //写入数据,在上升沿使数据逐次左移 6'd10,6'd12,6'd14,6'd16,6'd18,6'd20,6'd22,6'd24,6'd26,6'd28,6'd30,6'd32:
  99. begin SCLK <= 1'b1;r_data <= {r_data[10:0],DOUT};end
  100. 6'd11,6'd13,6'd15,6'd17,6'd19,6'd21,6'd23,6'd25,6'd27,6'd29,6'd31:
  101. begin SCLK <= 1'b0;end
  102. //传输结束,结束选中
  103. 6'd33:begin CS_N <= 1'b1;end
  104. default:begin CS_N <= 1'b1;end
  105. endcase
  106. end
  107. else ;
  108. end
  109. else begin
  110. SCLK <= 1'b1;
  111. CS_N <= 1'b1;
  112. DIN <= 1'b1;
  113. end
  114. end
  115. //================done=================//
  116. always@(posedge clk or negedge rst_n)begin
  117. if(!rst_n)
  118. done <= 1'b0;
  119. else if(cnt_flag && (SCLK_CNT == 'd33))
  120. done <= 1'b1;
  121. else
  122. done <= 1'b0;
  123. end
  124. //================data=================//
  125. always@(posedge clk or negedge rst_n)begin
  126. if(!rst_n)
  127. data <= 'd0;
  128. else if(cnt_flag && (SCLK_CNT == 'd33))
  129. data <= r_data;
  130. else
  131. data <= data;
  132. end
  133. endmodule

        注:这部分代码参考自b站FPGA小学生。 

2.4 测试文件

  1. `timescale 1ns/1ns
  2. module SPI_tb;
  3. reg clk;
  4. reg rst_n;
  5. reg start;
  6. reg [2:0]channel;
  7. wire SCLK;
  8. wire DIN;
  9. wire CS_N;
  10. reg DOUT;
  11. wire done;
  12. wire [11:0]data;
  13. reg i = 0;
  14. initial clk = 1'b1;
  15. always#10 clk = ~clk;
  16. SPI SPI_inst(
  17. .clk(clk),
  18. .rst_n(rst_n),
  19. .start(start),
  20. .channel(channel),
  21. //========ADC128S022===========//
  22. .SCLK(SCLK),
  23. .DIN(DIN),
  24. .CS_N(CS_N),
  25. .DOUT(DOUT),
  26. .done(done),
  27. .data(data)
  28. );
  29. initial begin
  30. rst_n = 1'b0;
  31. channel = 'd0;
  32. start = 1'b0;
  33. DOUT = 1'b0;
  34. #100;
  35. rst_n = 1'b1;
  36. #100;
  37. channel = 3;
  38. for(i=0;i<3;i=i+1)begin
  39. start = 1;
  40. #20;
  41. start = 0;
  42. gene_DOUT(12'b0101_1100_1010); //依次将存储器中存储的波形读出,按照ADC的转换结果输出方式送到DOUT信号线上
  43. @(posedge done); //等待转换完成信号
  44. #200;
  45. end
  46. #20000;
  47. $stop;
  48. end
  49. //将并行数据按照ADC的数据输出格式,送到DOUT信号线上,供控制模块采集读取
  50. task gene_DOUT;
  51. input [15:0]vdata;
  52. reg [4:0]cnt;
  53. begin
  54. cnt = 0;
  55. wait(!CS_N);
  56. while(cnt<16)begin
  57. @(negedge SCLK) DOUT = vdata[15-cnt];
  58. cnt = cnt + 1'b1;
  59. end
  60. end
  61. endtask
  62. endmodule

 

3. FLASH读写实验

3.1 FLASH的基本介绍

        FLASH闪存是一种非易失性存储器,常用于存储数据并替代传统的磁盘驱动器。它具有许多优点,例如速度快、耐用性高和体积小。其具有内部时钟,可确保数据在正确的时间段写入和读取,同时提供更高的数据传输速度和准确性,还有助于协调闪存与其他设备之间的数据传输。对其主要操作包括擦除、写入和读取。因为闪存内部的存储单元被分为多个块,每个块都可以独立操作,使得闪存在处理大量数据时表现出色。

图 FLASH的连接方式 

3.2 FLASH的基本指令

 

注:其他有关SPI和FLASH的基础内容请移步至前章的STM32通信总结。 

3.3 实验代码

3.3.1 SPI驱动代码

        值得注意的是这里需要区分delay_cnt、bit_cnt和clk_cnt,具体如下图所示。

         delay_cnt和clk_cnt均为1位,delay_cnt更多是作为延时开始的标志,而bit_clk会在clk_cnt高电平时加一,进而切换输出的位号。根据FLASH定义的时序,上电后会需要一段时间的延时等待,接着是8位的命令、24位的地址以及后续的数据,这也说明了在32位后才真正开始进行数据的传输。

  1. module spi_drive(
  2. input clk_100m ,
  3. input sys_rst_n ,
  4. //user interface
  5. input spi_start ,//spi开启使能。
  6. input [7:0 ] spi_cmd ,//FLAH操作指令
  7. input [23:0] spi_addr ,//FLASH地址
  8. input [7:0 ] spi_data ,//FLASH写入的数据
  9. input [3:0 ] cmd_cnt ,
  10. output idel_flag_r ,//空闲状态标志的上升沿
  11. output reg w_data_req ,//FLASH写数据请求
  12. output reg [7:0] r_data ,//FLASH读出的数据
  13. output reg erro_flag ,//读出的数据错误标志
  14. //spi interface
  15. output reg spi_cs ,//SPI从机的片选信号,低电平有效。
  16. output reg spi_clk ,//主从机之间的数据同步时钟。
  17. output reg spi_mosi ,//数据引脚,主机输出,从机输入。
  18. input spi_miso //数据引脚,主机输入,从机输出。
  19. );
  20. //状态机
  21. parameter IDLE =4'd0;//空闲状态
  22. parameter WEL =4'd1;//写使能状态
  23. parameter S_ERA =4'd2;//扇区擦除状态
  24. parameter C_ERA =4'd3;//全局擦除
  25. parameter READ =4'd4;//读状态
  26. parameter WRITE =4'd5;//写状态
  27. parameter R_STA_REG =4'd6;
  28. //指令集
  29. parameter WEL_CMD =8'h06;
  30. parameter S_ERA_CMD =8'h20;
  31. parameter C_ERA_CMD =8'hc7;
  32. parameter READ_CMD =8'h03;
  33. parameter WRITE_CMD =8'h02;
  34. parameter R_STA_REG_CMD=8'h05;
  35. //wire define
  36. wire idel_flag;
  37. //reg define
  38. reg[3:0] current_state ;
  39. reg[3:0] next_state ;
  40. reg[7:0 ] data_buffer ;
  41. reg[7:0 ] cmd_buffer ;
  42. reg[7:0 ] sta_reg ;
  43. reg[23:0] addr_buffer ;
  44. reg[31:0] bit_cnt ;
  45. reg clk_cnt ;
  46. reg dely_cnt ;
  47. reg[31:0] dely_state_cnt ;
  48. reg[7:0 ] rd_data_buffer ;
  49. reg spi_clk0 ;
  50. reg stdone ;
  51. reg[7:0 ] data_check ;
  52. reg idel_flag0 ;
  53. reg idel_flag1 ;
  54. //*****************************************************
  55. //** main code
  56. //*****************************************************
  57. assign idel_flag=(current_state==IDLE)?1:0;//空闲状态标志
  58. assign idel_flag_r=idel_flag0&&(~idel_flag1);//空闲状态标志的上升沿
  59. always @(posedge clk_100m or negedge sys_rst_n )begin
  60. if(!sys_rst_n)begin
  61. idel_flag0<=1'b1;
  62. idel_flag1<=1'b1;
  63. end
  64. else begin
  65. idel_flag0<=idel_flag;
  66. idel_flag1<=idel_flag0;
  67. end
  68. end
  69. always @(posedge clk_100m or negedge sys_rst_n )begin
  70. if(!sys_rst_n)
  71. w_data_req<=1'b0;
  72. else if((bit_cnt+2)%8==0&&bit_cnt>=30&&clk_cnt==0&&current_state==WRITE)
  73. w_data_req<=1'b1;
  74. else
  75. w_data_req<=1'b0;
  76. end
  77. always @(posedge clk_100m or negedge sys_rst_n )begin//读出的数据移位寄存
  78. if(!sys_rst_n)
  79. rd_data_buffer<=8'd0;
  80. else if(bit_cnt>=32&&bit_cnt<=2080&&clk_cnt==0&&current_state==READ)
  81. rd_data_buffer<={rd_data_buffer[6:0],spi_miso};
  82. else
  83. rd_data_buffer<=rd_data_buffer;
  84. end
  85. always @(posedge clk_100m or negedge sys_rst_n )begin//检查读出的数据是否正确
  86. if(!sys_rst_n)
  87. data_check<=8'd0;
  88. else if(bit_cnt%8==0&&bit_cnt>=40&&clk_cnt==1&&current_state==READ)
  89. data_check<=data_check+1'd1;
  90. else
  91. data_check<=data_check;
  92. end
  93. always @(posedge clk_100m or negedge sys_rst_n )begin//读出的数据
  94. if(!sys_rst_n)
  95. r_data<=8'd0;
  96. else if(bit_cnt%8==0&&bit_cnt>38&&clk_cnt==1&&current_state==READ)
  97. r_data<=rd_data_buffer;
  98. else
  99. r_data<=r_data;
  100. end
  101. always @(posedge clk_100m or negedge sys_rst_n )begin//读出的数据错误标志
  102. if(!sys_rst_n)
  103. erro_flag<=1'd0;
  104. else if(bit_cnt>32&&bit_cnt<=2080&&current_state==READ&&cmd_cnt==6)begin
  105. if(data_check!=r_data)
  106. erro_flag<=1'd1;
  107. else
  108. erro_flag<=erro_flag;
  109. end
  110. else
  111. erro_flag<=erro_flag;
  112. end
  113. always @(posedge clk_100m or negedge sys_rst_n )begin
  114. if(!sys_rst_n)
  115. data_buffer<=8'd0;
  116. else if((bit_cnt+1)%8==0&&bit_cnt>30&&clk_cnt==1)
  117. data_buffer<=spi_data;
  118. else if(clk_cnt==1&&current_state==WRITE&&bit_cnt>=32)
  119. data_buffer<={data_buffer[6:0],data_buffer[7]};
  120. else
  121. data_buffer<=data_buffer;
  122. end
  123. always @(posedge clk_100m or negedge sys_rst_n )begin
  124. if(!sys_rst_n)
  125. cmd_buffer<=8'd0;
  126. else if(spi_cs==0&&dely_cnt==0)
  127. cmd_buffer<=spi_cmd;
  128. else if(clk_cnt==1&&(current_state==WEL||current_state==S_ERA||current_state==C_ERA
  129. ||current_state==READ||current_state==WRITE||current_state==R_STA_REG)&&bit_cnt<8)
  130. cmd_buffer<={cmd_buffer[6:0],1'b1};
  131. else
  132. cmd_buffer<=cmd_buffer;
  133. end
  134. always @(posedge clk_100m or negedge sys_rst_n )begin
  135. if(!sys_rst_n)
  136. addr_buffer<=8'd0;
  137. else if(spi_cs==0&&dely_cnt==0)
  138. addr_buffer<=spi_addr;
  139. else if(clk_cnt==1&&(current_state==READ||current_state==WRITE)&&bit_cnt>=8&&bit_cnt<32)
  140. addr_buffer<={addr_buffer[22:0],addr_buffer[23]};
  141. else
  142. addr_buffer<=addr_buffer;
  143. end
  144. always @(posedge clk_100m or negedge sys_rst_n )begin
  145. if(!sys_rst_n)
  146. clk_cnt<=1'd0;
  147. else if(dely_cnt==1)
  148. clk_cnt<=clk_cnt+1'd1;
  149. else
  150. clk_cnt<=1'd0;
  151. end
  152. always @(posedge clk_100m or negedge sys_rst_n )begin
  153. if(!sys_rst_n)
  154. dely_cnt<=1'd0;
  155. else if(spi_cs==0)begin
  156. if(dely_cnt<1)
  157. dely_cnt<=dely_cnt+1'd1;
  158. else
  159. dely_cnt<=dely_cnt;
  160. end
  161. else
  162. dely_cnt<=1'd0;
  163. end
  164. always @(posedge clk_100m or negedge sys_rst_n )begin
  165. if(!sys_rst_n)
  166. dely_state_cnt<=1'd0;
  167. else if(spi_cs)begin
  168. if(dely_state_cnt<400000000)
  169. dely_state_cnt<=dely_state_cnt+1'd1;
  170. else
  171. dely_state_cnt<=dely_state_cnt;
  172. end
  173. else
  174. dely_state_cnt<=1'd0;
  175. end
  176. always @(posedge clk_100m or negedge sys_rst_n )begin
  177. if(!sys_rst_n)
  178. bit_cnt<=11'd0;
  179. else if(dely_cnt==1)begin
  180. if(clk_cnt==1'b1)
  181. bit_cnt<=bit_cnt+1'd1;
  182. else
  183. bit_cnt<=bit_cnt;
  184. end
  185. else
  186. bit_cnt<=11'd0;
  187. end
  188. //三段式状态机
  189. always @(posedge clk_100m or negedge sys_rst_n )begin
  190. if(!sys_rst_n)
  191. current_state<=IDLE;
  192. else
  193. current_state<=next_state;
  194. end
  195. always @(*)begin
  196. case(current_state)
  197. IDLE: begin
  198. if(spi_start&&spi_cmd==WEL_CMD)
  199. next_state=WEL;
  200. else if(spi_start&&spi_cmd==C_ERA_CMD)
  201. next_state=C_ERA;
  202. else if(spi_start&&spi_cmd==S_ERA_CMD)
  203. next_state=S_ERA;
  204. else if(spi_start&&spi_cmd==READ_CMD)
  205. next_state=READ;
  206. else if(spi_start&&spi_cmd==WRITE_CMD)
  207. next_state=WRITE;
  208. else if(spi_start&&spi_cmd==R_STA_REG_CMD)
  209. next_state=R_STA_REG;
  210. else
  211. next_state=IDLE;
  212. end
  213. WEL: begin
  214. if(stdone&&bit_cnt>=8)
  215. next_state=IDLE;
  216. else
  217. next_state=WEL;
  218. end
  219. S_ERA: begin
  220. if(stdone)
  221. next_state=IDLE;
  222. else
  223. next_state=S_ERA;
  224. end
  225. C_ERA: begin
  226. if(stdone)
  227. next_state=IDLE;
  228. else
  229. next_state=C_ERA;
  230. end
  231. READ: begin
  232. if(stdone&&bit_cnt>=8)
  233. next_state=IDLE;
  234. else
  235. next_state=READ;
  236. end
  237. WRITE: begin
  238. if(stdone&&bit_cnt>=8)
  239. next_state=IDLE;
  240. else
  241. next_state=WRITE;
  242. end
  243. R_STA_REG: begin
  244. if(stdone)
  245. next_state=IDLE;
  246. else
  247. next_state=R_STA_REG;
  248. end
  249. default: next_state=IDLE;
  250. endcase
  251. end
  252. always @(posedge clk_100m or negedge sys_rst_n )begin
  253. if(!sys_rst_n) begin
  254. spi_cs<=1'b1;
  255. spi_clk<=1'b0;
  256. spi_clk0<=1'b0;
  257. spi_mosi<=1'b0;
  258. stdone<=1'b0;
  259. end
  260. else begin
  261. case(current_state)
  262. IDLE: begin
  263. spi_cs<=1'b1;
  264. spi_clk<=1'b0;
  265. spi_mosi<=1'b0;
  266. end
  267. WEL: begin
  268. stdone<=1'b0;
  269. spi_cs<=1'b0;
  270. if(dely_cnt==1&&bit_cnt<8) begin
  271. spi_clk0<=~spi_clk0;
  272. spi_clk<=spi_clk0;
  273. spi_mosi<=cmd_buffer[7];
  274. end
  275. else if(bit_cnt==8&&clk_cnt==0)begin
  276. stdone<=1'b1;
  277. spi_clk<=1'b0;
  278. spi_mosi<=1'b0;
  279. end
  280. else if(bit_cnt==8&&clk_cnt==1)begin
  281. spi_cs<=1'b1;
  282. end
  283. end
  284. C_ERA: begin
  285. stdone<=1'b0;
  286. if(dely_state_cnt==10)
  287. spi_cs<=1'b0;
  288. else if(dely_cnt==1&&bit_cnt<8) begin
  289. spi_clk0<=~spi_clk0;
  290. spi_clk<=spi_clk0;
  291. spi_mosi<=cmd_buffer[7];
  292. end
  293. else if(bit_cnt==8&&clk_cnt==0)begin
  294. stdone<=1'b1;
  295. spi_clk<=1'b0;
  296. spi_mosi<=1'b0;
  297. end
  298. else if(bit_cnt==8&&clk_cnt==1)begin
  299. spi_cs<=1'b1;
  300. end
  301. end
  302. S_ERA: begin
  303. stdone<=1'b0;
  304. if(dely_state_cnt==10)
  305. spi_cs<=1'b0;
  306. else if(dely_cnt==1&&bit_cnt<8) begin
  307. spi_clk0<=~spi_clk0;
  308. spi_clk<=spi_clk0;
  309. spi_mosi<=cmd_buffer[7];
  310. end
  311. else if(bit_cnt>=8&&bit_cnt<32&&spi_cs==0)begin
  312. spi_cs<=1'b0;
  313. spi_clk0<=~spi_clk0;
  314. spi_clk<=spi_clk0;
  315. spi_mosi<=addr_buffer[23];
  316. end
  317. else if(bit_cnt==32&&clk_cnt==0) begin
  318. spi_cs<=1'b1;
  319. spi_clk<=1'b0;
  320. spi_mosi<=1'b0;
  321. stdone<=1'b1;
  322. end
  323. end
  324. READ: begin
  325. stdone<=1'b0;
  326. if(dely_state_cnt==10)
  327. spi_cs<=1'b0;
  328. else if(dely_cnt==1&&bit_cnt<8) begin
  329. spi_clk0<=~spi_clk0;
  330. spi_clk<=spi_clk0;
  331. spi_mosi<=cmd_buffer[7];
  332. end
  333. else if(bit_cnt>=8&&bit_cnt<32&&spi_cs==0)begin
  334. spi_clk0<=~spi_clk0;
  335. spi_clk<=spi_clk0;
  336. spi_mosi<=addr_buffer[23];
  337. end
  338. else if(bit_cnt>=32&&bit_cnt<2080)begin
  339. spi_clk0<=~spi_clk0;
  340. spi_clk<=spi_clk0;
  341. spi_mosi<=1'b0;
  342. end
  343. else if(bit_cnt==2080&&clk_cnt==0) begin
  344. spi_clk<=1'b0;
  345. spi_mosi<=1'b0;
  346. stdone<=1'b1;
  347. end
  348. else if(bit_cnt==2080&&clk_cnt==1) begin
  349. spi_cs<=1'b1;
  350. end
  351. end
  352. WRITE: begin
  353. stdone<=1'b0;
  354. if(dely_state_cnt==10)
  355. spi_cs<=1'b0;
  356. else if(dely_cnt==1&&bit_cnt<8) begin
  357. spi_clk0<=~spi_clk0;
  358. spi_clk<=spi_clk0;
  359. spi_mosi<=cmd_buffer[7];
  360. end
  361. else if(bit_cnt>=8&&bit_cnt<32&&spi_cs==0)begin
  362. spi_clk0<=~spi_clk0;
  363. spi_clk<=spi_clk0;
  364. spi_mosi<=addr_buffer[23];
  365. end
  366. else if(bit_cnt>=32&&bit_cnt<2080)begin
  367. spi_clk0<=~spi_clk0;
  368. spi_clk<=spi_clk0;
  369. spi_mosi<=data_buffer[7];
  370. end
  371. else if(bit_cnt==2080&&clk_cnt==0) begin
  372. spi_clk<=1'b0;
  373. spi_mosi<=1'b0;
  374. stdone<=1'b1;
  375. end
  376. else if(bit_cnt==2080&&clk_cnt==1) begin
  377. spi_cs<=1'b1;
  378. end
  379. end
  380. R_STA_REG:begin
  381. stdone<=1'b0;
  382. if(dely_state_cnt==10)
  383. spi_cs<=1'b0;
  384. else if(dely_cnt==1&&bit_cnt<8)begin
  385. spi_clk0<=~spi_clk0;
  386. spi_clk<=spi_clk0;
  387. spi_mosi<=cmd_buffer[7];
  388. end
  389. else if(bit_cnt==8)begin
  390. spi_clk0<=~spi_clk0;
  391. spi_clk<=spi_clk0;
  392. spi_mosi<=1'b0;
  393. end
  394. else if(~spi_miso&&bit_cnt%8==0)begin
  395. spi_clk<=1'b0;
  396. spi_cs<=1'b1;
  397. stdone<=1'b1;
  398. end
  399. else if(~spi_cs&&dely_cnt==1)begin
  400. spi_clk0<=~spi_clk0;
  401. spi_clk<=spi_clk0;
  402. end
  403. end
  404. default: begin
  405. stdone<=1'b0;
  406. spi_cs<=1'b1;
  407. spi_clk<=1'b0;
  408. spi_clk0<=1'b0;
  409. spi_mosi<=1'b0;
  410. end
  411. endcase
  412. end
  413. end
  414. endmodule

3.3.2 FLASH读写代码

  1. module flash_rw(
  2. input sys_clk ,
  3. input sys_rst_n ,
  4. input idel_flag_r ,//抓取空闲状态上升沿
  5. input w_data_req ,//写请求
  6. output reg[3:0 ] cmd_cnt ,//计数器
  7. output reg spi_start ,//spi开启使能
  8. output reg[7:0 ] spi_cmd ,//spi命令号
  9. output reg[7:0 ] spi_data
  10. );
  11. //指令集
  12. parameter WEL_CMD =16'h06;//允许写
  13. parameter S_ERA_CMD =16'h20;//扇擦除
  14. parameter C_ERA_CMD =16'hc7;//块擦除
  15. parameter READ_CMD =16'h03;//读数据
  16. parameter WRITE_CMD =16'h02;//写数据
  17. parameter R_STA_REG_CMD=8'h05 ;//读状态寄存器
  18. //reg define
  19. reg[3:0] flash_start;
  20. //*****************************************************
  21. //** main code
  22. //*****************************************************
  23. always @(posedge sys_clk or negedge sys_rst_n )begin //延时
  24. if(!sys_rst_n)
  25. flash_start<=0;
  26. else if(flash_start<=10)
  27. flash_start<=flash_start+1;
  28. else
  29. flash_start<=flash_start;
  30. end
  31. always @(posedge sys_clk or negedge sys_rst_n )begin
  32. if(!sys_rst_n)
  33. cmd_cnt<=0;
  34. else if(flash_start==9) //生成第一次flash_start
  35. spi_start<=1'b1;
  36. else if(idel_flag_r&&cmd_cnt<10)begin //状态抓取idel_flag_r状态
  37. cmd_cnt<=cmd_cnt+1; //切换下一次指令
  38. spi_start<=1'b1;
  39. end
  40. else begin
  41. cmd_cnt<=cmd_cnt;
  42. spi_start<=1'b0;
  43. end
  44. end
  45. always @(posedge sys_clk or negedge sys_rst_n )begin //数据逐次加一
  46. if(!sys_rst_n)
  47. spi_data<=8'd0;
  48. else if(w_data_req)
  49. spi_data<=spi_data+1'b1;
  50. else
  51. spi_data<=spi_data;
  52. end
  53. always @(*)begin //赋值命令
  54. case(cmd_cnt)
  55. 0:spi_cmd=WEL_CMD;
  56. 1:spi_cmd=C_ERA_CMD;
  57. 2:spi_cmd=R_STA_REG_CMD;
  58. 3:spi_cmd=WEL_CMD;
  59. 4:spi_cmd=WRITE_CMD;
  60. 5:spi_cmd=R_STA_REG_CMD;
  61. 6:spi_cmd=READ_CMD;
  62. 7:spi_cmd=WEL_CMD;
  63. 8:spi_cmd=S_ERA_CMD;
  64. 9:spi_cmd=R_STA_REG_CMD;
  65. 10:spi_cmd=READ_CMD;
  66. default:;
  67. endcase
  68. end
  69. endmodule

免责声明:本文所引用的各种资料均用于自己学习使用,这里感谢黑金和正点原子官方的资料以及各位优秀的创作者。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/510565
推荐阅读
相关标签
  

闽ICP备14008679号