当前位置:   article > 正文

Verilog:【8】基于FPGA实现SD NAND FLASH的SPI协议读写_verilog实现sd卡的读写

verilog实现sd卡的读写

碎碎念:

终于熬过了期末周,可以开始快乐的开发之旅了。

这一期作为一千粉后的首篇博客,由于之后项目会涉及到相关的部分,因此介绍的是使用FPGA实现SD NAND FLASH的读写操作,以雷龙发展提供的CS创世SD NAND FLASH样品为例,分别讲解电路连接、读写时序与仿真和实验结果。

目录

1 视频讲解

2 SD NAND FLASH背景介绍

3 样品申请

4 电路结构与接口协议

4.1 SD NAND

4.2 SD NAND测试板

4.3 FPGA开发板

5 SD卡协议与时序流程

5.1 SD卡协议

5.2 SD卡2.0版本初始化步骤

5.3 SD卡的读步骤

5.4 SD卡的写步骤

6 模块代码

6.1 sd_card_top

6.2 sd_card_cmd

6.3 sd_card_sec_read_write

6.4 spi_master

6.5 其余代码

6.5.1 sd_card_test

6.5.2 ax_debounce

6.5.3 seg_decoder

6.5.4 seg_scan

7 实验结果

8 参考资料


使用FPGA讲解SD NAND FLASH的文章网上也有很多比较详实的内容,本文的部分思路也是参考了其他博主的博客思路

1 视频讲解

为了便于更加清晰地讲解内容,本文也将文章的对应部分以视频的形式进行了录制:

(后期正在紧锣密鼓制作ing)

2 SD NAND FLASH背景介绍

目前市面上主流的存储芯片,分为了EEPROM、NOR FLASH、NAND FLASH三种,其中后两种是市面上主要的非易失闪存技术,他们分别具有不同的特点:

1.EEPROM

EEPROM (Electrically Erasable Programmable read only memory)是指带电可擦可编程只读存储器。是一种掉电后数据不丢失的存储芯片。 EEPROM 可以在电脑上或专用设备上擦除已有信息,重新编程。一般用在即插即用设备中。

相较于EEPROM计数,下文提到的FLASH技术,具有更快的速度,工艺上可以分为NOR FLASH和NAND FLASH两种

2.NOR FLASH

NOR FLASH是一种非易失闪存技术。其特点是芯片内执行 (XIP),应用程序可以直接在存储芯片内运行,不必再把代码读到系统 RAM 中。其传输效率较高高,在 1~4MB 的小容量时具有很高的成本效益。

3.NAND FLASH

NAND FLASH内部采用非线性宏单元模式,这种结构能提供极高的单元密度,并且写入和擦除的速度很快。作为当前最热门的存储芯片,目前生活中常见的电子产品都会使用到这种存储芯片,例如数码相机、U盘等等。

由于NAND FLASH在大容量应用中的便利性,因此作为今天介绍的主角~

什么是SD NAND呢(以下省略FLASH)?下面的内容是从雷龙发展官网的介绍中得到:

SD NAND俗称贴片式TF卡,尽管与TF卡名称类似,但是有较大的区别:

相比常见的TF卡,SD NAND是专门为内置存储进行设计,焊接在PCB板上以供工业级产品的应用。因此对品质稳定性、一致性、以及尺寸都有较高的要求。

下图中左侧即为SD NAND、右侧是常见的TF卡。

3 样品申请

本文所使用的CS创世SD NAND是从深圳雷龙发展申请获得,可以在官网中最上面找到申请样品的入口:

深圳市雷龙发展有限公司创立于2008年,专注NAND Flash设计研发13年。创始人均为步步高/华为技术背景出身。是一家专注于存储元器件代理分销商。 如果有一些技术问题也可以和其公司人员进行沟通,相关的工作人员非常专业和热心。

下图是我收到的测试样品:

4 电路结构与接口协议

4.1 SD NAND

本文所使用的产品是CSNP4GCR01-AMW,是雷龙的第二代产品,产品如下图所示:

数据手册可以在立创商城进行下载,其封装与连接的电路原理参考图如下图所示: 

芯片共包含8个引脚,包括4根数据线(6、7、1、2);2根电源线(4、8);1根时钟线(3);1根命令控制线(5)

手册中提供了SD NAND的两种使用模式,分别为SD MODE 以及 SPI MODE。他们所对应的引脚定义,如下图所示:

对于两种模式的切换,官方给出了初始化的方式。下文在代码的时序部分也会涉及到相关内容。

在对SD卡数据读写速度要求不高的情况下,选用SPI通信模式可以说是一种最佳方案。因为在该模式下,同只需要通过四根线就是可以完成所有的数据交换,可以为我们节省出宝贵的FPGA I/O资源。下图给出了SPI一对一通信时,主设备与从设备之间的连接关系。 

注:SPI协议详解传送门

因此本文主要介绍SPI MODE下各个引脚的功能:

引脚功能
CLK同步时钟线,与SPI总线时钟SCK相连
CMD命令控制线,与SPI总线的MOSI相连,主机用于发送命令
SDD0-3只有SDD0使用,与SPI总线MISO相连,用于主机选择从设备
VCC、VSS电源线

确定了通讯模式后,也就便于我们后文中,利用这种通讯模式按照SD卡的读写时序进行读写操作。

4.2 SD NAND测试板

单独的SD NAND不便于我们使用FPGA进行读写测试,好在官方提供了测试板,如下图所示:

有了它就可以轻松实现SD NAND与我们常见的FPGA开发板上的Micro SD插槽进行连接与测试了。

适用产品:LGA8,6x8mm 封装的SD NAND产品。

测试板尺寸:长度6.22厘米,宽度2.49厘米,接口长度2.53厘米。

使用方法:将芯片焊接至测试板上,可在原有的Micro SD卡座上直接调试和测试。

准备工具:热风枪,锡膏,镊子。温度要求:将热风枪温度调至300摄氏度℃即可焊接。

4.3 FPGA开发板

本文所使用的是黑金的AX301开发板,上面装有一个 Micro SD 卡座, FPGA 通过 SPI 数据总线访问 Micro SD 卡,SD 卡座和 FPGA 的硬件电路连接如下:

借由硬件电路的连接,FPGA可以直接与我们的SD NAND进行通信了。

至此,我们已经实现了SD NANDSPI通信方式方案的确定以及基于此的硬件电路连接,下一步就是根据SD卡的读写时序讲通信方式初始化为SPI模式,并按照SD卡协议进行读写操作。

5 SD卡协议与时序流程

5.1 SD卡协议

以下内容来自黑金的实验手册:

SD 卡的协议是一种简单的命令/响应的协议。全部命令由主机发起, SD 卡接收到命令后并返
回响应数据。根据命令的不同,返回的数据内容和长度也不同。 SD 卡命令是一个 6 字节组成的命
令包,其中第一个字节为命令号, 命令号高位 bit7 和 bit6 为固定的“01“,其它 6 个 bit 为具体
的命令号。第 2 个字节到第 5 个字节为命令参数。第 6 个字节为 7 个 bit 的 CRC 校验加 1 个 bit 的结束位。 如果在 SPI 模式的时候, CRC 校验位为可选。 如下图所示, Command 表示命令,通常使用十进制表示名称,例如 CMD17,这个时候 Command 就是十进制的 17。

对于详细的SD卡协议内容,可以参考传送门中的相关内容,给出了比较具体的解释。

SD 卡对每个命令会返回一个响应,每个命令有一定的响应格式。响应的格式跟给它的命令号
有关。在 SPI 模式中,有三种响应格式: R1, R2, R3。

在进行SD NAND的SPI模式读写操作时,主要使用到了以下几种SD卡命令,下面的表格进行简单介绍,这里可以找到完整版

