查看: 1099|回复: 0

【紫光同创国产FPGA教程】【第八章】SD卡读写实验

[复制链接]
  • TA的每日心情
    开心
    2021-1-12 14:00
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2021-2-2 14:06:37 | 显示全部楼层 |阅读模式
    分享到:
    原创声明:
    本原创教程由芯驿电子科技(上海)有限公司(ALINX)创作,版权归本公司所有,如需转载,需授权并注明出处(http://www.alinx.com)。
    适用于板卡型号:
    PGL22G/PGL12G
    1. 实验简介
    SD卡是现在嵌入式设备重要的存储模块,内部集成了nand flash控制器,方便了主机的的管理。本实验主要是练习对sd卡的扇区进行读写,通常sd卡都有文件系统,可以按照文件名和目录路径来读写文件,但文件系统非常复杂,本实验不做讲解,在后续的实验中我们通过搜索特定的文件头来读特殊的文件,完成音频播放、图片读取显示等。
    2. 实验原理
    2.1 硬件描述
    开发板上装有一个Micro SD卡座,FPGA通过SPI数据总线访问Micro SD卡, SD卡座和FPGA的硬件电路连接如下:
    开发板SD卡
    在SD卡数据读写速度要求不高的情况下,选用SPI通信模式可以说是一种最佳的解决方案。因为在SPI模式下,通过四条线就可以完成所有的数据交换。本实验将为大家介绍FPGA通过SPI总线读写SD卡。要完成SD卡的FPGA读写,用户需要理解SD卡的命令协议。
    2.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。
    2.2 SD卡2.0版的初始化步骤
    • 上电后延时至少74clock,等待SD卡内部操作完成
    • 片选CS低电平选中SD卡
    • 发送CMD0,需要返回0x01,进入Idle状态
    • 为了区别SD卡是2.0还是1.0,或是MMC卡,这里根据协议向上兼容的,首先发送只有SD2.0才有的命令CMD8,如果CMD8返回无错误,则初步判断为2.0卡,进一步循环发送命令CMD55+ACMD41,直到返回0x00,确定SD2.0卡
    • 如果CMD8返回错误则判断为1.0卡还是MMC卡,循环发送CMD55+ACMD41,返回无错误,则为SD1.0卡,到此SD1.0卡初始成功,如果在一定的循环次数下,返回为错误,则进一步发送CMD1进行初始化,如果返回无错误,则确定为MMC卡,如果在一定的次数下,返回为错误,则不能识别该卡,初始化结束。(通过CMD16可以改变SD卡一次性读写的长度)
    6. CS拉高
    2.3 SD卡的读步骤
    • 发送CMD17(单块)或CMD18(多块)读命令,返回0X00
    • 接收数据开始令牌fe(或fc)+正式数据512Bytes + CRC校验2Bytes
    默认正式传输的数据长度是512Bytes

    2.4 SD卡的写步骤
    • 发送CMD24(单块)或CMD25(多块)写命令,返回0X00
    • 发送数据开始令牌fe(或fc)+正式数据512Bytes + CRC校验2Bytes
    3. 程序设计
    下面主要对sd_card_top及其子程序进行介绍和说明。sd_card_top包含3个子程序,分别为sd_card_sec_read_write.v,sd_card_cmd.v和spi_master.v文件。它们的逻辑关系如下图所示:
    3.1 sd_card_sec_read_write
    以下为sd_card_sec_read_write模块端口说明:
    信号名称方向说明
    clkin时钟输入
    rstin异步复位输入,高复位
    sd_init_doneoutsd卡初始化完成
    sd_sec_readinsd卡扇区读请求
    sd_sec_read_addrinsd卡扇区读地址
    sd_sec_read_dataoutsd卡扇区读出的数据
    sd_sec_read_data_validoutsd卡扇区读出的数据有效
    sd_sec_read_endoutsd卡扇区读完成
    sd_sec_writeinsd卡扇区写请求
    sd_sec_write_addrinsd卡扇区写请求应答
    sd_sec_write_datainsd卡扇区写请求数据
    sd_sec_write_data_reqoutsd卡扇区写请求数据读取,提前sd_sec_write_data一个时钟周期
    sd_sec_write_endoutsd卡扇区写请求完成
    spi_clk_divinSPI时钟分频,SPI时钟频率=系统时钟/(( spi_clk_div + 2)*2)
    cmd_reqinsd卡命令请求
    cmd_req_ackoutsd卡命令请求应答
    cmd_req_erroroutsd卡命令请求错误
    cmdinsd卡命令,命令+参数+CRC,一共48bit
    cmd_r1insd卡命令期待的R1响应
    cmd_data_leninsd卡命令后读取的数据长度,大部分命令没有读取数据
    block_read_reqin块数据读取请求
    block_read_validout块数据读取数据有效
    block_read_dataout块数据读取数据
    block_read_req_ackout块数据读取请求应答
    block_write_reqin块数据写请求
    block_write_datain块数据写数据
    block_write_data_rdout块数据写数据请求,提前block_write_data一个时钟周期
    block_write_req_ackout块数据写请求应答
    sd_card_sec_read_write模块有一个状态机,首先完成SD卡初始化,下图为模块的初始化状态机转换图,首先发送CMD0命令,然后发送CMD8命令,再发送CMD55,接着发送ACMD41和CMD16。如果应答正常,sd卡初始化完成,等待SD卡扇区的读写命令。
    然后等待扇区读写指令,并完成扇区的读写操作,下图为模块的读写状态机转换图。
    在此模块中定义了两个参数,SD卡的初始化过程是需要先用慢时钟来发送命令和配置,等待初始化成功后再用快时钟来进行数据读写。
    parameter SPI_LOW_SPEED_DIV = 248
    parameter SPI_HIGH_SPEED_DIV = 0
    3.2 sd_card_cmd
    sd_card_cmd模块端口的说明如下:
    信号名称方向说明
    sys_clkin时钟输入
    rstin异步复位输入,高复位
    spi_clk_divinSPI时钟分频,SPI时钟频率=系统时钟/(( spi_clk_div + 2)*2)
    cmd_reqinsd卡命令请求
    cmd_req_ackoutsd卡命令请求应答
    cmd_req_erroroutsd卡命令请求错误
    cmdinsd卡命令,命令+参数+CRC,一共48bit
    cmd_r1insd卡命令期待的R1响应
    cmd_data_leninsd卡命令后读取的数据长度,大部分命令没有读取数据
    block_read_reqin块数据读取请求
    block_read_validout块数据读取数据有效
    block_read_dataout块数据读取数据
    block_read_req_ackout块数据读取请求应答
    block_write_reqin块数据写请求
    block_write_datain块数据写数据
    block_write_data_rdout块数据写数据请求,提前block_write_data一个时钟周期
    block_write_req_ackout块数据写请求应答
    nCS_ctrlout到SPI master控制器,cs片选控制
    clk_divout到SPI Master控制器,时钟分频参数
    spi_wr_reqout到SPI Master控制器,写一个字节请求
    spi_wr_ackin来自SPI Master控制器,写请求应答
    spi_data_inout到SPI Master控制器,写数据
    spi_data_outin来自SPI Master控制器,读数据
    sd_card_cmd模块主要实现sd卡基本命令操作,还有上电初始化的88个周期的时钟,数据块的命令和读写的状态机如下。
    从SD2.0的标准里我们可以看到,从主控设备写命令到SD卡, 最高两位47~46位必须为“01”,代表命令发送开始。
    所以代码中都是将48位命令的高八位与十六进制0x40做或操作得到的结果再写入,所以才有了如下一段代码:
    3.3 spi_master
    spi_master模块主要完成SPI一个字节的读写,当SPI状态机在idle的时候,检测到wr_req的信号为高,会产生8个DCLK,并把datain的数据从高位依次输出到MOSI信号线上。MOSI在8个DCLK的输出数据为datain的值0x58。
    同时spi_master程序也会读取MISO输入的数据,转换成8位的data_out数据输出实现SPI的一个字节的数据读取。
    4. 实验现象
    下载实验程序后,可以看到LED显示一个二进制数字,这个数字是存储在sd卡中第一扇区的第一个数据,数据是随机的,这个时候按键KEY2按下,数字加一,并写入了sd卡,再次下载程序,可以看到直接显示更新后的数据。

    开发板

    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-4-25 15:20 , Processed in 0.104901 second(s), 15 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.