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

  在此介绍的是使用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卡名称类似,但是有较大的区别:

SD NAND俗称贴片式TF卡与TF卡的区别

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

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

SD NAND与常见的TF卡的对比

  3 样品申请

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

CS创世SD NAND是从深圳雷龙发展申请

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

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

创世SD NAND免费样品

  4 电路结构与接口协议

  4.1 SD NAND

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

CSNP4GCR01-AMW

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

SD NAND封装图

SD NAND连接的电路原理参考图

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

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

SD NAND的两种使用模式,分别为SD MODE 以及 SPI MODE

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

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

  (注:SPI协议详解传送门)

SPI协议详解传送门

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

 

介绍SPI MODE下各个引脚

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

  4.2 SD NAND测试板

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

SD NAND测试板 转接板

  有了它就可以轻松实现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进行通信

  借由硬件电路的连接,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卡协议

  SD 卡对每个命令会返回一个响应,每个命令有一定的响应格式。响应的格式跟给它的命令号

  有关。在 SPI 模式中,有三种响应格式: R1, R2, R3。

在 SPI 模式中响应格式R1

在 SPI 模式中响应格式R2

在 SPI 模式中响应格式R3

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

进行SD NAND的SPI模式读写操作时

  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模块,用来实现不同子模块之间的连接。

//

//                                                                              //

//                                                                              //

//  Author: meisq                                                               //

//          msq@qq.com                                                          //

//          ALINX(shanghai) Technology Co.,Ltd                                  //

//          heijin                                                              //

//     WEB: http://www.alinx.cn/                                                //

//     BBS: http://www.heijin.org/                                              //

//                                                                              //

//

//                                                                              //

// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd                        //

//                    All rights reserved                                       //

//                                                                              //

// This source file may be used and distributed without restriction provided    //

// that this copyright statement is not removed from the file and that any      //

// derivative work contains the original copyright notice and the associated    //

// disclaimer.                                                                  //

//                                                                              //

//

//==========================================================================

//  Revision History:

//  Date          By            Revision    Change Description

//--------------------------------------------------------------------------

//  2017/6/21    meisq         1.0         Original

//*************************************************************************/

module sd_card_top

#(

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 )

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 )

)

(

input            clk,

input            rst,

output           SD_nCS,                    //SD card chip select (SPI mode)

output           SD_DCLK,                   //SD card clock

output           SD_MOSI,                   //SD card controller data output

input            SD_MISO,                   //SD card controller data input

output           sd_init_done,              //SD card initialization is complete

input            sd_sec_read,               //SD card sector read

input[31:0]      sd_sec_read_addr,          //SD card sector read address

output[7:0]      sd_sec_read_data,          //SD card sector read data

output           sd_sec_read_data_valid,    //SD card sector read data valid

output           sd_sec_read_end,           //SD card sector read end

input            sd_sec_write,              //SD card sector write

input[31:0]      sd_sec_write_addr,         //SD card sector write address

input[7:0]       sd_sec_write_data,         //SD card sector write data

output           sd_sec_write_data_req,     //SD card sector write data next clock is valid

output           sd_sec_write_end           //SD card sector write end

);

wire[15:0]           spi_clk_div;               //SPI module clock division parameter

wire                 cmd_req;                   //SD card command request

wire                 cmd_req_ack;               //SD card command request response

wire                 cmd_req_error;             //SD card command request error

wire[47:0]           cmd;                       //SD card command

wire[7:0]            cmd_r1;                    //SD card expect response

wire[15:0]           cmd_data_len;              //SD card command read data length

wire                 block_read_req;            //SD card sector data read request

wire                 block_read_valid;          //SD card sector data read data valid

wire[7:0]            block_read_data;           //SD card sector data read data

wire                 block_read_req_ack;        //SD card sector data read response

wire                 block_write_req;           //SD card sector data write request

wire[7:0]            block_write_data;          //SD card sector data write data next clock is valid

wire                 block_write_data_rd;       //SD card sector data write data

wire                 block_write_req_ack;       //SD card sector data write response

wire                 nCS_ctrl;                  //SPI module chip select control

wire                 spi_wr_req;                //SPI module data sending request

wire                 spi_wr_ack;                //SPI module data request response

wire[7:0]            spi_data_in;               //SPI module send data

wire[7:0]            spi_data_out;              //SPI module data returned

wire[15:0]           clk_div;

sd_card_sec_read_write

#(

.SPI_LOW_SPEED_DIV(SPI_LOW_SPEED_DIV),

.SPI_HIGH_SPEED_DIV(SPI_HIGH_SPEED_DIV)

)

sd_card_sec_read_write_m0(

.clk                            (clk                    ),

.rst                            (rst                    ),

.sd_init_done                   (sd_init_done           ),

.sd_sec_read                    (sd_sec_read            ),

.sd_sec_read_addr               (sd_sec_read_addr       ),

.sd_sec_read_data               (sd_sec_read_data       ),

.sd_sec_read_data_valid         (sd_sec_read_data_valid ),

.sd_sec_read_end                (sd_sec_read_end        ),

.sd_sec_write                   (sd_sec_write           ),

.sd_sec_write_addr              (sd_sec_write_addr      ),

.sd_sec_write_data              (sd_sec_write_data      ),

.sd_sec_write_data_req          (sd_sec_write_data_req  ),

.sd_sec_write_end               (sd_sec_write_end       ),

.spi_clk_div                    (spi_clk_div            ),

.cmd_req                        (cmd_req                ),

.cmd_req_ack                    (cmd_req_ack            ),

.cmd_req_error                  (cmd_req_error          ),

.cmd                            (cmd                    ),

.cmd_r1                         (cmd_r1                 ),

.cmd_data_len                   (cmd_data_len           ),

.block_read_req                 (block_read_req         ),

.block_read_valid               (block_read_valid       ),

.block_read_data                (block_read_data        ),

.block_read_req_ack             (block_read_req_ack     ),

.block_write_req                (block_write_req        ),

.block_write_data               (block_write_data       ),

.block_write_data_rd            (block_write_data_rd    ),

.block_write_req_ack            (block_write_req_ack    )

);

sd_card_cmd sd_card_cmd_m0(

.sys_clk                        (clk                    ),

.rst                            (rst                    ),

.spi_clk_div                    (spi_clk_div            ),

.cmd_req                        (cmd_req                ),

.cmd_req_ack                    (cmd_req_ack            ),

.cmd_req_error                  (cmd_req_error          ),

.cmd                            (cmd                    ),

.cmd_r1                         (cmd_r1                 ),

.cmd_data_len                   (cmd_data_len           ),

.block_read_req                 (block_read_req         ),

.block_read_req_ack             (block_read_req_ack     ),

.block_read_data                (block_read_data        ),

.block_read_valid               (block_read_valid       ),

.block_write_req                (block_write_req        ),

.block_write_data               (block_write_data       ),

.block_write_data_rd            (block_write_data_rd    ),

.block_write_req_ack            (block_write_req_ack    ),

.nCS_ctrl                       (nCS_ctrl               ),

.clk_div                        (clk_div                ),

.spi_wr_req                     (spi_wr_req             ),

.spi_wr_ack                     (spi_wr_ack             ),

.spi_data_in                    (spi_data_in            ),

.spi_data_out                   (spi_data_out           )

);

