通信控制篇——SD卡数据传输(一)

Yelena ·
更新时间:2024-09-21
· 673 次阅读

通信控制篇——SD卡数据传输(一) 1.简介

利用FPGA实现SD卡数据传输——SPI模式。

2.原理 SD卡简介

SD卡——Secure Digital Memory Card。最早的SD卡是从MMC卡发展而来的,目前SD卡有三种规范——SD1.0、SD2.0和SD3.0,SD1.0已经不用了,目前主流的规范是SD2.0和SD3.0,SD2.0被称为高速卡,传输速度在2MB/s以上,SD3.0被称为超高速卡,传输速度可达104MB/s。

SD卡容量有3个级别——SD、SDHC和SDXC,下表为各等级的容量范围和标准磁盘格式:

容量等级 容量范围 磁盘格式
SD 不大于2GB FAT12,16
SDHC 2GB~32GB FAT32
SDXC 32GB~2TB exFAT

SD2.0规范中,规定了不同传输速率的等级,如下表:

速率等级 性能要求
Class 0 无性能要求
Class 2 大于等于2MB/s
Class 4 大于等于4MB/s
Class 6 大于等于6MB/s
Class 10 大于等于10MB/s

在市面上买的SD卡,卡面上会印有“HC”字样,这代表这张卡是SDHC卡,同理,印有“XC”字样的代表是SDXC卡;而且,卡面上还印有一个圆圈圈起来的数字,这代表速率等级,如4就代表Class 4类型的卡。

在这里插入图片描述

SD卡数据通信

SD卡一般支持两种通信模式,SPI模式和SD模式,这两种模式分别需要使用到的信号及其对应关系如下表:

SD模式信号名 SPI模式信号名
SD_CLK SD_CLK
SD_CMD SD_DATAIN
SD_DATA0 SD_DATAOUT
SD_DATA1 -
SD_DATA2 -
SD_DATA3 SD_CS

在SD卡数据读写时间要求不是很严格的情况下,选用SPI模式可以说是一种最佳的解决方案。因为在SPI模式下,使用相对简单,只要四条线就可以完成所有的数据交换。本文主要介绍SPI模式的数据通信。

SD2.0命令协议

SD卡的协议是一种简单的命令/响应的协议。全部命令由主机发起,SD卡接收到命令后并返回响应数据。根据命令的不同,返回的数据内容和长度也不同。

SD卡命令是一个6字节组成的命令包,其中第一个字节为命令号,命令号高位bit7和bit6为固定的“01“,其它6个bit为具体的命令号。第2个字节到第5个字节为命令参数。第6个字节为7个bit的CRC校验加1个bit的结束位“1”。如果在SPI模式的时候,CRC校验位为可选。

SD卡命令格式:

First Byte Byte 2-5 Last Byte
‘0’+‘1’+Command Argument (MSB First) CRC+‘1’

SD卡对每个命令会返回一个响应,每个命令有一定的响应格式。响应的格式跟给它的命令号有关。在SPI模式中,有三种响应格式:R1(1个字节),R2(2个字节),R3(5个字节)。(具体可参照SD2.0协议官方文档,本文不再赘述)

下面列举一些常用的SD命令及响应格式:

Command Argument Type Description
CMD0 None R1 Tell the card to reset and enter its idle state
CMD16 32-bit Block Length R1 Select the block length
CMD17 32-bit Block Address R1 Read a single block
CMD24 32-bit Block Address R1 Write a single block
CMD55 None R1 Next command will be application-specific (ACMD××)
CMD58 None R3 Read OCR (Operating Conditions Register)
ACMD41 None R1 Initialize the card
SD卡初始化 选择SPI模式

SD卡上电后,默认为SD模式,只要在发送CMD0命令的同时使得CS置低,若SD卡返回响应无错误,则已经进入了SPI模式。一旦选择了SPI模式,只有当SD卡掉电重启后,才会退出SPI模式。

SPI模式初始化步骤 发送CMD0,需要返回0x01,进入Idle状态(这一步同时需要令CS置低,选择SPI模式); 为了区别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卡,如果在一定的次数下,返回为错误,则不能识别该卡,初始化结束。 CS拉高。 初始化流程图

初始化流程图

流程图详细说明请参考SD2.0协议官方文档。

