利用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卡上电后,默认为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;