spi_master spi_master_m0(

.sys_clk                        (clk                    ),

.rst                            (rst                    ),

.nCS                            (SD_nCS                 ),

.DCLK                           (SD_DCLK                ),

.MOSI                           (SD_MOSI                ),

.MISO                           (SD_MISO                ),

.clk_div                        (clk_div                ),

.CPOL                           (1'b1                   ),

.CPHA                           (1'b1                   ),

.nCS_ctrl                       (nCS_ctrl               ),

.wr_req                         (spi_wr_req             ),

.wr_ack                         (spi_wr_ack             ),

.data_in                        (spi_data_in            ),

.data_out                       (spi_data_out           )

);

endmodule

  6.2 sd_card_cmd

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

  块的读写,状态机如下:

sd card cmd

  代码如下:

//

//                                                                              //

//                                                                              //

//  Author: meisq                                                               //

//          msq@qq.com                                                          //

//          ALINX(shanghai) Technology Co.,Ltd                                  //

//          heijin                                                              //

//     WEB: http://www.alinx.cn/                                                //

//     BBS: http://www.heijin.org/                                              //

//                                                                              //

//

//                                                                              //

// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd                        //

//                    All rights reserved                                       //

//                                                                              //

// This source file may be used and distributed without restriction provided    //

// that this copyright statement is not removed from the file and that any      //

// derivative work contains the original copyright notice and the associated    //

// disclaimer.                                                                  //

//                                                                              //

//

//==========================================================================

//  Revision History:

//  Date          By            Revision    Change Description

//--------------------------------------------------------------------------

//  2017/6/21     meisq         1.0         Original

//*************************************************************************/

module sd_card_cmd(

input                       sys_clk,

input                       rst,

input[15:0]                 spi_clk_div,                  //SPI module clock division parameter

input                       cmd_req,                      //SD card command request

output                      cmd_req_ack,                  //SD card command request response

output reg                  cmd_req_error,                //SD card command request error

input[47:0]                 cmd,                          //SD card command

input[7:0]                  cmd_r1,                       //SD card expect response

input[15:0]                 cmd_data_len,                 //SD card command read data length

input                       block_read_req,               //SD card sector data read request

output reg                  block_read_valid,             //SD card sector data read data valid

output reg[7:0]             block_read_data,              //SD card sector data read data

output                      block_read_req_ack,           //SD card sector data read response

input                       block_write_req,              //SD card sector data write request

input[7:0]                  block_write_data,             //SD card sector data write data next clock is valid

output                      block_write_data_rd,          //SD card sector data write data

output                      block_write_req_ack,          //SD card sector data write response

output                      nCS_ctrl,                     //SPI module chip select control

output reg[15:0]            clk_div,

output reg                  spi_wr_req,                   //SPI module data sending request

input                       spi_wr_ack,                   //SPI module data request response

output[7:0]                 spi_data_in,                  //SPI module send data

input[7:0]                  spi_data_out                  //SPI module data returned

);

parameter S_IDLE         = 0;

parameter S_WAIT         = 1;

parameter S_INIT         = 2;

parameter S_CMD_PRE      = 3;

parameter S_CMD          = 4;

parameter S_CMD_DATA     = 5;

parameter S_READ_WAIT    = 6;

parameter S_READ         = 7;

parameter S_READ_ACK     = 8;

parameter S_WRITE_TOKEN  = 9;

parameter S_WRITE_DATA_0 = 10;

parameter S_WRITE_DATA_1 = 11;

parameter S_WRITE_CRC    = 12;

parameter S_WRITE_ACK    = 13;

parameter S_ERR          = 14;

parameter S_END          = 15;

reg[3:0]                      state;

reg                           CS_reg;

reg[15:0]                     byte_cnt;

reg[7:0]                      send_data;

wire[7:0]                     data_recv;

reg[9:0]                      wr_data_cnt;

assign cmd_req_ack = (state == S_END);

assign block_read_req_ack = (state == S_READ_ACK);

assign block_write_req_ack= (state == S_WRITE_ACK);

assign block_write_data_rd = (state == S_WRITE_DATA_0);

assign spi_data_in = send_data;

assign data_recv = spi_data_out;

assign nCS_ctrl = CS_reg;

always@(posedge sys_clk or posedge rst)

begin

if(rst == 1'b1)

begin

CS_reg <= 1'b1;

spi_wr_req <= 1'b0;

byte_cnt <= 16'd0;

clk_div <= 16'd0;

send_data <= 8'hff;

state <= S_IDLE;

cmd_req_error <= 1'b0;

wr_data_cnt <= 10'd0;

end

else

case(state)

S_IDLE:

begin

state <= S_INIT;

clk_div <= spi_clk_div;

CS_reg <= 1'b1;

end

S_INIT:

begin

//send 11 bytes on power(at least 74 SPI clocks)

if(spi_wr_ack == 1'b1)

begin

if(byte_cnt >= 16'd10)

begin

byte_cnt <= 16'd0;

spi_wr_req <= 1'b0;

state <= S_WAIT;

end

begin

byte_cnt <= byte_cnt + 16'd1;

end

end

else

begin

spi_wr_req <= 1'b1;

send_data <= 8'hff;

end

end

S_WAIT:

begin

cmd_req_error <= 1'b0;

wr_data_cnt <= 10'd0;

//wait for  instruction

if(cmd_req == 1'b1)

state <= S_CMD_PRE;

else if(block_read_req == 1'b1)

state <= S_READ_WAIT;

else if(block_write_req == 1'b1)

state <= S_WRITE_TOKEN;

clk_div <= spi_clk_div;

end

S_CMD_PRE:

begin

//before sending a command, send an byte 'ff',provide some clocks

if(spi_wr_ack == 1'b1)

begin

state <= S_CMD;

spi_wr_req <= 1'b0;

byte_cnt <= 16'd0;

end

else

begin

spi_wr_req <= 1'b1;

CS_reg <= 1'b1;

send_data <= 8'hff;

end

end

S_CMD:

begin

if(spi_wr_ack == 1'b1)

begin

if((byte_cnt == 16'hffff) || (data_recv != cmd_r1 && data_recv[7] == 1'b0))

begin

state <= S_ERR;

spi_wr_req <= 1'b0;

end

else if(data_recv == cmd_r1)

begin

spi_wr_req <= 1'b0;

if(cmd_data_len != 16'd0)

begin

state <= S_CMD_DATA;

byte_cnt <= 16'd0;

end

else

state <= S_END;

end

else

byte_cnt <=  byte_cnt + 16'd1;

end

else

begin

spi_wr_req <= 1'b1;

CS_reg <= 1'b0;

if(byte_cnt == 16'd0)

send_data <= (cmd[47:40] | 8'h40);

else if(byte_cnt == 16'd1)

send_data <= cmd[39:32];

else if(byte_cnt == 16'd2)

send_data <= cmd[31:24];

else if(byte_cnt == 16'd3)

send_data <= cmd[23:16];

else if(byte_cnt == 16'd4)

send_data <= cmd[15:8];

else if(byte_cnt == 16'd5)

send_data <= cmd[7:0];

else

send_data <= 8'hff;

end

end

S_CMD_DATA:

begin

if(spi_wr_ack == 1'b1)

begin

if(byte_cnt == cmd_data_len - 16'd1)

begin

state <= S_END;

spi_wr_req <= 1'b0;

byte_cnt <= 16'd0;

end

else

begin

byte_cnt <= byte_cnt + 16'd1;

end

end

else

begin

spi_wr_req <= 1'b1;

send_data <= 8'hff;

end

end

S_READ_WAIT:

begin

if(spi_wr_ack == 1'b1 && data_recv == 8'hfe)

begin

spi_wr_req <= 1'b0;

state <= S_READ;

byte_cnt <= 16'd0;

end

else

begin

spi_wr_req <= 1'b1;

send_data <= 8'hff;

end

end

S_READ:

begin

if(spi_wr_ack == 1'b1)

begin

if(byte_cnt == 16'd513)

begin

state <= S_READ_ACK;

spi_wr_req <= 1'b0;

byte_cnt <= 16'd0;

end

else

begin

byte_cnt <= byte_cnt + 16'd1;

end

end

else

begin

spi_wr_req <= 1'b1;

send_data <= 8'hff;

end

end

S_WRITE_TOKEN:

if(spi_wr_ack == 1'b1)

begin

state <= S_WRITE_DATA_0;

spi_wr_req <= 1'b0;

end

else

begin

spi_wr_req <= 1'b1;

send_data <= 8'hfe;

end

S_WRITE_DATA_0:

begin

state <= S_WRITE_DATA_1;

wr_data_cnt <= wr_data_cnt + 10'd1;

end

S_WRITE_DATA_1:

begin

if(spi_wr_ack == 1'b1 && wr_data_cnt == 10'd512)

begin

state <= S_WRITE_CRC;

spi_wr_req <= 1'b0;

end

else if(spi_wr_ack == 1'b1)

begin

state <= S_WRITE_DATA_0;

spi_wr_req <= 1'b0;

end

else

begin

spi_wr_req <= 1'b1;

send_data <= block_write_data;

end

end

S_WRITE_CRC:

begin

if(spi_wr_ack == 1'b1)

begin

if(byte_cnt == 16'd2)

begin

state <= S_WRITE_ACK;

spi_wr_req <= 1'b0;

byte_cnt <= 16'd0;

end

else

begin

byte_cnt <= byte_cnt + 16'd1;

end

end

else

begin

spi_wr_req <= 1'b1;

send_data <= 8'hff;

end

end

S_ERR:

begin

state <= S_END;

cmd_req_error <= 1'b1;

end

S_READ_ACK,S_WRITE_ACK,S_END:

begin

state <= S_WAIT;

end

default:

state <= S_IDLE;

endcase

end

always@(posedge sys_clk or posedge rst)

begin

if(rst == 1'b1)

block_read_valid <= 1'b0;

else if(state == S_READ && byte_cnt < 16'd512)

block_read_valid <= spi_wr_ack;

else

block_read_valid <= 1'b0;

end

always@(posedge sys_clk or posedge rst)

begin

if(rst == 1'b1)

block_read_data <= 8'd0;

else if(state == S_READ && spi_wr_ack == 1'b1)

block_read_data <= data_recv;

end

endmodule

  6.3 sd_card_sec_read_write

  sd_card_sec_read_write 模块继续完成 SD 卡初始化,然后等待扇区读写指令,并完成扇区的

  读写操作。 下图为模块的状态机转换图,首先发送 CMD0 命令,然后发送 CMD8 命令,再发送

  CMD55,接着发送 ACMD41,如果应答正常, sd 卡初始化完成,等待扇区的读写。

sd_card_sec_read_write

  代码如下:

//

//                                                                              //

//                                                                              //

//  Author: meisq                                                               //

//          msq@qq.com                                                          //

//          ALINX(shanghai) Technology Co.,Ltd                                  //

//          heijin                                                              //

//     WEB: http://www.alinx.cn/                                                //

//     BBS: http://www.heijin.org/                                              //

//                                                                              //

//

//                                                                              //

// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd                        //

//                    All rights reserved                                       //

//                                                                              //

// This source file may be used and distributed without restriction provided    //

// that this copyright statement is not removed from the file and that any      //

// derivative work contains the original copyright notice and the associated    //

// disclaimer.                                                                  //

//                                                                              //

//

//===============================================================================

//  Revision History:

//  Date          By            Revision    Change Description

//-------------------------------------------------------------------------------

//  2017/6/21     meisq         1.0         Original

//*******************************************************************************/

module sd_card_sec_read_write

#(

parameter  SPI_LOW_SPEED_DIV = 248,         // spi clk speed = clk speed /((SPI_LOW_SPEED_DIV + 2) * 2 )

parameter  SPI_HIGH_SPEED_DIV = 0           // spi clk speed = clk speed /((SPI_HIGH_SPEED_DIV + 2) * 2 )

)

(

input            clk,

input            rst,

output reg       sd_init_done,

input            sd_sec_read,

input[31:0]      sd_sec_read_addr,

output[7:0]      sd_sec_read_data,

output           sd_sec_read_data_valid,

output           sd_sec_read_end,

input            sd_sec_write,

input[31:0]      sd_sec_write_addr,

input[7:0]       sd_sec_write_data,

output           sd_sec_write_data_req,

output           sd_sec_write_end,

output reg[15:0] spi_clk_div,

output reg       cmd_req,

input            cmd_req_ack,

input            cmd_req_error,

output reg[47:0] cmd,

output reg[7:0]  cmd_r1,

output reg[15:0] cmd_data_len,

output reg       block_read_req,

input            block_read_valid,

input[7:0]       block_read_data,

input            block_read_req_ack,

output reg       block_write_req,

output[7:0]      block_write_data,

input            block_write_data_rd,

input            block_write_req_ack

);

reg[7:0] read_data;

reg[31:0] timer;

localparam S_IDLE               = 0;

localparam S_CMD0               = 1;

localparam S_CMD8               = 2;

localparam S_CMD55              = 3;

localparam S_CMD41              = 4;

localparam S_CMD17              = 5;

localparam S_READ               = 6;

localparam S_CMD24              = 7;

localparam S_WRITE              = 8;

localparam S_ERR                = 14;

localparam S_WRITE_END          = 15;

localparam S_READ_END           = 16;

localparam S_WAIT_READ_WRITE    = 17;

localparam S_CMD16              = 18;

reg[4:0]                       state;

reg[31:0]                      sec_addr;

assign sd_sec_read_data_valid = (state == S_READ) && block_read_valid;

assign sd_sec_read_data = block_read_data;

assign sd_sec_read_end = (state == S_READ_END);

assign sd_sec_write_data_req = (state == S_WRITE) && block_write_data_rd;

assign block_write_data = sd_sec_write_data;

assign sd_sec_write_end = (state == S_WRITE_END);

always@(posedge clk or posedge rst)

begin

if(rst == 1'b1)

begin

state <= S_IDLE;

cmd_req <= 1'b0;

cmd_data_len <= 16'd0;

cmd_r1 <= 8'd0;

cmd <= 48'd0;

spi_clk_div <= SPI_LOW_SPEED_DIV[15:0];

block_write_req <= 1'b0;

block_read_req <= 1'b0;

sec_addr <= 32'd0;

sd_init_done <= 1'b0;

end

else

case(state)

S_IDLE:

begin

state <= S_CMD0;

sd_init_done <= 1'b0;

spi_clk_div <= SPI_LOW_SPEED_DIV[15:0];

end

S_CMD0:

begin

if(cmd_req_ack & ~cmd_req_error)

begin

state <= S_CMD8;

cmd_req <= 1'b0;

end

else

begin

cmd_req <= 1'b1;

cmd_data_len <= 16'd0;

cmd_r1 <= 8'h01;

cmd <= {8'd0,8'h00,8'h00,8'h00,8'h00,8'h95};

end

end

S_CMD8:

begin

if(cmd_req_ack & ~cmd_req_error)

begin

state <= S_CMD55;

cmd_req <= 1'b0;

end

else

begin

cmd_req <= 1'b1;

cmd_data_len <= 16'd4;

cmd_r1 <= 8'h01;

cmd <= {8'd8,8'h00,8'h00,8'h01,8'haa,8'h87};

end

end

S_CMD55:

begin

if(cmd_req_ack & ~cmd_req_error)

begin

state <= S_CMD41;

cmd_req <= 1'b0;

end

else

begin

cmd_req <= 1'b1;

cmd_data_len <= 16'd0;

cmd_r1 <= 8'h01;

cmd <= {8'd55,8'h00,8'h00,8'h00,8'h00,8'hff};

end

end

S_CMD41:

begin

if(cmd_req_ack & ~cmd_req_error)

begin

state <= S_CMD16;

cmd_req <= 1'b0;

sd_init_done <= 1'b1;

spi_clk_div <= SPI_HIGH_SPEED_DIV[15:0];

end

else if(cmd_req_ack)

begin

state <= S_CMD55;

end

else

begin

cmd_req <= 1'b1;

cmd_data_len <= 16'd0;

cmd_r1 <= 8'h00;

cmd <= {8'd41,8'h40,8'h00,8'h00,8'h00,8'hff};

end

end

S_CMD16:

begin

if(cmd_req_ack & ~cmd_req_error)

begin

state <= S_WAIT_READ_WRITE;

cmd_req <= 1'b0;

sd_init_done <= 1'b1;

spi_clk_div <= SPI_HIGH_SPEED_DIV[15:0];

end

else if(cmd_req_ack)

begin

state <= S_CMD55;

end

else

begin

cmd_req <= 1'b1;

cmd_data_len <= 16'd0;

cmd_r1 <= 8'h00;

cmd <= {8'd16,32'd512,8'hff};

end

end

S_WAIT_READ_WRITE:

begin

if(sd_sec_write ==  1'b1)

begin

state <= S_CMD24;

sec_addr <= sd_sec_write_addr;

end

else if(sd_sec_read == 1'b1)

begin

state <= S_CMD17;

sec_addr <= sd_sec_read_addr;

end

spi_clk_div <= 16'd0;

end

S_CMD24:

begin

if(cmd_req_ack & ~cmd_req_error)

begin

state <= S_WRITE;

cmd_req <= 1'b0;

end

else

begin

cmd_req <= 1'b1;

cmd_data_len <= 16'd0;

cmd_r1 <= 8'h00;

cmd <= {8'd24,sec_addr,8'hff};

end

end

S_WRITE:

begin

if(block_write_req_ack == 1'b1)

begin

block_write_req <= 1'b0;

state <= S_WRITE_END;

end

else

block_write_req <= 1'b1;

end

S_CMD17:

begin

if(cmd_req_ack & ~cmd_req_error)

begin

state <= S_READ;

cmd_req <= 1'b0;

end

else

begin

cmd_req <= 1'b1;

cmd_data_len <= 16'd0;

cmd_r1 <= 8'h00;

cmd <= {8'd17,sec_addr,8'hff};

end

end

S_READ:

begin

if(block_read_req_ack)

begin

state <= S_READ_END;

block_read_req <= 1'b0;

end

else

begin

block_read_req <= 1'b1;

end

end

S_WRITE_END:

begin

state <= S_WAIT_READ_WRITE;

end

S_READ_END:

begin

state <= S_WAIT_READ_WRITE;

end

default:

state <= S_IDLE;

endcase

end

endmodule

  6.4 spi_master

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

  spi master 状态机设计, 主要完成一个字节 spi 数据的读写,由于是全双工的,写一个字节的

  同时也读一个字节。 首先空闲状态“IDLE”接收到写请求后进入“DCLK_IDLE”状态,这个状态为

  spi 时钟沿变化保持一定的时间,用来控制 spi 时钟的周期,然后进入 spi 时钟沿的变化状态,一

  个字节上升沿和下降沿一共 16 个数据沿。 在最后一个数据沿进入“LAST_HALF_CYCLE”状态,为

  让最后一个沿也保持一定的时间,再进入应答状态,完成一次写请求。spi_master 模块中模拟了一个 spi 时钟,在状态机进入到‘DCLK_EDGE’时进行翻转。状态机图示如下:

spi_master

  代码如下:

//

//                                                                              //

//                                                                              //

//  Author: meisq                                                               //

//          msq@qq.com                                                          //

//          ALINX(shanghai) Technology Co.,Ltd                                  //

//          heijin                                                              //

//     WEB: http://www.alinx.cn/                                                //

//     BBS: http://www.heijin.org/                                              //

//                                                                              //

//

//                                                                              //

// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd                        //

//                    All rights reserved                                       //

//                                                                              //

// This source file may be used and distributed without restriction provided    //

// that this copyright statement is not removed from the file and that any      //

// derivative work contains the original copyright notice and the associated    //

// disclaimer.                                                                  //

//                                                                              //

//

//==========================================================================

//  Revision History:

//  Date          By            Revision    Change Description

//--------------------------------------------------------------------------

//  2017/6/19     meisq         1.0         Original

//*************************************************************************/

module spi_master

(

input                       sys_clk,

input                       rst,

output                      nCS,       //chip select (SPI mode)

output                      DCLK,      //spi clock

output                      MOSI,      //spi data output

input                       MISO,      //spi input

input                       CPOL,

input                       CPHA,

input                       nCS_ctrl,

input[15:0]                 clk_div,

input                       wr_req,

output                      wr_ack,

input[7:0]                  data_in,

output[7:0]                 data_out

);

localparam                   IDLE            = 0;

localparam                   DCLK_EDGE       = 1;

localparam                   DCLK_IDLE       = 2;

localparam                   ACK             = 3;

localparam                   LAST_HALF_CYCLE = 4;

localparam                   ACK_WAIT        = 5;

reg                          DCLK_reg;

reg[7:0]                     MOSI_shift;

reg[7:0]                     MISO_shift;

reg[2:0]                     state;

reg[2:0]                     next_state;

reg [15:0]                   clk_cnt;

reg[4:0]                     clk_edge_cnt;

assign MOSI = MOSI_shift[7];

assign DCLK = DCLK_reg;

assign data_out = MISO_shift;

assign wr_ack = (state == ACK);

assign nCS = nCS_ctrl;

always@(posedge sys_clk or posedge rst)

begin

if(rst)

state <= IDLE;

else

state <= next_state;

end

always@(*)

begin

case(state)

IDLE:

if(wr_req == 1'b1)

next_state <= DCLK_IDLE;

else

next_state <= IDLE;

DCLK_IDLE:

//half a SPI clock cycle produces a clock edge

if(clk_cnt == clk_div)

next_state <= DCLK_EDGE;

else

next_state <= DCLK_IDLE;

DCLK_EDGE:

//a SPI byte with a total of 16 clock edges

if(clk_edge_cnt == 5'd15)

next_state <= LAST_HALF_CYCLE;

else

next_state <= DCLK_IDLE;

//this is the last data edge

LAST_HALF_CYCLE:

if(clk_cnt == clk_div)

next_state <= ACK;

else

next_state <= LAST_HALF_CYCLE;

//send one byte complete

ACK:

next_state <= ACK_WAIT;

//wait for one clock cycle, to ensure that the cancel request signal

ACK_WAIT:

next_state <= IDLE;

default:

next_state <= IDLE;

endcase

end

always@(posedge sys_clk or posedge rst)

begin

if(rst)

DCLK_reg <= 1'b0;

else if(state == IDLE)

DCLK_reg <= CPOL;

else if(state == DCLK_EDGE)

DCLK_reg <= ~DCLK_reg;//SPI clock edge

end

//SPI clock wait counter

always@(posedge sys_clk or posedge rst)

begin

if(rst)

clk_cnt <= 16'd0;

else if(state == DCLK_IDLE || state == LAST_HALF_CYCLE)

clk_cnt <= clk_cnt + 16'd1;

else

clk_cnt <= 16'd0;

end

//SPI clock edge counter

always@(posedge sys_clk or posedge rst)

begin

if(rst)

clk_edge_cnt <= 5'd0;

else if(state == DCLK_EDGE)

clk_edge_cnt <= clk_edge_cnt + 5'd1;

else if(state == IDLE)

clk_edge_cnt <= 5'd0;

end

//SPI data output

always@(posedge sys_clk or posedge rst)

begin

if(rst)

MOSI_shift <= 8'd0;

else if(state == IDLE && wr_req)

MOSI_shift <= data_in;

else if(state == DCLK_EDGE)

if(CPHA == 1'b0 && clk_edge_cnt[0] == 1'b1)

MOSI_shift <= {MOSI_shift[6:0],MOSI_shift[7]};

else if(CPHA == 1'b1 && (clk_edge_cnt != 5'd0 && clk_edge_cnt[0] == 1'b0))

MOSI_shift <= {MOSI_shift[6:0],MOSI_shift[7]};

end

//SPI data input

always@(posedge sys_clk or posedge rst)

begin

if(rst)

MISO_shift <= 8'd0;

else if(state == IDLE && wr_req)

MISO_shift <= 8'h00;

else if(state == DCLK_EDGE)

if(CPHA == 1'b0 && clk_edge_cnt[0] == 1'b0)

MISO_shift <= {MISO_shift[6:0],MISO};

else if(CPHA == 1'b1 && (clk_edge_cnt[0] == 1'b1))

MISO_shift <= {MISO_shift[6:0],MISO};

end

endmodule

  6.5 其余代码

  6.5.1 sd_card_test

//

//                                                                              //

//                                                                              //

//  Author: meisq                                                               //

//          msq@qq.com                                                          //

//          ALINX(shanghai) Technology Co.,Ltd                                  //

//          heijin                                                              //

//     WEB: http://www.alinx.cn/                                                //

//     BBS: http://www.heijin.org/                                              //

//                                                                              //

//

//                                                                              //

// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd                        //

//                    All rights reserved                                       //

//                                                                              //

// This source file may be used and distributed without restriction provided    //

// that this copyright statement is not removed from the file and that any      //

// derivative work contains the original copyright notice and the associated    //

// disclaimer.                                                                  //

//                                                                              //

//

//================================================================================

//  Revision History:

//  Date          By            Revision    Change Description

//--------------------------------------------------------------------------------

//  2017/6/19     meisq         1.0         Original

//*******************************************************************************/

module sd_card_test(

input            clk,

input            rst_n,

input            key1,

output           SD_nCS,

output           SD_DCLK,

output           SD_MOSI,

input            SD_MISO,

output [5:0]     seg_sel,

output [7:0]     seg_data

);

parameter S_IDLE         = 0;

parameter S_READ         = 1;

parameter S_WRITE        = 2;

parameter S_END          = 3;

reg[3:0] state;

wire             sd_init_done;

reg              sd_sec_read;

wire[31:0]       sd_sec_read_addr;

wire[7:0]        sd_sec_read_data;

wire             sd_sec_read_data_valid;

wire             sd_sec_read_end;

reg              sd_sec_write;

wire[31:0]       sd_sec_write_addr;

reg [7:0]        sd_sec_write_data;

wire             sd_sec_write_data_req;

wire             sd_sec_write_end;

reg[9:0]         wr_cnt;

reg[9:0]         rd_cnt;

wire             button_negedge;

reg[7:0]         read_data;

ax_debounce ax_debounce_m0

(

.clk             (clk),

.rst             (~rst_n),

.button_in       (key1),

.button_posedge  (),

.button_negedge  (button_negedge),

.button_out      ()

);

wire[6:0] seg_data_0;

seg_decoder seg_decoder_m0(

    .bin_data  (read_data[3:0]),

    .seg_data  (seg_data_0)

);

wire[6:0] seg_data_1;

seg_decoder seg_decoder_m1(

    .bin_data  (read_data[7:4]),

    .seg_data  (seg_data_1)

);

seg_scan seg_scan_m0(

    .clk        (clk),

    .rst_n      (rst_n),

    .seg_sel    (seg_sel),

    .seg_data   (seg_data),

    .seg_data_0 ({1'b1,7'b1111_111}),

    .seg_data_1 ({1'b1,7'b1111_111}),

    .seg_data_2 ({1'b1,7'b1111_111}),

    .seg_data_3 ({1'b1,7'b1111_111}),

    .seg_data_4 ({1'b1,seg_data_1}),

    .seg_data_5 ({sd_init_done,seg_data_0})

);

always@(posedge clk or negedge rst_n)

begin

if(rst_n == 1'b0)

wr_cnt <= 10'd0;

else if(state == S_WRITE)

begin

if(sd_sec_write_data_req == 1'b1)

wr_cnt <= wr_cnt + 10'd1;

end

else

wr_cnt <= 10'd0;

end

always@(posedge clk or negedge rst_n)

begin

if(rst_n == 1'b0)

rd_cnt <= 10'd0;

else if(state == S_READ)

begin

if(sd_sec_read_data_valid == 1'b1)

rd_cnt <= rd_cnt + 10'd1;

end

else

rd_cnt <= 10'd0;

end

always@(posedge clk or negedge rst_n)

begin

if(rst_n == 1'b0)

read_data <= 8'd0;

else if(state == S_READ)

begin

if(sd_sec_read_data_valid == 1'b1 && rd_cnt == 10'd0)

read_data <= sd_sec_read_data;

end

else if(state == S_END && button_negedge == 1'b1)

read_data <= read_data + 8'd1;

end

always@(posedge clk or negedge rst_n)

begin

if(rst_n == 1'b0)

sd_sec_write_data <= 8'd0;

else if(sd_sec_write_data_req)

sd_sec_write_data <= read_data + wr_cnt[7:0];

end

always@(posedge clk or negedge rst_n)

begin

if(rst_n == 1'b0)

begin

state <= S_IDLE;

sd_sec_read <= 1'b0;

sd_sec_write <= 1'b0;

end

else if(sd_init_done == 1'b0)

begin

state <= S_IDLE;

end

else

case(state)

S_IDLE:

begin

state <= S_READ;

end

S_WRITE:

begin

if(sd_sec_write_end == 1'b1)

begin

sd_sec_write <= 1'b0;

state <= S_READ;

end

else

sd_sec_write <= 1'b1;

end

S_READ:

begin

if(sd_sec_read_end == 1'b1)

begin

state <= S_END;

sd_sec_read <= 1'b0;

end

else

begin

sd_sec_read <= 1'b1;

end                 

end         

S_END:

begin

if(button_negedge == 1'b1)

state <= S_WRITE;

end

default:

state <= S_IDLE;

endcase

end

sd_card_top  sd_card_top_m0(

.clk                       (clk                    ),

.rst                       (~rst_n                 ),

.SD_nCS                    (SD_nCS                 ),

.SD_DCLK                   (SD_DCLK                ),

.SD_MOSI                   (SD_MOSI                ),

.SD_MISO                   (SD_MISO                ),

.sd_init_done              (sd_init_done           ),

.sd_sec_read               (sd_sec_read            ),

.sd_sec_read_addr          (sd_sec_read_addr       ),

.sd_sec_read_data          (sd_sec_read_data       ),

.sd_sec_read_data_valid    (sd_sec_read_data_valid ),

.sd_sec_read_end           (sd_sec_read_end        ),

.sd_sec_write              (sd_sec_write           ),

.sd_sec_write_addr         (sd_sec_write_addr      ),

.sd_sec_write_data         (sd_sec_write_data      ),

.sd_sec_write_data_req     (sd_sec_write_data_req  ),

.sd_sec_write_end          (sd_sec_write_end       )

);

endmodule 

  6.5.2 ax_debounce

//

//                                                                              //

//                                                                              //

//  Author: meisq                                                               //

//          msq@qq.com                                                          //

//          ALINX(shanghai) Technology Co.,Ltd                                  //

//          heijin                                                              //

//     WEB: http://www.alinx.cn/                                                //

//     BBS: http://www.heijin.org/                                              //

//                                                                              //

//

//                                                                              //

// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd                        //

//                    All rights reserved                                       //

//                                                                              //

// This source file may be used and distributed without restriction provided    //

// that this copyright statement is not removed from the file and that any      //

// derivative work contains the original copyright notice and the associated    //

// disclaimer.                                                                  //

//                                                                              //

//

//================================================================================

//  Revision History:

//  Date          By            Revision    Change Description

//--------------------------------------------------------------------------------

//  2017/5/3     meisq          1.0         Original

//*******************************************************************************/

`timescale 1 ns / 100 ps

module  ax_debounce 

(

    input       clk, 

    input       rst, 

    input       button_in,

    output reg  button_posedge,

    output reg  button_negedge,

    output reg  button_out

);

 ---------------- internal constants --------------

parameter N = 32 ;           // debounce timer bitwidth

parameter FREQ = 50;         //model clock :Mhz

parameter MAX_TIME = 20;     //ms

localparam TIMER_MAX_VAL =   MAX_TIME * 1000 * FREQ;

---------------- internal variables ---------------

reg  [N-1 : 0]  q_reg;      // timing regs

reg  [N-1 : 0]  q_next;

reg DFF1, DFF2;             // input flip-flops

wire q_add;                 // control flags

wire q_reset;

reg button_out_d0;

 ------------------------------------------------------

contenious assignment for counter control

assign q_reset = (DFF1  ^ DFF2);          // xor input flip flops to look for level chage to reset counter

assign q_add = ~(q_reg == TIMER_MAX_VAL); // add to counter when q_reg msb is equal to 0

    

 combo counter to manage q_next 

always @ ( q_reset, q_add, q_reg)

begin

    case( {q_reset , q_add})

        2'b00 :

                q_next <= q_reg;

        2'b01 :

                q_next <= q_reg + 1;

        default :

                q_next <= { N {1'b0} };

    endcase     

end

 Flip flop inputs and q_reg update

always @ ( posedge clk or posedge rst)

begin

    if(rst == 1'b1)

    begin

        DFF1 <= 1'b0;

        DFF2 <= 1'b0;

        q_reg <= { N {1'b0} };

    end

    else

    begin

        DFF1 <= button_in;

        DFF2 <= DFF1;

        q_reg <= q_next;

    end

end

 counter control

always @ ( posedge clk or posedge rst)

begin

if(rst == 1'b1)

button_out <= 1'b1;

    else if(q_reg == TIMER_MAX_VAL)

        button_out <= DFF2;

    else

        button_out <= button_out;

end

always @ ( posedge clk or posedge rst)

begin

if(rst == 1'b1)

begin

button_out_d0 <= 1'b1;

button_posedge <= 1'b0;

button_negedge <= 1'b0;

end

else

begin

button_out_d0 <= button_out;

button_posedge <= ~button_out_d0 & button_out;

button_negedge <= button_out_d0 & ~button_out;

end

end

endmodule

  6.5.3 seg_decoder

//

//                                                                              //

//                                                                              //

//  Author: meisq                                                               //

//          msq@qq.com                                                          //

//          ALINX(shanghai) Technology Co.,Ltd                                  //

//          heijin                                                              //

//     WEB: http://www.alinx.cn/                                                //

//     BBS: http://www.heijin.org/                                              //

//                                                                              //

//

//                                                                              //

// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd                        //

//                    All rights reserved                                       //

//                                                                              //

// This source file may be used and distributed without restriction provided    //

// that this copyright statement is not removed from the file and that any      //

// derivative work contains the original copyright notice and the associated    //

// disclaimer.                                                                  //

//                                                                              //

//

//==========================================================================

//  Revision History:

//  Date          By            Revision    Change Description

//--------------------------------------------------------------------------

//  2017/6/19     meisq         1.0         Original

//*************************************************************************/

module seg_decoder

(

input[3:0]      bin_data,     // bin data input

output reg[6:0] seg_data      // seven segments LED output

);

always@(*)

begin

case(bin_data)

4'd0:seg_data <= 7'b100_0000;

4'd1:seg_data <= 7'b111_1001;

4'd2:seg_data <= 7'b010_0100;

4'd3:seg_data <= 7'b011_0000;

4'd4:seg_data <= 7'b001_1001;

4'd5:seg_data <= 7'b001_0010;

4'd6:seg_data <= 7'b000_0010;

4'd7:seg_data <= 7'b111_1000;

4'd8:seg_data <= 7'b000_0000;

4'd9:seg_data <= 7'b001_0000;

4'ha:seg_data <= 7'b000_1000;

4'hb:seg_data <= 7'b000_0011;

4'hc:seg_data <= 7'b100_0110;

4'hd:seg_data <= 7'b010_0001;

4'he:seg_data <= 7'b000_0110;

4'hf:seg_data <= 7'b000_1110;

default:seg_data <= 7'b111_1111;

endcase

end

endmodule

  6.5.4 seg_scan

//

//                                                                              //

//                                                                              //

//  Author: meisq                                                               //

//          msq@qq.com                                                          //

//          ALINX(shanghai) Technology Co.,Ltd                                  //

//          heijin                                                              //

//     WEB: http://www.alinx.cn/                                                //

//     BBS: http://www.heijin.org/                                              //

//                                                                              //

//

//                                                                              //

// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd                        //

//                    All rights reserved                                       //

//                                                                              //

// This source file may be used and distributed without restriction provided    //

// that this copyright statement is not removed from the file and that any      //

// derivative work contains the original copyright notice and the associated    //

// disclaimer.                                                                  //

//                                                                              //

//

//==========================================================================

//  Revision History:

//  Date          By            Revision    Change Description

//--------------------------------------------------------------------------

//  2017/6/19     meisq         1.0         Original

//*************************************************************************/

module seg_scan(

input           clk,

input           rst_n,

output reg[5:0] seg_sel,      //digital led chip select

output reg[7:0] seg_data,     //eight segment digital tube output,MSB is the decimal point

input[7:0]      seg_data_0,

input[7:0]      seg_data_1,

input[7:0]      seg_data_2,

input[7:0]      seg_data_3,

input[7:0]      seg_data_4,

input[7:0]      seg_data_5

);

parameter SCAN_FREQ = 200;     //scan frequency

parameter CLK_FREQ = 50000000; //clock frequency

parameter SCAN_COUNT = CLK_FREQ /(SCAN_FREQ * 6) - 1;

reg[31:0] scan_timer;  //scan time counter

reg[3:0] scan_sel;     //Scan select counter

always@(posedge clk or negedge rst_n)

begin

if(rst_n == 1'b0)

begin

scan_timer <= 32'd0;

scan_sel <= 4'd0;

end

else if(scan_timer >= SCAN_COUNT)

begin

scan_timer <= 32'd0;

if(scan_sel == 4'd5)

scan_sel <= 4'd0;

else

scan_sel <= scan_sel + 4'd1;

end

else

begin

scan_timer <= scan_timer + 32'd1;

end

end

always@(posedge clk or negedge rst_n)

begin

if(rst_n == 1'b0)

begin

seg_sel <= 6'b111111;

seg_data <= 8'hff;

end

else

begin

case(scan_sel)

//first digital led

4'd0:

begin

seg_sel <= 6'b11_1110;

seg_data <= seg_data_0;

end

//second digital led

4'd1:

begin

seg_sel <= 6'b11_1101;

seg_data <= seg_data_1;

end

//...

4'd2:

begin

seg_sel <= 6'b11_1011;

seg_data <= seg_data_2;

end

4'd3:

begin

seg_sel <= 6'b11_0111;

seg_data <= seg_data_3;

end

4'd4:

begin

seg_sel <= 6'b10_1111;

seg_data <= seg_data_4;

end

4'd5:

begin

seg_sel <= 6'b01_1111;

seg_data <= seg_data_5;

end

default:

begin

seg_sel <= 6'b11_1111;

seg_data <= 8'hff;

end

endcase

end

end

endmodule

  7 实验结果

  下载实验程序后,可以看到数码管显示一个数字,这个数字是存储在 sd 卡中第一扇区的第一

  个数据,数据是随机的,这个时候按键 KEY1 按下,数字加一,并写入了 sd 卡,再次下载程序,

  可以看到直接显示更新后的数据。

基于FPGA实现SD NAND FLASH的SPI协议读写

基于FPGA实现SD NAND FLASH的SPI协议读写

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/31622.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习算法的电影推荐系统以及票房预测系统

一、实验概述 1. 实验目标 本项目希望基于电影数据集&#xff0c;依据电影的简介、关键词、预算、票房、用户评分等特征来对电影进行分析&#xff0c;并完成以下任务&#xff1a; 对电影特征的可视化分析对电影票房的预测多功能个性化的电影推荐算法 2. 数据集 针对票房预…

AIGC-CVPR2024best paper-Rich Human Feedback for Text-to-Image Generation-论文精读

Rich Human Feedback for Text-to-Image Generation斩获CVPR2024最佳论文&#xff01;受大模型中的RLHF技术启发&#xff0c;团队用人类反馈来改进Stable Diffusion等文生图模型。这项研究来自UCSD、谷歌等。 在本文中&#xff0c;作者通过标记不可信或与文本不对齐的图像区域&…

vulnhub靶场之FunBox-11

一.环境搭建 1.靶场描述 As always, its a very easy box for beginners. Add to your /etc/hosts: funbox11 This works better with VirtualBox rather than VMware. 2.靶场下载 https://www.vulnhub.com/entry/funbox-scriptkiddie,725/ 3.靶场启动 二.信息收集 1.寻找靶…

通过腾讯云TDSQL TCPTCE(MySQL版)认证考试秘籍宝典

腾讯云TDSQL(MySQL版)交付运维高级工程师TCCP证书展示 腾讯云TDSQL(MySQL版)交付运维专家TCCE考试成绩、证书展示 认证类型与级别 TCCA:入门级(初级) TCCP:高级(中级) TCCE:专家级(高级) 考试形式 考试是在线考试&#xff0c;考生需要在腾讯云大学官网上完成。 腾讯云TDSQ…

LabVIEW项目中的常见电机及其特点分析

在LabVIEW项目中&#xff0c;电机的选择对系统的性能和应用效果至关重要。常见电机类型包括直流电机&#xff08;DC Motor&#xff09;、步进电机&#xff08;Stepper Motor&#xff09;、交流感应电机&#xff08;AC Induction Motor&#xff09;和无刷直流电机&#xff08;BL…

mongosh常用命令详解及如何开启MongoDB身份验证

目录 Mongosh常用命令介绍 连接到MongoDB实例 基本命令 查看当前数据库 切换数据库 查看所有数据库 查看当前数据库中的集合 CRUD操作 插入文档 查询文档 更新文档 删除文档 替换文档 索引操作 创建索引 查看索引 删除索引 聚合操作 数据库管理 创建用户 …

手把手教你软著申请(带视频+包括所有模板附赠软著申请软件)

基于前面的这个软件&#xff0c;这一次我沉淀两日重新归来&#xff01; 小唐读取软件全新升级&#xff01; 现在我们开始把我们软著申请流程重新走一遍&#xff01; 要不&#xff1f;你也来申请一张软著&#xff1f; 1.中国版权保护中心注册 1.1注册 大家在这个网址处写好自…

RedisConnectionException: Unable to connect to localhost/<unresolved>:6379

方法一&#xff1a;删除配置密码选项 一般是因为你在启动redsi服务的时候没有以指定配置文件启动 把application.yml文件中的redis密码注释掉 方法二 以指定配置文件启动 这样就不用删除yml文件中密码的选项了 在redis,windows.conf 中找到requirepass&#xff0c;删除掉前…

【JavaSE复习】基础、面向对象

JavaSE复习 1.Java入门1.1 cmd常见命令1.2 JDK下载和安装1.3 JRE和JDK 2.基础语法2.1 注释和关键字2.2 常量2.3 变量2.4 数据类型2.4.1 基本数据类型2.4.2 引用数据类型 2.5 IDEA 的下载和安装 3. 运算符3.1 算数运算符3.2 数据类型转换3.2.1 隐式转换3.2.2 强制转换 3.3 自增自…

【Matlab】CNN-LSTM分类 卷积神经网络-长短期记忆神经网络组合模型(附代码)

资源下载&#xff1a; https://download.csdn.net/download/vvoennvv/89466499 分类算法资源合集&#xff1a;https://download.csdn.net/download/vvoennvv/89466519 目录 Matlab SVM支持向量机分类算法 Matlab RF随机森林分类算法 Matlab RBF径向基神经网络分类算法 Ma…

服装连锁实体店bC一体化运营方案

一、引言 随着互联网的快速发展和消费者购物习惯的变化&#xff0c;传统服装连锁实体店在面对新的市场环境下亟需转型升级。BC&#xff08;Business to Consumer&#xff09;一体化运营方案的实施将成为提升服装连锁实体店竞争力和顾客体验的关键举掖。商淘云详细介绍服装连锁…

如何将现有系统逐步优化成微服务设计

目录 基础服务改造核心步骤准备阶段实施阶段 基础服务设计 本文诞生于学习架构实践专栏后的深思以及总结&#xff0c;结合公司之前“大泥球”的架构风格&#xff0c;改造服务设计的思维。 改造公司系统服务主要原因&#xff1a;1、代码类似“屎山”&#xff0c;牵一发而动全身&…

人工智能--搭建人工神经网络

欢迎来到 Papicatch的博客 文章目录 &#x1f349;引言 &#x1f349;神经元与感知器 &#x1f348;神经元&#xff08;Neuron&#xff09; &#x1f348;感知器 &#x1f349;损失函数与梯度下降算法 &#x1f348;损失函数 &#x1f348;梯度下降算法 &#x1f349;…

cd 命令特殊路径符 mkdir命令

cd 特殊路径符 cd . 表示当前目录&#xff0c;比如 cd ./Desktop表示切换到当前目录下的Desktop目录内&#xff0c;和 cd Desktop效果一致。cd … 表示上一级目录&#xff0c;比如 cd … 即可切换到上一级目录&#xff0c;cd…/…切换到上二级目录。cd ~ 表示 HOME 目录&#…

快速又不失灵活性的JeecgBoot框架

简介JeecgBoot 开源界 "小普元" 超越传统商业平台。引领低代码开发模式 (OnlineCoding-> 代码生成器 -> 手工 MERGE)&#xff0c;低代码开发同时又支持灵活编码&#xff0c; 可以帮助解决 Java 项目 70% 的重复工作&#xff0c;让开发更多关注业务。既能快速提…

面试官:JavaScript执行机制中的闭包?

前言 JavaScript 中的闭包指的是一个函数以及其捆绑的周边环境状态的引用的组合。闭包可以让开发者从内部函数访问外部函数的作用域&#xff0c;即使外部函数已经执行完毕 今天我们通过JavaScript执行机制来聊聊闭包 正文 首先来分析这段代码的执行机制&#xff0c;这段代码…

详细解读“找不到mfc140u.dll无法继续执行代码”问题

当你打开某个软件或者运行游戏&#xff0c;系统提示mfc140u.dll丢失&#xff0c;此时这个软件或者游戏根本无法运行。其实&#xff0c;mfc140u.dll是动态库文件&#xff0c;它是VS2010编译的软件所产生的&#xff0c;如果电脑运行程序时提示缺少mfc140u.dll文件&#xff0c;程序…

复分析——第6章—— Γ 函数和 ζ 函数(E.M. Stein R. Shakarchi)

第6章 Γ函数和Ζ函数(The Gamma and Zeta Functions) 毫不夸张地说&#xff0c;Γ函数和Ζ函数是数学中最重要的非初等函数之一。Γ函数在自然界中无处不在。它出现在大量计算中&#xff0c;并以分析中出现的大量恒等式为特征。对此的部分解释可能在于Γ函数的基本结构特性&…

python20 函数的定及调用

函数的定及调用 函数是将一段实现功能的完整代码&#xff0c;使用函数名称进行封装&#xff0c;通过函数名称进行调用。以此达到一次编写&#xff0c;多次调用的目的 用 def 关键字来声明 函数 格式&#xff1a; def 函数名(参数列表):函数体[:return 返回值是可选的&#xff0…

《沃趣 分手后霸道少爷宠爆我》盛大开机典礼

南京五聚文化传媒有限公司自豪地宣布&#xff0c;引人入胜的2024年度短剧巨作——《沃趣 分手后霸道少爷宠爆我》——今日正式开拍&#xff01;在星辰下的华丽舞台上&#xff0c;我们汇集了业界的精英力量&#xff0c;准备讲述一个关于爱、错位与重生的故事。 典礼精彩亮点 1.…