5.2 SD卡2.0版本初始化步骤

  1. 上电后延时至少 74clock,等待 SD 卡内部操作完成
  2. 片选 CS 低电平选中 SD 卡
  3. 发送 CMD0,需要返回 0x01,进入 Idle 状态
  4. 为了区别 SD 卡是 2.0 还是 1.0,或是 MMC 卡,这里根据协议向上兼容的,首先发送只有SD2.0 才有的命令 CMD8,如果 CMD8 返回无错误,则初步判断为 2.0 卡,进一步循环发送命令 CMD55+ACMD41,直到返回 0x00,确定 SD2.0 卡
  5. 如果 CMD8 返回错误则判断为 1.0 卡还是 MMC 卡,循环发送 CMD55+ACMD41,返回无错误,则为 SD1.0 卡,到此 SD1.0 卡初始成功,如果在一定的循环次数下,返回为错误,则进一步发送 CMD1 进行初始化,如果返回无错误,则确定为 MMC 卡,如果在一定的次数下,返回为错误,则不能识别该卡,初始化结束。 (通过 CMD16 可以改变 SD 卡一次性读写的长度)
  6. CS 拉高

5.3 SD卡的读步骤

  1. 发送 CMD17(单块)或 CMD18(多块)读命令,返回 0X00
  2. 接收数据开始令牌 fe(或 fc) +正式数据 512Bytes + CRC 校验 2Bytes(默认正式传输的数据长度是 512Bytes)

5.4 SD卡的写步骤

  1. 发送 CMD24(单块)或 CMD25(多块)写命令,返回 0X00
  2. 发送数据开始令牌 fe(或 fc) +正式数据 512Bytes + CRC 校验 2Bytes

6 模块代码

本代码所实现的功能,是基于黑金AX301B,实现对SD NAND FLASH的数据写入与读取,并显示在开发板的数码管上。当按下开发板上的按键时,会自动将数据加一操作,并进行同步显示。

前文介绍的是SD NAND的协议以及初始化、读写操作的流程,下面介绍代码的组成部分,整个工程主要由以下部分模块构成:

sd_card_test(top模块)

        ax_debounce:ax_debounce_m0(按键消抖模块)

        sd_card_top:sd_card_top_m0(SD卡top模块)

                sd_card_cmd:sd_card_cmd_m0(SD卡指令)

                sd_card_sec_read_write:sd_card_sec_read_write_m0(SD卡读写)

                spi_master:spi_master_m0(SPI一个字节读写)

        seg_decoder:seg_decoder_m0(数码管控制)

        seg_decoder:seg_decoder_m1(数码管控制)

        seg_scan:seg_scan_m0(数码管控制)

下面主要介绍上述四个加粗的模块以及其功能

6.1 sd_card_top