SD卡数据读取 发送CMD17(单块)或CMD18(多块)读命令,返回0x00; 接收数据开始令牌0xfe(或0xfc)+正式数据512Bytes + CRC校验2Bytes。默认正式传输的数据长度是512Bytes,可用CMD16设置块长度。

在这里插入图片描述

SD卡数据写入 发送CMD24(单块)或CMD25(多块)写命令,返回0x00; 发送数据开始令牌0xfe(或0xfc)+正式数据512Bytes + CRC校验2Bytes。

在这里插入图片描述

关于具体的SD2.0的时序和标准,请大家参考文档SD2.0_Final_bookmark.pdf

3.程序实现 SD卡初始化模块 library ieee; use ieee.std_logic_1164.all; entity sd_init is port ( sd_clk : in std_logic; --sd卡SPI时钟25MHz rst : in std_logic; --复位信号,低电平有效 sd_cs : out std_logic; --sd片选信号,低电平有效,在发送和接收数据时,CS都需要置0 sd_data_in : out std_logic; --sd卡数据输入 sd_data_out : in std_logic; --sd卡数据输出 rx : buffer std_logic_vector(47 downto 0); --接收sd卡输出数据(存储48位) init_o : out std_logic; --sd卡初始化完成信号,高电平有效 init_state : buffer std_logic_vector(3 downto 0) --sd初始化状态 ); end sd_init; architecture tt of sd_init is --常量定义 constant idle:std_logic_vector(3 downto 0):= "0000"; --状态为idle constant send_cmd0:std_logic_vector(3 downto 0):= "0001"; --状态为发送CMD0 constant wait_cmd0:std_logic_vector(3 downto 0):= "0010"; --状态为等待CMD0应答 constant wait_time:std_logic_vector(3 downto 0):= "0011"; --状态为等待一段时间 constant send_cmd8:std_logic_vector(3 downto 0):= "0100"; --状态为发送CMD8 constant wait_cmd8:std_logic_vector(3 downto 0):= "0101"; --状态为等待CMD8应答 constant send_cmd55:std_logic_vector(3 downto 0):= "0110"; --状态为发送CMD55 constant send_acmd41:std_logic_vector(3 downto 0):= "0111"; --状态为发送ACMD41 constant init_done:std_logic_vector(3 downto 0):= "1000"; --状态为初始化结束 constant init_fail:std_logic_vector(3 downto 0):= "1001"; --状态为初始化错误 --信号定义 signal CMD0:std_logic_vector(47 downto 0):= x"400000000095"; --CMD0命令, 需要CRC 95 signal CMD8:std_logic_vector(47 downto 0):= x"48000001aa87"; --CMD8命令, 需要CRC 87 signal CMD55:std_logic_vector(47 downto 0):= x"7700000000ff"; --CMD55命令, 不需要CRC signal ACMD41:std_logic_vector(47 downto 0):= x"6940000000ff"; --ACMD41命令, 不需要CRC signal reset:std_logic:= '1'; --复位信号,高电平时有效,进行延时片选sd卡复位;低电平时进行sd卡初始化 signal init_cnt:integer range 0 to 1023 := 0; --初始化计时计数器 signal delay_cnt:integer range 0 to 1023 := 0; --延时计数器 signal bit_cnt:integer range 0 to 47 := 0; --48位命令传输计数器 signal rx_valid:std_logic:= '0'; --接收数据有效信号(即接收48位命令完成) signal rx_start:std_logic:= '0'; --开始接收数据 begin --接收sd卡的数据 process(sd_clk) begin if(sd_clk'event and sd_clk = '1')then rx(0) <= sd_data_out; rx(47 downto 1) <= rx(46 downto 0); end if; end process; --接收sd卡的命令应答信号 process(sd_clk) begin if(sd_clk'event and sd_clk = '1')then if((sd_data_out = '0') and (rx_start = '0'))then --等待sd_data_out为低,则开始接收数据 rx_valid <= '0'; bit_cnt <= 1; --接收到第一位为0 rx_start <= '1'; --开始接收命令 elsif(rx_start = '1')then if(bit_cnt < 47)then --计数 bit_cnt <= bit_cnt + 1; rx_valid <= '0'; else bit_cnt <= 0; rx_start <= '0'; rx_valid <= '1'; --接收到第48位,命令应答接收完毕,数据有效 end if; else rx_start <= '0'; bit_cnt <= 0; rx_valid <= '0'; end if; end if; end process; --上电后延时计数,释放reset信号 process(sd_clk) begin if(sd_clk'event and sd_clk = '1')then if(rst = '0')then init_cnt <= 0; reset <= '1'; else if(init_cnt < 1023)then init_cnt <= init_cnt + 1; reset <= '1'; else reset <= '0'; end if; end if; end if; end process; --sd卡初始化程序 process(sd_clk) begin if(sd_clk'event and sd_clk = '1')then if(reset = '1')then if(init_cnt < 512)then sd_cs <= '0'; sd_data_in <= '1'; init_o <= '0'; init_state <= idle; else sd_cs <= '1'; sd_data_in <= '1'; init_o <= '0'; init_state sd_cs <= '1'; sd_data_in <= '1'; init_o <= '0'; CMD0 <= x"400000000095"; delay_cnt <= 0; init_state if(CMD0 /= x"000000000000")then sd_cs <= '0'; sd_data_in <= CMD0(47); CMD0 <= CMD0(46 downto 0) & '0'; else sd_cs <= '0'; sd_data_in <= '1'; init_state if(rx_valid = '1' and (rx(47 downto 40) = x"01"))then sd_cs <= '1'; sd_data_in<= '1'; init_state <= wait_time; elsif(rx_valid = '1' and (rx(47 downto 40) /= x"01"))then sd_cs <= '1'; sd_data_in<= '1'; init_state <= idle; else sd_cs <= '0'; sd_data_in<= '1'; init_state if(delay_cnt < 1023)then sd_cs <= '1'; sd_data_in<= '1'; init_state <= wait_time; delay_cnt <= delay_cnt + 1; else sd_cs <= '1'; sd_data_in<= '1'; init_state <= send_cmd8; CMD8 <= x"48000001aa87"; delay_cnt if(CMD8 /= x"000000000000")then sd_cs <= '0'; sd_data_in <= CMD8(47); CMD8 <= CMD8(46 downto 0) & '0'; else sd_cs <= '0'; sd_data_in<= '1'; init_state sd_cs <= '0'; sd_data_in <= '1'; if(rx_valid = '1' and (rx(19 downto 16) = "0001"))then init_state <= send_cmd55; CMD55 <= x"7700000000ff"; ACMD41 <= x"6940000000ff"; elsif(rx_valid = '1' and (rx(19 downto 16) /= "0001"))then init_state if(CMD55 /= x"000000000000")then sd_cs <= '0'; sd_data_in <= CMD55(47); CMD55 <= CMD55(46 downto 0) & '0'; else sd_cs <= '0'; sd_data_in <= '1'; if(rx_valid = '1' and (rx(47 downto 40) = x"01"))then init_state <= send_acmd41; else if(delay_cnt < 127)then delay_cnt <= delay_cnt + 1; else delay_cnt <= 0; init_state if(ACMD41 /= x"000000000000")then sd_cs <= '0'; sd_data_in <= ACMD41(47); ACMD41 <= ACMD41(46 downto 0) & '0'; else sd_cs <= '0'; sd_data_in <= '1'; if(rx_valid = '1' and (rx(47 downto 40) = x"00"))then init_state <= init_done; else if(delay_cnt < 127)then delay_cnt <= delay_cnt + 1; else delay_cnt <= 0; init_state init_o <= '1'; sd_cs <= '1'; sd_data_in <= '1'; delay_cnt init_o <= '0'; sd_cs <= '1'; sd_data_in <= '1'; delay_cnt <= 0; init_state init_o <= '0'; sd_cs <= '1'; sd_data_in <= '1'; delay_cnt <= 0; init_state <= idle; end case; end if; end if; end process; end tt; SD卡数据读取模块 library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; entity sd_read is port ( sd_clk : in std_logic; --SD卡时钟 sd_cs : out std_logic; --SD卡片选,0有效,在发送和接收数据时,CS都需要置0 sd_data_in : out std_logic; --SD卡数据输入 sd_data_out : in std_logic; --SD卡数据输出 sec : in std_logic_vector(31 downto 0); --SD卡的sec地址 read_req : in std_logic; --SD卡数据读请求信号,1有效 sd_data : out std_logic_vector(7 downto 0); --SD卡读出的数据 data_valid : out std_logic; --数据有效信号,1有效 data_come : out std_logic; --SD卡数据起始位读出信号,1有效 init_o : in std_logic; --SD卡初始化完成信号,1有效 read_state : buffer std_logic_vector(3 downto 0); --SD卡读状态 read_o : out std_logic --SD卡读完成,1有效 ); end sd_read; architecture tt of sd_read is --常量定义:SD读取状态 constant idle:std_logic_vector(3 downto 0):= x"0"; constant read_cmd:std_logic_vector(3 downto 0):= x"1"; constant read_wait:std_logic_vector(3 downto 0):= x"2"; constant read_data:std_logic_vector(3 downto 0):= x"3"; constant read_done:std_logic_vector(3 downto 0):= x"4"; --信号定义 signal rx:std_logic_vector(7 downto 0); signal rx_start:std_logic; signal rx_valid:std_logic; signal bit_cnt_1:integer range 0 to 7; signal bit_cnt_2:integer range 0 to 7; signal read_cnt_1:integer range 0 to 1023; signal read_cnt_2:integer range 0 to 1023; signal read_start:std_logic; signal read_finish:std_logic; signal data_buffer:std_logic_vector(7 downto 0); signal read_step:integer range 0 to 3; signal CMD17:std_logic_vector(47 downto 0):= x"5100000000ff"; begin --接收SD卡数据 process(sd_clk) begin if(sd_clk'event and sd_clk = '1')then rx(0) <= sd_data_out; rx(7 downto 1) <= rx(6 downto 0); end if; end process; --接收一个block读命令的应答数据 process(sd_clk) begin if(sd_clk'event and sd_clk = '1')then if(sd_data_out = '0' and rx_start = '0')then --检测到应答起始位0 rx_valid <= '0'; bit_cnt_1 <= 1; --第一位:0 rx_start <= '1'; --开始接收 elsif(rx_start = '1')then if(bit_cnt_1 < 7)then --共接收8bit应答数据 bit_cnt_1 <= bit_cnt_1 + 1; rx_valid <= '0'; else bit_cnt_1 <= 0; rx_start <= '0'; rx_valid <= '1'; --接收完成,数据有效 end if; else rx_start <= '0'; bit_cnt_1 <= 0; rx_valid <= '0'; end if; end if; end process; --block SD读流程 process(sd_clk) begin if(sd_clk'event and sd_clk = '1')then if(init_o = '0')then --只有当初始化工作完成,才进行读取 read_state <= idle; CMD17 <= x"5100000000ff"; read_start <= '0'; read_o <= '0'; sd_cs <= '1'; sd_data_in read_start <= '0'; sd_cs <= '1'; sd_data_in <= '1'; read_cnt_1 <= 0; if(read_req = '1')then --当有读取请求时,开始读取流程,给SD卡发送命令 read_state <= read_cmd; read_o <= '0'; CMD17 <= x"51" & sec & x"ff"; else read_state --发送读取命令 read_start <= '0'; if(CMD17 /= x"000000000000")then sd_cs <= '0'; sd_data_in <= CMD17(47); CMD17 <= CMD17(46 downto 0) & '0'; read_cnt_1 <= 0; else if(rx_valid = '1')then --接收应答信号完成,进入等待数据读取完成状态...似乎没有检测应答是否正确 read_cnt_1 <= 0; read_state --等待数据读取完成 if(read_finish = '1')then read_state <= read_done; read_start <= '0'; else read_start --读取完成 read_start <= '0'; if(read_cnt_1 < 15)then --等待15个时钟后,进入空闲状态 sd_cs <= '1'; sd_data_in <= '1'; read_cnt_1 <= read_cnt_1 + 1; else read_cnt_1 <= 0; read_state <= idle; read_o read_state <= idle; end case; end if; end if; end process; --接收SD的512个数据 process(sd_clk) begin if(sd_clk'event and sd_clk = '1')then if(init_o = '0')then data_valid <= '0'; sd_data <= x"00"; data_buffer <= x"00"; read_step <= 0; read_finish <= '0'; data_come --等待数据起始位:一般SD卡发出应答信号后,还要等待一段时间,才会发送数据 bit_cnt_2 <= 0; read_cnt_2 <= 0; read_finish <= '0'; if(read_start = '1' and sd_data_out = '0')then --检测到数据起始位0 read_step <= 1; data_come <= '1'; else read_step if(read_cnt_2 < 512)then --一共512byte if(bit_cnt_2 < 7)then --一字节8bit data_valid <= '0'; data_buffer <= data_buffer(6 downto 0) & sd_data_out; bit_cnt_2 <= bit_cnt_2 + 1; data_come <= '0'; else data_valid <= '1'; sd_data <= data_buffer(6 downto 0) & sd_data_out; bit_cnt_2 <= 0; read_cnt_2 <= read_cnt_2 + 1; data_come <= '0'; end if; else read_finish <= '1'; --读取完成 read_step <= 0; data_valid <= '0'; data_come read_step <= 0; end case; end if; end if; end process; end tt; SD卡数据写入模块 library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; entity sd_write is port ( sd_clk : in std_logic; --sd时钟 sd_cs : out std_logic; --sd片选信号,0有效,在发送和接收数据时,CS都需要置0 sd_data_in : out std_logic; --sd数据输入 sd_data_out : in std_logic; --sd数据输出 init_o : in std_logic; --初始化完成信号:1有效 sec : in std_logic_vector(31 downto 0); --写sd的sec地址 write_req : in std_logic; --写sd卡请求,1有效 write_state : buffer std_logic_vector(3 downto 0); --写sd卡的状态 rx_valid : buffer std_logic; --接收数据有效(即接收应答完成),1有效 write_o : out std_logic --写sd完成,1有效 ); end sd_write; architecture tt of sd_write is --常量定义 constant idle:std_logic_vector(3 downto 0):= "0000"; --空闲状态 constant write_cmd:std_logic_vector(3 downto 0):= "0001"; --发送CMD24命令 constant wait_8clk:std_logic_vector(3 downto 0):= "0010"; --写数据前等待8clock constant start_taken:std_logic_vector(3 downto 0):= "0011"; --发送start block taken constant writea:std_logic_vector(3 downto 0):= "0100"; --写512个字节(0~255,0~255)到SD卡 constant write_crc:std_logic_vector(3 downto 0):= "0101"; --写crc:0xff,0xff constant write_wait:std_logic_vector(3 downto 0):= "0110"; --等待数据写入完成 constant write_done:std_logic_vector(3 downto 0):= "0111"; --数据写入完成 --信号定义 signal rx:std_logic_vector(7 downto 0); --接收数据 signal rx_start:std_logic; --开始接收数据:高电平有效 signal bit_cnt:integer range 0 to 7; signal write_cnt:integer range 0 to 1023; signal data_cnt:integer range 0 to 7; signal write_cnt_reg:std_logic_vector(9 downto 0); signal CMD24:std_logic_vector(47 downto 0):= x"5800000000ff"; signal start_block_token:std_logic_vector(7 downto 0):= x"fe"; --令牌字 begin write_cnt_reg <= conv_std_logic_vector(write_cnt, 10); --接收SD卡输出数据 process(sd_clk) begin if(sd_clk'event and sd_clk = '1')then rx(0) <= sd_data_out; rx(7 downto 1) <= rx(6 downto 0); end if; end process; --接收SD卡应答信号 process(sd_clk) begin if(sd_clk'event and sd_clk = '1')then if(sd_data_out = '0' and rx_start = '0')then --检测到应答起始位0 rx_valid <= '0'; bit_cnt <= 1; rx_start <= '1'; elsif(rx_start = '1')then if(bit_cnt < 7)then bit_cnt <= bit_cnt + 1; rx_valid <= '0'; else bit_cnt <= 0; rx_start <= '0'; rx_valid <= '1'; --接收完成,数据有效 end if; else rx_start <= '0'; bit_cnt <= 0; rx_valid <= '0'; end if; end if; end process; --SD卡写程序 process(sd_clk) begin if(sd_clk'event and sd_clk = '1')then if(init_o = '0')then --只有当初始化工作完成,才进行写入 write_state <= idle; CMD24 <= x"5800000000ff"; write_o sd_cs <= '1'; sd_data_in <= '1'; write_cnt <= 0; if(write_req = '1')then --当有写请求时,开始写流程,给SD卡发送命令 write_state <= write_cmd; CMD24 <= x"58" & sec & x"ff"; start_block_token <= x"fe"; write_o <= '0'; else write_state --发送写命令 if(CMD24 /= x"000000000000")then sd_cs <= '0'; sd_data_in <= CMD24(47); CMD24 <= CMD24(46 downto 0) & '0'; else if(rx_valid = '1')then data_cnt <= 7; write_state <= wait_8clk; sd_cs <= '1'; sd_data_in --写数据之前等待8clock if(data_cnt > 0)then data_cnt <= data_cnt - 1; sd_cs <= '1'; sd_data_in <= '1'; else sd_cs <= '1'; sd_data_in <= '1'; write_state <= start_taken; data_cnt --发送Start Block Taken if(data_cnt > 0)then data_cnt <= data_cnt - 1; sd_cs <= '0'; sd_data_in <= start_block_token(data_cnt); else sd_cs <= '0'; sd_data_in <= start_block_token(0); write_state <= writea; data_cnt <= 7; write_cnt --写512个字节(0~255,0~255)到SD卡 if(write_cnt 0)then sd_cs <= '0'; sd_data_in <= write_cnt_reg(data_cnt); data_cnt <= data_cnt - 1; else sd_cs <= '0'; sd_data_in <= write_cnt_reg(0); data_cnt <= 7; write_cnt 0)then sd_data_in <= write_cnt_reg(data_cnt); data_cnt <= data_cnt - 1; else sd_data_in <= write_cnt_reg(0); data_cnt <= 7; write_cnt <= 0; write_state --写crc:0xff,0xff if(write_cnt < 16)then sd_cs <= '0'; sd_data_in <= '1'; write_cnt <= write_cnt + 1; else if(rx_valid = '1')then --等待Data Response Token write_state <= write_wait; else write_state --等待数据写入完成 if(rx = x"ff")then write_state <= write_done; else write_state if(write_cnt < 15)then --等待15个clock sd_cs <= '1'; sd_data_in <= '1'; write_cnt <= write_cnt + 1; else write_state <= idle; write_o <= '1'; write_cnt write_state <= idle; end case; end if; end if; end process; end tt; 顶层模块 library ieee; use ieee.std_logic_1164.all; entity sd_test is port ( clk_50MHz : in std_logic; rst : in std_logic; sd_clk : out std_logic; sd_cs : out std_logic; sd_data_in : out std_logic; sd_data_out : in std_logic; LED1 : out std_logic ); end sd_test; architecture tt of sd_test is --元件例化 component sd_init port ( sd_clk : in std_logic; --sd卡SPI时钟25MHz rst : in std_logic; --复位信号,低电平有效 sd_cs : out std_logic; --sd片选信号 sd_data_in : out std_logic; --sd卡数据输入 sd_data_out : in std_logic; --sd卡数据输出 rx : buffer std_logic_vector(47 downto 0); --接收sd卡输出数据(存储48位) init_o : out std_logic; --sd卡初始化完成信号,高电平有效 init_state : buffer std_logic_vector(3 downto 0) --sd初始化状态 ); end component; component sd_write port ( sd_clk : in std_logic; --sd时钟 sd_cs : out std_logic; --sd片选信号 sd_data_in : out std_logic; --sd数据输入 sd_data_out : in std_logic; --sd数据输出 init_o : in std_logic; --初始化完成信号:高电平有效 sec : in std_logic_vector(31 downto 0); --写sd的sec地址 write_req : in std_logic; --写sd卡请求 write_state : buffer std_logic_vector(3 downto 0); --写sd卡的状态 rx_valid : buffer std_logic; --接收数据有效(即接收应答完成) write_o : out std_logic --写sd完成 ); end component; component sd_read port ( sd_clk : in std_logic; --SD卡时钟 sd_cs : out std_logic; --SD卡片选 sd_data_in : out std_logic; --SD卡数据输入 sd_data_out : in std_logic; --SD卡数据输出 sec : in std_logic_vector(31 downto 0); --SD卡的sec地址 read_req : in std_logic; --SD卡数据读请求信号 sd_data : out std_logic_vector(7 downto 0); --SD卡读出的数据 data_valid : out std_logic; --数据有效信号 data_come : out std_logic; --SD卡数据读出指示信号 init_o : in std_logic; --SD卡初始化完成信号 read_state : buffer std_logic_vector(3 downto 0); --SD卡读状态 read_o : out std_logic --SD卡读完成 ); end component; --常量定义 constant status_init:std_logic_vector(1 downto 0):= "00"; constant status_write:std_logic_vector(1 downto 0):= "01"; constant status_read:std_logic_vector(1 downto 0):= "10"; constant status_idle:std_logic_vector(1 downto 0):= "11"; --信号定义 signal clk_25MHz:std_logic; signal sd_data_in_i:std_logic; signal sd_data_in_w:std_logic; signal sd_data_in_r:std_logic; signal sd_data_in_o:std_logic; signal sd_cs_i:std_logic; signal sd_cs_w:std_logic; signal sd_cs_r:std_logic; signal sd_cs_o:std_logic; signal read_sec:std_logic_vector(31 downto 0); signal read_req:std_logic; signal write_sec:std_logic_vector(31 downto 0); signal write_req:std_logic; signal data_come:std_logic; signal sd_data:std_logic_vector(7 downto 0); signal data_valid:std_logic; signal rx_valid:std_logic; signal init_o:std_logic; --初始化完成 signal write_o:std_logic; --写完成 signal read_o:std_logic; --读完成 signal sd_state:std_logic_vector(1 downto 0); --SD卡状态:空闲、初始化、写、读 signal init_state:std_logic_vector(3 downto 0); signal write_state:std_logic_vector(3 downto 0); signal read_state:std_logic_vector(3 downto 0); begin sd_clk <= clk_25MHz; sd_cs <= sd_cs_o; sd_data_in <= sd_data_in_o; --时钟分频 process(clk_50MHz) begin if(clk_50MHz'event and clk_50MHz = '1')then clk_25MHz <= not clk_25MHz; end if; end process; --SD卡初始化,block写,block读 process(clk_25MHz) begin if(clk_25MHz'event and clk_25MHz = '1')then if(rst = '0')then LED1 <= '1'; --用于测试 sd_state <= status_init; read_req <= '0'; read_sec <= x"00000000"; write_req <= '0'; write_sec <= x"00000000"; else LED1 if(init_o = '1')then --初始化完成,开始写SD卡 sd_state <= status_write; write_sec <= x"00000000"; write_req <= '1'; --产生写请求 else sd_state if(write_o = '1')then --SD卡写完成,开始读SD卡 sd_state <= status_read; read_sec <= x"00000000"; read_req <= '1'; --产生读请求 else write_req <= '0'; --写入未完成,取消写请求 sd_state if(read_o = '1')then --读完成,进入空闲状态 sd_state <= status_idle; else read_req <= '0'; --读未完成,取消读请求 sd_state sd_state sd_state --初始化 sd_cs_o <= sd_cs_i; sd_data_in_o --写 sd_cs_o <= sd_cs_w; sd_data_in_o --读 sd_cs_o <= sd_cs_r; sd_data_in_o --空闲 sd_cs_o <= '1'; sd_data_in_o clk_25MHz, rst => rst, sd_cs => sd_cs_i, sd_data_in => sd_data_in_i, sd_data_out => sd_data_out, --rx => init_o => init_o, init_state => init_state ); --SD卡写入 u2:sd_write port map ( sd_clk => clk_25MHz, sd_cs => sd_cs_w, sd_data_in => sd_data_in_w, sd_data_out => sd_data_out, init_o => init_o, sec => write_sec, write_req => write_req, write_state => write_state, rx_valid => rx_valid, write_o => write_o ); --SD卡读取 u3:sd_read port map ( sd_clk => clk_25MHz, sd_cs => sd_cs_r, sd_data_in => sd_data_in_r, sd_data_out => sd_data_out, sec => read_sec, read_req => read_req, sd_data => sd_data, data_valid => data_valid, data_come => data_come, init_o => init_o, read_state => read_state, read_o => read_o ); end tt;
作者:YongxiangG



sd卡 数据 sd 通信

需要 登录 后方可回复, 如果你还没有账号请 注册新账号