本模块是SD card的top模块,用来实现不同子模块之间的连接。

  1. //
  2. // //
  3. // //
  4. // Author: meisq //
  5. // msq@qq.com //
  6. // ALINX(shanghai) Technology Co.,Ltd //
  7. // heijin //
  8. // WEB: http://www.alinx.cn/ //
  9. // BBS: http://www.heijin.org/ //
  10. // //
  11. //
  12. // //
  13. // Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
  14. // All rights reserved //
  15. // //
  16. // This source file may be used and distributed without restriction provided //
  17. // that this copyright statement is not removed from the file and that any //
  18. // derivative work contains the original copyright notice and the associated //
  19. // disclaimer. //
  20. // //
  21. //
  22. //==========================================================================
  23. // Revision History:
  24. // Date By Revision Change Description
  25. //--------------------------------------------------------------------------
  26. // 2017/6/21 meisq 1.0 Original
  27. //*************************************************************************/
  28. module sd_card_top
  29. #(
  30. parameter SPI_LOW_SPEED_DIV = 248, // SD card low speed mode frequency division parameter,spi clk speed = clk speed /((SPI_LOW_SPEED_DIV + 2) * 2 )
  31. parameter SPI_HIGH_SPEED_DIV = 0 // SD card high speed mode frequency division parameter,spi clk speed = clk speed /((SPI_HIGH_SPEED_DIV + 2) * 2 )
  32. )
  33. (
  34. input clk,
  35. input rst,
  36. output SD_nCS, //SD card chip select (SPI mode)
  37. output SD_DCLK, //SD card clock
  38. output SD_MOSI, //SD card controller data output
  39. input SD_MISO, //SD card controller data input
  40. output sd_init_done, //SD card initialization is complete
  41. input sd_sec_read, //SD card sector read
  42. input[31:0] sd_sec_read_addr, //SD card sector read address
  43. output[7:0] sd_sec_read_data, //SD card sector read data
  44. output sd_sec_read_data_valid, //SD card sector read data valid
  45. output sd_sec_read_end, //SD card sector read end
  46. input sd_sec_write, //SD card sector write
  47. input[31:0] sd_sec_write_addr, //SD card sector write address
  48. input[7:0] sd_sec_write_data, //SD card sector write data
  49. output sd_sec_write_data_req, //SD card sector write data next clock is valid
  50. output sd_sec_write_end //SD card sector write end
  51. );
  52. wire[15:0] spi_clk_div; //SPI module clock division parameter
  53. wire cmd_req; //SD card command request
  54. wire cmd_req_ack; //SD card command request response
  55. wire cmd_req_error; //SD card command request error
  56. wire[47:0] cmd; //SD card command
  57. wire[7:0] cmd_r1; //SD card expect response
  58. wire[15:0] cmd_data_len; //SD card command read data length
  59. wire block_read_req; //SD card sector data read request
  60. wire block_read_valid; //SD card sector data read data valid
  61. wire[7:0] block_read_data; //SD card sector data read data
  62. wire block_read_req_ack; //SD card sector data read response
  63. wire block_write_req; //SD card sector data write request
  64. wire[7:0] block_write_data; //SD card sector data write data next clock is valid
  65. wire block_write_data_rd; //SD card sector data write data
  66. wire block_write_req_ack; //SD card sector data write response
  67. wire nCS_ctrl; //SPI module chip select control
  68. wire spi_wr_req; //SPI module data sending request
  69. wire spi_wr_ack; //SPI module data request response
  70. wire[7:0] spi_data_in; //SPI module send data
  71. wire[7:0] spi_data_out; //SPI module data returned
  72. wire[15:0] clk_div;
  73. sd_card_sec_read_write
  74. #(
  75. .SPI_LOW_SPEED_DIV(SPI_LOW_SPEED_DIV),
  76. .SPI_HIGH_SPEED_DIV(SPI_HIGH_SPEED_DIV)
  77. )
  78. sd_card_sec_read_write_m0(
  79. .clk (clk ),
  80. .rst (rst ),
  81. .sd_init_done (sd_init_done ),
  82. .sd_sec_read (sd_sec_read ),
  83. .sd_sec_read_addr (sd_sec_read_addr ),
  84. .sd_sec_read_data (sd_sec_read_data ),
  85. .sd_sec_read_data_valid (sd_sec_read_data_valid ),
  86. .sd_sec_read_end (sd_sec_read_end ),
  87. .sd_sec_write (sd_sec_write ),
  88. .sd_sec_write_addr (sd_sec_write_addr ),
  89. .sd_sec_write_data (sd_sec_write_data ),
  90. .sd_sec_write_data_req (sd_sec_write_data_req ),
  91. .sd_sec_write_end (sd_sec_write_end ),
  92. .spi_clk_div (spi_clk_div ),
  93. .cmd_req (cmd_req ),
  94. .cmd_req_ack (cmd_req_ack ),
  95. .cmd_req_error (cmd_req_error ),
  96. .cmd (cmd ),
  97. .cmd_r1 (cmd_r1 ),
  98. .cmd_data_len (cmd_data_len ),
  99. .block_read_req (block_read_req ),
  100. .block_read_valid (block_read_valid ),
  101. .block_read_data (block_read_data ),
  102. .block_read_req_ack (block_read_req_ack ),
  103. .block_write_req (block_write_req ),
  104. .block_write_data (block_write_data ),
  105. .block_write_data_rd (block_write_data_rd ),
  106. .block_write_req_ack (block_write_req_ack )
  107. );
  108. sd_card_cmd sd_card_cmd_m0(
  109. .sys_clk (clk ),
  110. .rst (rst ),
  111. .spi_clk_div (spi_clk_div ),
  112. .cmd_req (cmd_req ),
  113. .cmd_req_ack (cmd_req_ack ),
  114. .cmd_req_error (cmd_req_error ),
  115. .cmd (cmd ),
  116. .cmd_r1 (cmd_r1 ),
  117. .cmd_data_len (cmd_data_len ),
  118. .block_read_req (block_read_req ),
  119. .block_read_req_ack (block_read_req_ack ),
  120. .block_read_data (block_read_data ),
  121. .block_read_valid (block_read_valid ),
  122. .block_write_req (block_write_req ),
  123. .block_write_data (block_write_data ),
  124. .block_write_data_rd (block_write_data_rd ),
  125. .block_write_req_ack (block_write_req_ack ),
  126. .nCS_ctrl (nCS_ctrl ),
  127. .clk_div (clk_div ),
  128. .spi_wr_req (spi_wr_req ),
  129. .spi_wr_ack (spi_wr_ack ),
  130. .spi_data_in (spi_data_in ),
  131. .spi_data_out (spi_data_out )
  132. );
  133. spi_master spi_master_m0(
  134. .sys_clk (clk ),
  135. .rst (rst ),
  136. .nCS (SD_nCS ),
  137. .DCLK (SD_DCLK ),
  138. .MOSI (SD_MOSI ),
  139. .MISO (SD_MISO ),
  140. .clk_div (clk_div ),
  141. .CPOL (1'b1 ),
  142. .CPHA (1'b1 ),
  143. .nCS_ctrl (nCS_ctrl ),
  144. .wr_req (spi_wr_req ),
  145. .wr_ack (spi_wr_ack ),
  146. .data_in (spi_data_in ),
  147. .data_out (spi_data_out )
  148. );
  149. endmodule

6.2 sd_card_cmd

sd_card_cmd 模块主要实验 sd 卡基本命令操作,还有上电初始化的 88 个周期的时钟,数据
块的读写,状态机如下:

代码如下:

  1. //
  2. // //
  3. // //
  4. // Author: meisq //
  5. // msq@qq.com //
  6. // ALINX(shanghai) Technology Co.,Ltd //
  7. // heijin //
  8. // WEB: http://www.alinx.cn/ //
  9. // BBS: http://www.heijin.org/ //
  10. // //
  11. //
  12. // //
  13. // Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
  14. // All rights reserved //
  15. // //
  16. // This source file may be used and distributed without restriction provided //
  17. // that this copyright statement is not removed from the file and that any //
  18. // derivative work contains the original copyright notice and the associated //
  19. // disclaimer. //
  20. // //
  21. //
  22. //==========================================================================
  23. // Revision History:
  24. // Date By Revision Change Description
  25. //--------------------------------------------------------------------------
  26. // 2017/6/21 meisq 1.0 Original
  27. //*************************************************************************/
  28. module sd_card_cmd(
  29. input sys_clk,
  30. input rst,
  31. input[15:0] spi_clk_div, //SPI module clock division parameter
  32. input cmd_req, //SD card command request
  33. output cmd_req_ack, //SD card command request response
  34. output reg cmd_req_error, //SD card command request error
  35. input[47:0] cmd, //SD card command
  36. input[7:0] cmd_r1, //SD card expect response
  37. input[15:0] cmd_data_len, //SD card command read data length
  38. input block_read_req, //SD card sector data read request
  39. output reg block_read_valid, //SD card sector data read data valid
  40. output reg[7:0] block_read_data, //SD card sector data read data
  41. output block_read_req_ack, //SD card sector data read response
  42. input block_write_req, //SD card sector data write request
  43. input[7:0] block_write_data, //SD card sector data write data next clock is valid
  44. output block_write_data_rd, //SD card sector data write data
  45. output block_write_req_ack, //SD card sector data write response
  46. output nCS_ctrl, //SPI module chip select control
  47. output reg[15:0] clk_div,
  48. output reg spi_wr_req, //SPI module data sending request
  49. input spi_wr_ack, //SPI module data request response
  50. output[7:0] spi_data_in, //SPI module send data
  51. input[7:0] spi_data_out //SPI module data returned
  52. );
  53. parameter S_IDLE = 0;
  54. parameter S_WAIT = 1;
  55. parameter S_INIT = 2;
  56. parameter S_CMD_PRE = 3;
  57. parameter S_CMD = 4;
  58. parameter S_CMD_DATA = 5;
  59. parameter S_READ_WAIT = 6;
  60. parameter S_READ = 7;
  61. parameter S_READ_ACK = 8;
  62. parameter S_WRITE_TOKEN = 9;
  63. parameter S_WRITE_DATA_0 = 10;
  64. parameter S_WRITE_DATA_1 = 11;
  65. parameter S_WRITE_CRC = 12;
  66. parameter S_WRITE_ACK = 13;
  67. parameter S_ERR = 14;
  68. parameter S_END = 15;
  69. reg[3:0] state;
  70. reg CS_reg;
  71. reg[15:0] byte_cnt;
  72. reg[7:0] send_data;
  73. wire[7:0] data_recv;
  74. reg[9:0] wr_data_cnt;
  75. assign cmd_req_ack = (state == S_END);
  76. assign block_read_req_ack = (state == S_READ_ACK);
  77. assign block_write_req_ack= (state == S_WRITE_ACK);
  78. assign block_write_data_rd = (state == S_WRITE_DATA_0);
  79. assign spi_data_in = send_data;
  80. assign data_recv = spi_data_out;
  81. assign nCS_ctrl = CS_reg;
  82. always@(posedge sys_clk or posedge rst)
  83. begin
  84. if(rst == 1'b1)
  85. begin
  86. CS_reg <= 1'b1;
  87. spi_wr_req <= 1'b0;
  88. byte_cnt <= 16'd0;
  89. clk_div <= 16'd0;
  90. send_data <= 8'hff;
  91. state <= S_IDLE;
  92. cmd_req_error <= 1'b0;
  93. wr_data_cnt <= 10'd0;
  94. end
  95. else
  96. case(state)
  97. S_IDLE:
  98. begin
  99. state <= S_INIT;
  100. clk_div <= spi_clk_div;
  101. CS_reg <= 1'b1;
  102. end
  103. S_INIT:
  104. begin
  105. //send 11 bytes on power(at least 74 SPI clocks)
  106. if(spi_wr_ack == 1'b1)
  107. begin
  108. if(byte_cnt >= 16'd10)
  109. begin
  110. byte_cnt <= 16'd0;
  111. spi_wr_req <= 1'b0;
  112. state <= S_WAIT;
  113. end
  114. begin
  115. byte_cnt <= byte_cnt + 16'd1;
  116. end
  117. end
  118. else
  119. begin
  120. spi_wr_req <= 1'b1;
  121. send_data <= 8'hff;
  122. end
  123. end
  124. S_WAIT:
  125. begin
  126. cmd_req_error <= 1'b0;
  127. wr_data_cnt <= 10'd0;
  128. //wait for instruction
  129. if(cmd_req == 1'b1)
  130. state <= S_CMD_PRE;
  131. else if(block_read_req == 1'b1)
  132. state <= S_READ_WAIT;
  133. else if(block_write_req == 1'b1)
  134. state <= S_WRITE_TOKEN;
  135. clk_div <= spi_clk_div;
  136. end
  137. S_CMD_PRE:
  138. begin
  139. //before sending a command, send an byte 'ff',provide some clocks
  140. if(spi_wr_ack == 1'b1)
  141. begin
  142. state <= S_CMD;
  143. spi_wr_req <= 1'b0;
  144. byte_cnt <= 16'd0;
  145. end
  146. else
  147. begin
  148. spi_wr_req <= 1'b1;
  149. CS_reg <= 1'b1;
  150. send_data <= 8'hff;
  151. end
  152. end
  153. S_CMD:
  154. begin
  155. if(spi_wr_ack == 1'b1)
  156. begin
  157. if((byte_cnt == 16'hffff) || (data_recv != cmd_r1 && data_recv[7] == 1'b0))
  158. begin
  159. state <= S_ERR;
  160. spi_wr_req <= 1'b0;
  161. end
  162. else if(data_recv == cmd_r1)
  163. begin
  164. spi_wr_req <= 1'b0;
  165. if(cmd_data_len != 16'd0)
  166. begin
  167. state <= S_CMD_DATA;
  168. byte_cnt <= 16'd0;
  169. end
  170. else
  171. state <= S_END;
  172. end
  173. else
  174. byte_cnt <= byte_cnt + 16'd1;
  175. end
  176. else
  177. begin
  178. spi_wr_req <= 1'b1;
  179. CS_reg <= 1'b0;
  180. if(byte_cnt == 16'd0)
  181. send_data <= (cmd[47:40] | 8'h40);
  182. else if(byte_cnt == 16'd1)
  183. send_data <= cmd[39:32];
  184. else if(byte_cnt == 16'd2)
  185. send_data <= cmd[31:24];
  186. else if(byte_cnt == 16'd3)
  187. send_data <= cmd[23:16];
  188. else if(byte_cnt == 16'd4)
  189. send_data <= cmd[15:8];
  190. else if(byte_cnt == 16'd5)
  191. send_data <= cmd[7:0];
  192. else
  193. send_data <= 8'hff;
  194. end
  195. end
  196. S_CMD_DATA:
  197. begin
  198. if(spi_wr_ack == 1'b1)
  199. begin
  200. if(byte_cnt == cmd_data_len - 16'd1)
  201. begin
  202. state <= S_END;
  203. spi_wr_req <= 1'b0;
  204. byte_cnt <= 16'd0;
  205. end
  206. else
  207. begin
  208. byte_cnt <= byte_cnt + 16'd1;
  209. end
  210. end
  211. else
  212. begin
  213. spi_wr_req <= 1'b1;
  214. send_data <= 8'hff;
  215. end
  216. end
  217. S_READ_WAIT:
  218. begin
  219. if(spi_wr_ack == 1'b1 && data_recv == 8'hfe)
  220. begin
  221. spi_wr_req <= 1'b0;
  222. state <= S_READ;
  223. byte_cnt <= 16'd0;
  224. end
  225. else
  226. begin
  227. spi_wr_req <= 1'b1;
  228. send_data <= 8'hff;
  229. end
  230. end
  231. S_READ:
  232. begin
  233. if(spi_wr_ack == 1'b1)
  234. begin
  235. if(byte_cnt == 16'd513)
  236. begin
  237. state <= S_READ_ACK;
  238. spi_wr_req <= 1'b0;
  239. byte_cnt <= 16'd0;
  240. end
  241. else
  242. begin
  243. byte_cnt <= byte_cnt + 16'd1;
  244. end
  245. end
  246. else
  247. begin
  248. spi_wr_req <= 1'b1;
  249. send_data <= 8'hff;
  250. end
  251. end
  252. S_WRITE_TOKEN:
  253. if(spi_wr_ack == 1'b1)
  254. begin
  255. state <= S_WRITE_DATA_0;
  256. spi_wr_req <= 1'b0;
  257. end
  258. else
  259. begin
  260. spi_wr_req <= 1'b1;
  261. send_data <= 8'hfe;
  262. end
  263. S_WRITE_DATA_0:
  264. begin
  265. state <= S_WRITE_DATA_1;
  266. wr_data_cnt <= wr_data_cnt + 10'd1;
  267. end
  268. S_WRITE_DATA_1:
  269. begin
  270. if(spi_wr_ack == 1'b1 && wr_data_cnt == 10'd512)
  271. begin
  272. state <= S_WRITE_CRC;
  273. spi_wr_req <= 1'b0;
  274. end
  275. else if(spi_wr_ack == 1'b1)
  276. begin
  277. state <= S_WRITE_DATA_0;
  278. spi_wr_req <= 1'b0;
  279. end
  280. else
  281. begin
  282. spi_wr_req <= 1'b1;
  283. send_data <= block_write_data;
  284. end
  285. end
  286. S_WRITE_CRC:
  287. begin
  288. if(spi_wr_ack == 1'b1)
  289. begin
  290. if(byte_cnt == 16'd2)
  291. begin
  292. state <= S_WRITE_ACK;
  293. spi_wr_req <= 1'b0;
  294. byte_cnt <= 16'd0;
  295. end
  296. else
  297. begin
  298. byte_cnt <= byte_cnt + 16'd1;
  299. end
  300. end
  301. else
  302. begin
  303. spi_wr_req <= 1'b1;
  304. send_data <= 8'hff;
  305. end
  306. end
  307. S_ERR:
  308. begin
  309. state <= S_END;
  310. cmd_req_error <= 1'b1;
  311. end
  312. S_READ_ACK,S_WRITE_ACK,S_END:
  313. begin
  314. state <= S_WAIT;
  315. end
  316. default:
  317. state <= S_IDLE;
  318. endcase
  319. end
  320. always@(posedge sys_clk or posedge rst)
  321. begin
  322. if(rst == 1'b1)
  323. block_read_valid <= 1'b0;
  324. else if(state == S_READ && byte_cnt < 16'd512)
  325. block_read_valid <= spi_wr_ack;
  326. else
  327. block_read_valid <= 1'b0;
  328. end
  329. always@(posedge sys_clk or posedge rst)
  330. begin
  331. if(rst == 1'b1)
  332. block_read_data <= 8'd0;
  333. else if(state == S_READ && spi_wr_ack == 1'b1)
  334. block_read_data <= data_recv;
  335. end
  336. endmodule

6.3 sd_card_sec_read_write

sd_card_sec_read_write 模块继续完成 SD 卡初始化,然后等待扇区读写指令,并完成扇区的
读写操作。 下图为模块的状态机转换图,首先发送 CMD0 命令,然后发送 CMD8 命令,再发送
CMD55,接着发送 ACMD41,如果应答正常, sd 卡初始化完成,等待扇区的读写。
 

代码如下: 

  1. //
  2. // //
  3. // //
  4. // Author: meisq //
  5. // msq@qq.com //
  6. // ALINX(shanghai) Technology Co.,Ltd //
  7. // heijin //
  8. // WEB: http://www.alinx.cn/ //
  9. // BBS: http://www.heijin.org/ //
  10. // //
  11. //
  12. // //
  13. // Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
  14. // All rights reserved //
  15. // //
  16. // This source file may be used and distributed without restriction provided //
  17. // that this copyright statement is not removed from the file and that any //
  18. // derivative work contains the original copyright notice and the associated //
  19. // disclaimer. //
  20. // //
  21. //
  22. //===============================================================================
  23. // Revision History:
  24. // Date By Revision Change Description
  25. //-------------------------------------------------------------------------------
  26. // 2017/6/21 meisq 1.0 Original
  27. //*******************************************************************************/
  28. module sd_card_sec_read_write
  29. #(
  30. parameter SPI_LOW_SPEED_DIV = 248, // spi clk speed = clk speed /((SPI_LOW_SPEED_DIV + 2) * 2 )
  31. parameter SPI_HIGH_SPEED_DIV = 0 // spi clk speed = clk speed /((SPI_HIGH_SPEED_DIV + 2) * 2 )
  32. )
  33. (
  34. input clk,
  35. input rst,
  36. output reg sd_init_done,
  37. input sd_sec_read,
  38. input[31:0] sd_sec_read_addr,
  39. output[7:0] sd_sec_read_data,
  40. output sd_sec_read_data_valid,
  41. output sd_sec_read_end,
  42. input sd_sec_write,
  43. input[31:0] sd_sec_write_addr,
  44. input[7:0] sd_sec_write_data,
  45. output sd_sec_write_data_req,
  46. output sd_sec_write_end,
  47. output reg[15:0] spi_clk_div,
  48. output reg cmd_req,
  49. input cmd_req_ack,
  50. input cmd_req_error,
  51. output reg[47:0] cmd,
  52. output reg[7:0] cmd_r1,
  53. output reg[15:0] cmd_data_len,
  54. output reg block_read_req,
  55. input block_read_valid,
  56. input[7:0] block_read_data,
  57. input block_read_req_ack,
  58. output reg block_write_req,
  59. output[7:0] block_write_data,
  60. input block_write_data_rd,
  61. input block_write_req_ack
  62. );
  63. reg[7:0] read_data;
  64. reg[31:0] timer;
  65. localparam S_IDLE = 0;
  66. localparam S_CMD0 = 1;
  67. localparam S_CMD8 = 2;
  68. localparam S_CMD55 = 3;
  69. localparam S_CMD41 = 4;
  70. localparam S_CMD17 = 5;
  71. localparam S_READ = 6;
  72. localparam S_CMD24 = 7;
  73. localparam S_WRITE = 8;
  74. localparam S_ERR = 14;
  75. localparam S_WRITE_END = 15;
  76. localparam S_READ_END = 16;
  77. localparam S_WAIT_READ_WRITE = 17;
  78. localparam S_CMD16 = 18;
  79. reg[4:0] state;
  80. reg[31:0] sec_addr;
  81. assign sd_sec_read_data_valid = (state == S_READ) && block_read_valid;
  82. assign sd_sec_read_data = block_read_data;
  83. assign sd_sec_read_end = (state == S_READ_END);
  84. assign sd_sec_write_data_req = (state == S_WRITE) && block_write_data_rd;
  85. assign block_write_data = sd_sec_write_data;
  86. assign sd_sec_write_end = (state == S_WRITE_END);
  87. always@(posedge clk or posedge rst)
  88. begin
  89. if(rst == 1'b1)
  90. begin
  91. state <= S_IDLE;
  92. cmd_req <= 1'b0;
  93. cmd_data_len <= 16'd0;
  94. cmd_r1 <= 8'd0;
  95. cmd <= 48'd0;
  96. spi_clk_div <= SPI_LOW_SPEED_DIV[15:0];
  97. block_write_req <= 1'b0;
  98. block_read_req <= 1'b0;
  99. sec_addr <= 32'd0;
  100. sd_init_done <= 1'b0;
  101. end
  102. else
  103. case(state)
  104. S_IDLE:
  105. begin
  106. state <= S_CMD0;
  107. sd_init_done <= 1'b0;
  108. spi_clk_div <= SPI_LOW_SPEED_DIV[15:0];
  109. end
  110. S_CMD0:
  111. begin
  112. if(cmd_req_ack & ~cmd_req_error)
  113. begin
  114. state <= S_CMD8;
  115. cmd_req <= 1'b0;
  116. end
  117. else
  118. begin
  119. cmd_req <= 1'b1;
  120. cmd_data_len <= 16'd0;
  121. cmd_r1 <= 8'h01;
  122. cmd <= {8'd0,8'h00,8'h00,8'h00,8'h00,8'h95};
  123. end
  124. end
  125. S_CMD8:
  126. begin
  127. if(cmd_req_ack & ~cmd_req_error)
  128. begin
  129. state <= S_CMD55;
  130. cmd_req <= 1'b0;
  131. end
  132. else
  133. begin
  134. cmd_req <= 1'b1;
  135. cmd_data_len <= 16'd4;
  136. cmd_r1 <= 8'h01;
  137. cmd <= {8'd8,8'h00,8'h00,8'h01,8'haa,8'h87};
  138. end
  139. end
  140. S_CMD55:
  141. begin
  142. if(cmd_req_ack & ~cmd_req_error)
  143. begin
  144. state <= S_CMD41;
  145. cmd_req <= 1'b0;
  146. end
  147. else
  148. begin
  149. cmd_req <= 1'b1;
  150. cmd_data_len <= 16'd0;
  151. cmd_r1 <= 8'h01;
  152. cmd <= {8'd55,8'h00,8'h00,8'h00,8'h00,8'hff};
  153. end
  154. end
  155. S_CMD41:
  156. begin
  157. if(cmd_req_ack & ~cmd_req_error)
  158. begin
  159. state <= S_CMD16;
  160. cmd_req <= 1'b0;
  161. sd_init_done <= 1'b1;
  162. spi_clk_div <= SPI_HIGH_SPEED_DIV[15:0];
  163. end
  164. else if(cmd_req_ack)
  165. begin
  166. state <= S_CMD55;
  167. end
  168. else
  169. begin
  170. cmd_req <= 1'b1;
  171. cmd_data_len <= 16'd0;
  172. cmd_r1 <= 8'h00;
  173. cmd <= {8'd41,8'h40,8'h00,8'h00,8'h00,8'hff};
  174. end
  175. end
  176. S_CMD16:
  177. begin
  178. if(cmd_req_ack & ~cmd_req_error)
  179. begin
  180. state <= S_WAIT_READ_WRITE;
  181. cmd_req <= 1'b0;
  182. sd_init_done <= 1'b1;
  183. spi_clk_div <= SPI_HIGH_SPEED_DIV[15:0];
  184. end
  185. else if(cmd_req_ack)
  186. begin
  187. state <= S_CMD55;
  188. end
  189. else
  190. begin
  191. cmd_req <= 1'b1;
  192. cmd_data_len <= 16'd0;
  193. cmd_r1 <= 8'h00;
  194. cmd <= {8'd16,32'd512,8'hff};
  195. end
  196. end
  197. S_WAIT_READ_WRITE:
  198. begin
  199. if(sd_sec_write == 1'b1)
  200. begin
  201. state <= S_CMD24;
  202. sec_addr <= sd_sec_write_addr;
  203. end
  204. else if(sd_sec_read == 1'b1)
  205. begin
  206. state <= S_CMD17;
  207. sec_addr <= sd_sec_read_addr;
  208. end
  209. spi_clk_div <= 16'd0;
  210. end
  211. S_CMD24:
  212. begin
  213. if(cmd_req_ack & ~cmd_req_error)
  214. begin
  215. state <= S_WRITE;
  216. cmd_req <= 1'b0;
  217. end
  218. else
  219. begin
  220. cmd_req <= 1'b1;
  221. cmd_data_len <= 16'd0;
  222. cmd_r1 <= 8'h00;
  223. cmd <= {8'd24,sec_addr,8'hff};
  224. end
  225. end
  226. S_WRITE:
  227. begin
  228. if(block_write_req_ack == 1'b1)
  229. begin
  230. block_write_req <= 1'b0;
  231. state <= S_WRITE_END;
  232. end
  233. else
  234. block_write_req <= 1'b1;
  235. end
  236. S_CMD17:
  237. begin
  238. if(cmd_req_ack & ~cmd_req_error)
  239. begin
  240. state <= S_READ;
  241. cmd_req <= 1'b0;
  242. end
  243. else
  244. begin
  245. cmd_req <= 1'b1;
  246. cmd_data_len <= 16'd0;
  247. cmd_r1 <= 8'h00;
  248. cmd <= {8'd17,sec_addr,8'hff};
  249. end
  250. end
  251. S_READ:
  252. begin
  253. if(block_read_req_ack)
  254. begin
  255. state <= S_READ_END;
  256. block_read_req <= 1'b0;
  257. end
  258. else
  259. begin
  260. block_read_req <= 1'b1;
  261. end
  262. end
  263. S_WRITE_END:
  264. begin
  265. state <= S_WAIT_READ_WRITE;
  266. end
  267. S_READ_END:
  268. begin
  269. state <= S_WAIT_READ_WRITE;
  270. end
  271. default:
  272. state <= S_IDLE;
  273. endcase
  274. end
  275. endmodule

6.4 spi_master

这一模块用来完成SPI一个字节的读写。

spi master 状态机设计, 主要完成一个字节 spi 数据的读写,由于是全双工的,写一个字节的
同时也读一个字节。 首先空闲状态“IDLE”接收到写请求后进入“DCLK_IDLE”状态,这个状态为
spi 时钟沿变化保持一定的时间,用来控制 spi 时钟的周期,然后进入 spi 时钟沿的变化状态,一
个字节上升沿和下降沿一共 16 个数据沿。 在最后一个数据沿进入“LAST_HALF_CYCLE”状态,为
让最后一个沿也保持一定的时间,再进入应答状态,完成一次写请求。spi_master 模块中模拟了一个 spi 时钟,在状态机进入到‘DCLK_EDGE’时进行翻转。状态机图示如下:

 代码如下:

  1. //
  2. // //
  3. // //
  4. // Author: meisq //
  5. // msq@qq.com //
  6. // ALINX(shanghai) Technology Co.,Ltd //
  7. // heijin //
  8. // WEB: http://www.alinx.cn/ //
  9. // BBS: http://www.heijin.org/ //
  10. // //
  11. //
  12. // //
  13. // Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
  14. // All rights reserved //
  15. // //
  16. // This source file may be used and distributed without restriction provided //
  17. // that this copyright statement is not removed from the file and that any //
  18. // derivative work contains the original copyright notice and the associated //
  19. // disclaimer. //
  20. // //
  21. //
  22. //==========================================================================
  23. // Revision History:
  24. // Date By Revision Change Description
  25. //--------------------------------------------------------------------------
  26. // 2017/6/19 meisq 1.0 Original
  27. //*************************************************************************/
  28. module spi_master
  29. (
  30. input sys_clk,
  31. input rst,
  32. output nCS, //chip select (SPI mode)
  33. output DCLK, //spi clock
  34. output MOSI, //spi data output
  35. input MISO, //spi input
  36. input CPOL,
  37. input CPHA,
  38. input nCS_ctrl,
  39. input[15:0] clk_div,
  40. input wr_req,
  41. output wr_ack,
  42. input[7:0] data_in,
  43. output[7:0] data_out
  44. );
  45. localparam IDLE = 0;
  46. localparam DCLK_EDGE = 1;
  47. localparam DCLK_IDLE = 2;
  48. localparam ACK = 3;
  49. localparam LAST_HALF_CYCLE = 4;
  50. localparam ACK_WAIT = 5;
  51. reg DCLK_reg;
  52. reg[7:0] MOSI_shift;
  53. reg[7:0] MISO_shift;
  54. reg[2:0] state;
  55. reg[2:0] next_state;
  56. reg [15:0] clk_cnt;
  57. reg[4:0] clk_edge_cnt;
  58. assign MOSI = MOSI_shift[7];
  59. assign DCLK = DCLK_reg;
  60. assign data_out = MISO_shift;
  61. assign wr_ack = (state == ACK);
  62. assign nCS = nCS_ctrl;
  63. always@(posedge sys_clk or posedge rst)
  64. begin
  65. if(rst)
  66. state <= IDLE;
  67. else
  68. state <= next_state;
  69. end
  70. always@(*)
  71. begin
  72. case(state)
  73. IDLE:
  74. if(wr_req == 1'b1)
  75. next_state <= DCLK_IDLE;
  76. else
  77. next_state <= IDLE;
  78. DCLK_IDLE:
  79. //half a SPI clock cycle produces a clock edge
  80. if(clk_cnt == clk_div)
  81. next_state <= DCLK_EDGE;
  82. else
  83. next_state <= DCLK_IDLE;
  84. DCLK_EDGE:
  85. //a SPI byte with a total of 16 clock edges
  86. if(clk_edge_cnt == 5'd15)
  87. next_state <= LAST_HALF_CYCLE;
  88. else
  89. next_state <= DCLK_IDLE;
  90. //this is the last data edge
  91. LAST_HALF_CYCLE:
  92. if(clk_cnt == clk_div)
  93. next_state <= ACK;
  94. else
  95. next_state <= LAST_HALF_CYCLE;
  96. //send one byte complete
  97. ACK:
  98. next_state <= ACK_WAIT;
  99. //wait for one clock cycle, to ensure that the cancel request signal
  100. ACK_WAIT:
  101. next_state <= IDLE;
  102. default:
  103. next_state <= IDLE;
  104. endcase
  105. end
  106. always@(posedge sys_clk or posedge rst)
  107. begin
  108. if(rst)
  109. DCLK_reg <= 1'b0;
  110. else if(state == IDLE)
  111. DCLK_reg <= CPOL;
  112. else if(state == DCLK_EDGE)
  113. DCLK_reg <= ~DCLK_reg;//SPI clock edge
  114. end
  115. //SPI clock wait counter
  116. always@(posedge sys_clk or posedge rst)
  117. begin
  118. if(rst)
  119. clk_cnt <= 16'd0;
  120. else if(state == DCLK_IDLE || state == LAST_HALF_CYCLE)
  121. clk_cnt <= clk_cnt + 16'd1;
  122. else
  123. clk_cnt <= 16'd0;
  124. end
  125. //SPI clock edge counter
  126. always@(posedge sys_clk or posedge rst)
  127. begin
  128. if(rst)
  129. clk_edge_cnt <= 5'd0;
  130. else if(state == DCLK_EDGE)
  131. clk_edge_cnt <= clk_edge_cnt + 5'd1;
  132. else if(state == IDLE)
  133. clk_edge_cnt <= 5'd0;
  134. end
  135. //SPI data output
  136. always@(posedge sys_clk or posedge rst)
  137. begin
  138. if(rst)
  139. MOSI_shift <= 8'd0;
  140. else if(state == IDLE && wr_req)
  141. MOSI_shift <= data_in;
  142. else if(state == DCLK_EDGE)
  143. if(CPHA == 1'b0 && clk_edge_cnt[0] == 1'b1)
  144. MOSI_shift <= {MOSI_shift[6:0],MOSI_shift[7]};
  145. else if(CPHA == 1'b1 && (clk_edge_cnt != 5'd0 && clk_edge_cnt[0] == 1'b0))
  146. MOSI_shift <= {MOSI_shift[6:0],MOSI_shift[7]};
  147. end
  148. //SPI data input
  149. always@(posedge sys_clk or posedge rst)
  150. begin
  151. if(rst)
  152. MISO_shift <= 8'd0;
  153. else if(state == IDLE && wr_req)
  154. MISO_shift <= 8'h00;
  155. else if(state == DCLK_EDGE)
  156. if(CPHA == 1'b0 && clk_edge_cnt[0] == 1'b0)
  157. MISO_shift <= {MISO_shift[6:0],MISO};
  158. else if(CPHA == 1'b1 && (clk_edge_cnt[0] == 1'b1))
  159. MISO_shift <= {MISO_shift[6:0],MISO};
  160. end
  161. endmodule

6.5 其余代码

6.5.1 sd_card_test

  1. //
  2. // //
  3. // //
  4. // Author: meisq //
  5. // msq@qq.com //
  6. // ALINX(shanghai) Technology Co.,Ltd //
  7. // heijin //
  8. // WEB: http://www.alinx.cn/ //
  9. // BBS: http://www.heijin.org/ //
  10. // //
  11. //
  12. // //
  13. // Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
  14. // All rights reserved //
  15. // //
  16. // This source file may be used and distributed without restriction provided //
  17. // that this copyright statement is not removed from the file and that any //
  18. // derivative work contains the original copyright notice and the associated //
  19. // disclaimer. //
  20. // //
  21. //
  22. //================================================================================
  23. // Revision History:
  24. // Date By Revision Change Description
  25. //--------------------------------------------------------------------------------
  26. // 2017/6/19 meisq 1.0 Original
  27. //*******************************************************************************/
  28. module sd_card_test(
  29. input clk,
  30. input rst_n,
  31. input key1,
  32. output SD_nCS,
  33. output SD_DCLK,
  34. output SD_MOSI,
  35. input SD_MISO,
  36. output [5:0] seg_sel,
  37. output [7:0] seg_data
  38. );
  39. parameter S_IDLE = 0;
  40. parameter S_READ = 1;
  41. parameter S_WRITE = 2;
  42. parameter S_END = 3;
  43. reg[3:0] state;
  44. wire sd_init_done;
  45. reg sd_sec_read;
  46. wire[31:0] sd_sec_read_addr;
  47. wire[7:0] sd_sec_read_data;
  48. wire sd_sec_read_data_valid;
  49. wire sd_sec_read_end;
  50. reg sd_sec_write;
  51. wire[31:0] sd_sec_write_addr;
  52. reg [7:0] sd_sec_write_data;
  53. wire sd_sec_write_data_req;
  54. wire sd_sec_write_end;
  55. reg[9:0] wr_cnt;
  56. reg[9:0] rd_cnt;
  57. wire button_negedge;
  58. reg[7:0] read_data;
  59. ax_debounce ax_debounce_m0
  60. (
  61. .clk (clk),
  62. .rst (~rst_n),
  63. .button_in (key1),
  64. .button_posedge (),
  65. .button_negedge (button_negedge),
  66. .button_out ()
  67. );
  68. wire[6:0] seg_data_0;
  69. seg_decoder seg_decoder_m0(
  70. .bin_data (read_data[3:0]),
  71. .seg_data (seg_data_0)
  72. );
  73. wire[6:0] seg_data_1;
  74. seg_decoder seg_decoder_m1(
  75. .bin_data (read_data[7:4]),
  76. .seg_data (seg_data_1)
  77. );
  78. seg_scan seg_scan_m0(
  79. .clk (clk),
  80. .rst_n (rst_n),
  81. .seg_sel (seg_sel),
  82. .seg_data (seg_data),
  83. .seg_data_0 ({1'b1,7'b1111_111}),
  84. .seg_data_1 ({1'b1,7'b1111_111}),
  85. .seg_data_2 ({1'b1,7'b1111_111}),
  86. .seg_data_3 ({1'b1,7'b1111_111}),
  87. .seg_data_4 ({1'b1,seg_data_1}),
  88. .seg_data_5 ({sd_init_done,seg_data_0})
  89. );
  90. always@(posedge clk or negedge rst_n)
  91. begin
  92. if(rst_n == 1'b0)
  93. wr_cnt <= 10'd0;
  94. else if(state == S_WRITE)
  95. begin
  96. if(sd_sec_write_data_req == 1'b1)
  97. wr_cnt <= wr_cnt + 10'd1;
  98. end
  99. else
  100. wr_cnt <= 10'd0;
  101. end
  102. always@(posedge clk or negedge rst_n)
  103. begin
  104. if(rst_n == 1'b0)
  105. rd_cnt <= 10'd0;
  106. else if(state == S_READ)
  107. begin
  108. if(sd_sec_read_data_valid == 1'b1)
  109. rd_cnt <= rd_cnt + 10'd1;
  110. end
  111. else
  112. rd_cnt <= 10'd0;
  113. end
  114. always@(posedge clk or negedge rst_n)
  115. begin
  116. if(rst_n == 1'b0)
  117. read_data <= 8'd0;
  118. else if(state == S_READ)
  119. begin
  120. if(sd_sec_read_data_valid == 1'b1 && rd_cnt == 10'd0)
  121. read_data <= sd_sec_read_data;
  122. end
  123. else if(state == S_END && button_negedge == 1'b1)
  124. read_data <= read_data + 8'd1;
  125. end
  126. always@(posedge clk or negedge rst_n)
  127. begin
  128. if(rst_n == 1'b0)
  129. sd_sec_write_data <= 8'd0;
  130. else if(sd_sec_write_data_req)
  131. sd_sec_write_data <= read_data + wr_cnt[7:0];
  132. end
  133. always@(posedge clk or negedge rst_n)
  134. begin
  135. if(rst_n == 1'b0)
  136. begin
  137. state <= S_IDLE;
  138. sd_sec_read <= 1'b0;
  139. sd_sec_write <= 1'b0;
  140. end
  141. else if(sd_init_done == 1'b0)
  142. begin
  143. state <= S_IDLE;
  144. end
  145. else
  146. case(state)
  147. S_IDLE:
  148. begin
  149. state <= S_READ;
  150. end
  151. S_WRITE:
  152. begin
  153. if(sd_sec_write_end == 1'b1)
  154. begin
  155. sd_sec_write <= 1'b0;
  156. state <= S_READ;
  157. end
  158. else
  159. sd_sec_write <= 1'b1;
  160. end
  161. S_READ:
  162. begin
  163. if(sd_sec_read_end == 1'b1)
  164. begin
  165. state <= S_END;
  166. sd_sec_read <= 1'b0;
  167. end
  168. else
  169. begin
  170. sd_sec_read <= 1'b1;
  171. end
  172. end
  173. S_END:
  174. begin
  175. if(button_negedge == 1'b1)
  176. state <= S_WRITE;
  177. end
  178. default:
  179. state <= S_IDLE;
  180. endcase
  181. end
  182. sd_card_top sd_card_top_m0(
  183. .clk (clk ),
  184. .rst (~rst_n ),
  185. .SD_nCS (SD_nCS ),
  186. .SD_DCLK (SD_DCLK ),
  187. .SD_MOSI (SD_MOSI ),
  188. .SD_MISO (SD_MISO ),
  189. .sd_init_done (sd_init_done ),
  190. .sd_sec_read (sd_sec_read ),
  191. .sd_sec_read_addr (sd_sec_read_addr ),
  192. .sd_sec_read_data (sd_sec_read_data ),
  193. .sd_sec_read_data_valid (sd_sec_read_data_valid ),
  194. .sd_sec_read_end (sd_sec_read_end ),
  195. .sd_sec_write (sd_sec_write ),
  196. .sd_sec_write_addr (sd_sec_write_addr ),
  197. .sd_sec_write_data (sd_sec_write_data ),
  198. .sd_sec_write_data_req (sd_sec_write_data_req ),
  199. .sd_sec_write_end (sd_sec_write_end )
  200. );
  201. endmodule

6.5.2 ax_debounce

  1. //
  2. // //
  3. // //
  4. // Author: meisq //
  5. // msq@qq.com //
  6. // ALINX(shanghai) Technology Co.,Ltd //
  7. // heijin //
  8. // WEB: http://www.alinx.cn/ //
  9. // BBS: http://www.heijin.org/ //
  10. // //
  11. //
  12. // //
  13. // Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
  14. // All rights reserved //
  15. // //
  16. // This source file may be used and distributed without restriction provided //
  17. // that this copyright statement is not removed from the file and that any //
  18. // derivative work contains the original copyright notice and the associated //
  19. // disclaimer. //
  20. // //
  21. //
  22. //================================================================================
  23. // Revision History:
  24. // Date By Revision Change Description
  25. //--------------------------------------------------------------------------------
  26. // 2017/5/3 meisq 1.0 Original
  27. //*******************************************************************************/
  28. `timescale 1 ns / 100 ps
  29. module ax_debounce
  30. (
  31. input clk,
  32. input rst,
  33. input button_in,
  34. output reg button_posedge,
  35. output reg button_negedge,
  36. output reg button_out
  37. );
  38. ---------------- internal constants --------------
  39. parameter N = 32 ; // debounce timer bitwidth
  40. parameter FREQ = 50; //model clock :Mhz
  41. parameter MAX_TIME = 20; //ms
  42. localparam TIMER_MAX_VAL = MAX_TIME * 1000 * FREQ;
  43. ---------------- internal variables ---------------
  44. reg [N-1 : 0] q_reg; // timing regs
  45. reg [N-1 : 0] q_next;
  46. reg DFF1, DFF2; // input flip-flops
  47. wire q_add; // control flags
  48. wire q_reset;
  49. reg button_out_d0;
  50. ------------------------------------------------------
  51. contenious assignment for counter control
  52. assign q_reset = (DFF1 ^ DFF2); // xor input flip flops to look for level chage to reset counter
  53. assign q_add = ~(q_reg == TIMER_MAX_VAL); // add to counter when q_reg msb is equal to 0
  54. combo counter to manage q_next
  55. always @ ( q_reset, q_add, q_reg)
  56. begin
  57. case( {q_reset , q_add})
  58. 2'b00 :
  59. q_next <= q_reg;
  60. 2'b01 :
  61. q_next <= q_reg + 1;
  62. default :
  63. q_next <= { N {1'b0} };
  64. endcase
  65. end
  66. Flip flop inputs and q_reg update
  67. always @ ( posedge clk or posedge rst)
  68. begin
  69. if(rst == 1'b1)
  70. begin
  71. DFF1 <= 1'b0;
  72. DFF2 <= 1'b0;
  73. q_reg <= { N {1'b0} };
  74. end
  75. else
  76. begin
  77. DFF1 <= button_in;
  78. DFF2 <= DFF1;
  79. q_reg <= q_next;
  80. end
  81. end
  82. counter control
  83. always @ ( posedge clk or posedge rst)
  84. begin
  85. if(rst == 1'b1)
  86. button_out <= 1'b1;
  87. else if(q_reg == TIMER_MAX_VAL)
  88. button_out <= DFF2;
  89. else
  90. button_out <= button_out;
  91. end
  92. always @ ( posedge clk or posedge rst)
  93. begin
  94. if(rst == 1'b1)
  95. begin
  96. button_out_d0 <= 1'b1;
  97. button_posedge <= 1'b0;
  98. button_negedge <= 1'b0;
  99. end
  100. else
  101. begin
  102. button_out_d0 <= button_out;
  103. button_posedge <= ~button_out_d0 & button_out;
  104. button_negedge <= button_out_d0 & ~button_out;
  105. end
  106. end
  107. endmodule

6.5.3 seg_decoder

  1. //
  2. // //
  3. // //
  4. // Author: meisq //
  5. // msq@qq.com //
  6. // ALINX(shanghai) Technology Co.,Ltd //
  7. // heijin //
  8. // WEB: http://www.alinx.cn/ //
  9. // BBS: http://www.heijin.org/ //
  10. // //
  11. //
  12. // //
  13. // Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
  14. // All rights reserved //
  15. // //
  16. // This source file may be used and distributed without restriction provided //
  17. // that this copyright statement is not removed from the file and that any //
  18. // derivative work contains the original copyright notice and the associated //
  19. // disclaimer. //
  20. // //
  21. //
  22. //==========================================================================
  23. // Revision History:
  24. // Date By Revision Change Description
  25. //--------------------------------------------------------------------------
  26. // 2017/6/19 meisq 1.0 Original
  27. //*************************************************************************/
  28. module seg_decoder
  29. (
  30. input[3:0] bin_data, // bin data input
  31. output reg[6:0] seg_data // seven segments LED output
  32. );
  33. always@(*)
  34. begin
  35. case(bin_data)
  36. 4'd0:seg_data <= 7'b100_0000;
  37. 4'd1:seg_data <= 7'b111_1001;
  38. 4'd2:seg_data <= 7'b010_0100;
  39. 4'd3:seg_data <= 7'b011_0000;
  40. 4'd4:seg_data <= 7'b001_1001;
  41. 4'd5:seg_data <= 7'b001_0010;
  42. 4'd6:seg_data <= 7'b000_0010;
  43. 4'd7:seg_data <= 7'b111_1000;
  44. 4'd8:seg_data <= 7'b000_0000;
  45. 4'd9:seg_data <= 7'b001_0000;
  46. 4'ha:seg_data <= 7'b000_1000;
  47. 4'hb:seg_data <= 7'b000_0011;
  48. 4'hc:seg_data <= 7'b100_0110;
  49. 4'hd:seg_data <= 7'b010_0001;
  50. 4'he:seg_data <= 7'b000_0110;
  51. 4'hf:seg_data <= 7'b000_1110;
  52. default:seg_data <= 7'b111_1111;
  53. endcase
  54. end
  55. endmodule

6.5.4 seg_scan

  1. //
  2. // //
  3. // //
  4. // Author: meisq //
  5. // msq@qq.com //
  6. // ALINX(shanghai) Technology Co.,Ltd //
  7. // heijin //
  8. // WEB: http://www.alinx.cn/ //
  9. // BBS: http://www.heijin.org/ //
  10. // //
  11. //
  12. // //
  13. // Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
  14. // All rights reserved //
  15. // //
  16. // This source file may be used and distributed without restriction provided //
  17. // that this copyright statement is not removed from the file and that any //
  18. // derivative work contains the original copyright notice and the associated //
  19. // disclaimer. //
  20. // //
  21. //
  22. //==========================================================================
  23. // Revision History:
  24. // Date By Revision Change Description
  25. //--------------------------------------------------------------------------
  26. // 2017/6/19 meisq 1.0 Original
  27. //*************************************************************************/
  28. module seg_scan(
  29. input clk,
  30. input rst_n,
  31. output reg[5:0] seg_sel, //digital led chip select
  32. output reg[7:0] seg_data, //eight segment digital tube output,MSB is the decimal point
  33. input[7:0] seg_data_0,
  34. input[7:0] seg_data_1,
  35. input[7:0] seg_data_2,
  36. input[7:0] seg_data_3,
  37. input[7:0] seg_data_4,
  38. input[7:0] seg_data_5
  39. );
  40. parameter SCAN_FREQ = 200; //scan frequency
  41. parameter CLK_FREQ = 50000000; //clock frequency
  42. parameter SCAN_COUNT = CLK_FREQ /(SCAN_FREQ * 6) - 1;
  43. reg[31:0] scan_timer; //scan time counter
  44. reg[3:0] scan_sel; //Scan select counter
  45. always@(posedge clk or negedge rst_n)
  46. begin
  47. if(rst_n == 1'b0)
  48. begin
  49. scan_timer <= 32'd0;
  50. scan_sel <= 4'd0;
  51. end
  52. else if(scan_timer >= SCAN_COUNT)
  53. begin
  54. scan_timer <= 32'd0;
  55. if(scan_sel == 4'd5)
  56. scan_sel <= 4'd0;
  57. else
  58. scan_sel <= scan_sel + 4'd1;
  59. end
  60. else
  61. begin
  62. scan_timer <= scan_timer + 32'd1;
  63. end
  64. end
  65. always@(posedge clk or negedge rst_n)
  66. begin
  67. if(rst_n == 1'b0)
  68. begin
  69. seg_sel <= 6'b111111;
  70. seg_data <= 8'hff;
  71. end
  72. else
  73. begin
  74. case(scan_sel)
  75. //first digital led
  76. 4'd0:
  77. begin
  78. seg_sel <= 6'b11_1110;
  79. seg_data <= seg_data_0;
  80. end
  81. //second digital led
  82. 4'd1:
  83. begin
  84. seg_sel <= 6'b11_1101;
  85. seg_data <= seg_data_1;
  86. end
  87. //...
  88. 4'd2:
  89. begin
  90. seg_sel <= 6'b11_1011;
  91. seg_data <= seg_data_2;
  92. end
  93. 4'd3:
  94. begin
  95. seg_sel <= 6'b11_0111;
  96. seg_data <= seg_data_3;
  97. end
  98. 4'd4:
  99. begin
  100. seg_sel <= 6'b10_1111;
  101. seg_data <= seg_data_4;
  102. end
  103. 4'd5:
  104. begin
  105. seg_sel <= 6'b01_1111;
  106. seg_data <= seg_data_5;
  107. end
  108. default:
  109. begin
  110. seg_sel <= 6'b11_1111;
  111. seg_data <= 8'hff;
  112. end
  113. endcase
  114. end
  115. end
  116. endmodule

7 实验结果

下载实验程序后,可以看到数码管显示一个数字,这个数字是存储在 sd 卡中第一扇区的第一
个数据,数据是随机的,这个时候按键 KEY1 按下,数字加一,并写入了 sd 卡,再次下载程序,
可以看到直接显示更新后的数据。

8 参考资料

【1】百度百科:EEPROM

【2】百度百科:NOR FLASH

【3】百度百科:NAND FLASH

【4】黑金社区

【5】基于FPGA的SD卡的数据读写实现(SD NAND FLASH)


需要工程文件(Quartus工程文件)的小伙伴也可以在公众号“Alex的书桌与实验室”回复“1SD”获取下载链接~

这就是本期的全部内容啦,如果你喜欢我的文章,不要忘了点赞+收藏+关注,分享给身边的朋友哇~

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

闽ICP备14008679号