超高速SD卡拷贝机

2009年6月,项目进行中......

[概述]

    目前各种各样的多媒体得到广泛应用,如MP3,MP4,GPS,数码相框,CMMB移动电视等,对SD卡的需求量非常大,很多产品出厂时需要预先在SD卡中拷贝大量的软件或资料,由于文件量比较大,如何提高拷贝速度,从而提高生产效率成了关键性的问题。我们平时烧一个AT89C52的单片机,只需要几秒钟的时间,而现在拷贝1张1GB 的SD卡却要3-5分钟。

    我们先来分析在电脑上拷贝SD卡的情况,当我们在电脑上拷贝单张SD卡时,普通卡的写速度在3-6MB/秒左右,1GB的卡需要220秒(3分半钟),当我们同时拷多张卡,电脑/USB/HUB带宽将被共享,根据目前的测试,8张卡,1GB文件,需要5分钟以上,90张/小时,所以采用电脑做为拷贝机时,速度并不能得到保证,市面上基于电脑的拷贝机成本高昂,动辄几万元,并且使用不便,不好管理。

    针对当前的供需矛盾,我们采用全新的方法来设计SD拷贝机,力求能达到SD本身的极限速度,独立使用,体积小巧。采用32位MCU和FPGA进行设计,1拖8或1拖10,同步并行复制,最高可达到33MB/秒,实际速度受卡本身的 最高速度限制。

[设计特点]

1、采用32位处理器。

2、采用FPGA读写SD卡。

3、4线SD模式读写。

[设计指标]

一次拷贝数量 10张
支持容量 32MB-16GB
支持卡种类 普通SD卡、高速SD卡、miniSD卡、microSD卡、SDHC卡,1.0卡2.0卡
速度 最高33MB/秒,实际受卡本身****速度限制,
文件系统 FAT32,FAT16
读卡器插口可更换 可以
LCD显示工作状态
LED指示工作状态
声音提示
坏卡检测
统计功能
功能 格式化、拷贝、校验、拷贝+校验
复制方式 同步并行
不同厂商不同容量的SD卡同时拷贝 支持

 


 

以下为读写4GB,1GB卡过程

Init A card, wiat...Init OK!
SD卡版本=0
卡容量=7860224扇区 = 4024434688字节
CRC is OK!
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02
03 01 0B 5D DD CE 00 20 00 00 00 D0 77 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA
CRC is OK!
写入: B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
读出:
B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02
03 01 0B 5D DD CE 00 20 00 00 00 D0 77 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA
CRC is OK!
StartSector = 8192
CRC is OK!
BytesPerSec=512
SecPerClus=8
ReservedSectorsNum=36
NumFATs=2
Found FAT32
RootEntCnt=0
TotSec32=7852032 * 512=4020240384字节
FATSz32=7654
RootStartCluster=2
FatStartSector=8228
FirstDataSector=23536
TotCluster=979586 *SecPerClus=7836688扇区
CRC is OK!
FAT表:
F8 FF FF 0F FF FF FF FF FF FF FF 0F FF FF FF FF
FF FF FF FF FF FF FF 0F 07 00 00 00 08 00 00 00
09 00 00 00 0A 00 00 00 0B 00 00 00 0C 00 00 00
0D 00 00 00 0E 00 00 00 0F 00 00 00 10 00 00 00
11 00 00 00 12 00 00 00 13 00 00 00 14 00 00 00
15 00 00 00 16 00 00 00 17 00 00 00 18 00 00 00
19 00 00 00 1A 00 00 00 1B 00 00 00 1C 00 00 00
1D 00 00 00 1E 00 00 00 1F 00 00 00 20 00 00 00
21 00 00 00 22 00 00 00 23 00 00 00 24 00 00 00
25 00 00 00 26 00 00 00 27 00 00 00 28 00 00 00
29 00 00 00 2A 00 00 00 2B 00 00 00 2C 00 00 00
2D 00 00 00 2E 00 00 00 2F 00 00 00 30 00 00 00
31 00 00 00 32 00 00 00 33 00 00 00 34 00 00 00
35 00 00 00 36 00 00 00 37 00 00 00 38 00 00 00
39 00 00 00 3A 00 00 00 3B 00 00 00 3C 00 00 00
3D 00 00 00 3E 00 00 00 3F 00 00 00 40 00 00 00
41 00 00 00 42 00 00 00 43 00 00 00 44 00 00 00
45 00 00 00 46 00 00 00 47 00 00 00 48 00 00 00
49 00 00 00 4A 00 00 00 4B 00 00 00 4C 00 00 00
4D 00 00 00 4E 00 00 00 4F 00 00 00 50 00 00 00
51 00 00 00 52 00 00 00 53 00 00 00 54 00 00 00
55 00 00 00 56 00 00 00 57 00 00 00 58 00 00 00
59 00 00 00 5A 00 00 00 5B 00 00 00 5C 00 00 00
5D 00 00 00 5E 00 00 00 5F 00 00 00 60 00 00 00
61 00 00 00 62 00 00 00 63 00 00 00 64 00 00 00
65 00 00 00 66 00 00 00 67 00 00 00 68 00 00 00
69 00 00 00 6A 00 00 00 6B 00 00 00 6C 00 00 00
6D 00 00 00 6E 00 00 00 6F 00 00 00 70 00 00 00
71 00 00 00 72 00 00 00 73 00 00 00 74 00 00 00
75 00 00 00 76 00 00 00 77 00 00 00 78 00 00 00
79 00 00 00 7A 00 00 00 7B 00 00 00 7C 00 00 00
7D 00 00 00 7E 00 00 00 7F 00 00 00 80 00 00 00
状态=0
Init B card,wiat...状态=0
Init OK!
SD卡版本=0
卡容量=1984000扇区 = 1015808000字节
CRC is OK!
StartSector = 0
CRC is OK!
BytesPerSec=512
SecPerClus=8
ReservedSectorsNum=36
NumFATs=2
Found FAT32
RootEntCnt=0
TotSec32=1984000 * 512=1015808000字节
FATSz32=1934
RootStartCluster=2
FatStartSector=36
FirstDataSector=3904
TotCluster=247512 *SecPerClus=1980096扇区
状态=0
CRC is OK!
FAT表:
F8 FF FF 0F FF FF FF FF FF FF FF 0F FF FF FF FF
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00


 

FPGA发送命令的VHDL代码:

library IEEE;
use IEEE.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use WORK.pck_CRC7.all;


entity sendcmd is
port
(
DB : inout std_logic_vector(7 downto 0);
ADDR: in std_logic_vector(6 downto 0);
WR : in std_logic;
RD : in std_logic;

--BASE_ADDR: in std_logic_vector(6 downto 0);
CLK_IN: in std_logic;

--DATA: in std_logic_vector( 39 downto 0 );
FINISH_OUT: out std_logic;
CLK_OUT: out std_logic;
Q: out std_logic
);
end sendcmd;

architecture arch of sendcmd is

constant BASE_ADDR : std_logic_vector(6 downto 0) := "0010000";

type SC_STAT is
(
SC_IDLE,
SC_SEMDDATA,
SC_SENDCRC,
SC_FINISH
);

signal stat: SC_STAT;


signal SEND_IN: std_logic;
signal crc : std_logic_vector(6 downto 0);
signal count : integer range 0 to 50;
signal finish : std_logic;
signal send : std_logic;
signal start : std_logic;
signal cmd : std_logic_vector(39 downto 0);
begin

--===========================================================
process(CLK_IN)
begin
if CLK_IN'event and CLK_IN = '1' then
send <= SEND_IN;
end if;
end process;
--===========================================================
process(WR,ADDR)
begin
if ADDR = (BASE_ADDR + 6) then
if rising_edge(WR) then
SEND_IN <= DB(0);
end if;
end if;
end process;
--===========================================================
process(RD,ADDR)
begin
if RD = '0' and ADDR = (BASE_ADDR + 5) then
DB <= "0000000" & finish;
else
DB <= "ZZZZZZZZ";
end if;
end process;
--===========================================================
process(CLK_IN,send)
begin
if send = '0' then
count <= 0;
crc <= "0000000";
finish <= '0';
q <= '1';
stat <= SC_IDLE;

if ADDR = (BASE_ADDR + 0) then
if WR = '0' and WR'event then
cmd(39 downto 32) <= DB or "01000000";
end if;
end if;

if ADDR = (BASE_ADDR + 1) then
if WR = '0' and WR'event then
cmd(31 downto 24) <= DB;
end if;
end if;

if ADDR = (BASE_ADDR + 2) then
if WR = '0' and WR'event then
cmd(23 downto 16) <= DB;
end if;
end if;

if ADDR = (BASE_ADDR + 3) then
if WR = '0' and WR'event then
cmd(15 downto 8) <= DB;
end if;
end if;

if ADDR = (BASE_ADDR + 4) then
if WR = '0' and WR'event then
cmd(7 downto 0) <= DB;
end if;
end if;

elsif CLK_IN'event and CLK_IN = '0' then

case stat is
when SC_IDLE =>
stat <= SC_SEMDDATA;
when SC_SEMDDATA =>
count <= count + 1;
q <= cmd(39);
crc <= nextCRC7(cmd(39), crc);
for i in 1 to 39 loop
cmd(i) <= cmd(i - 1);
end loop;

if count = 39 then
stat <= SC_SENDCRC;
end if;
when SC_SENDCRC =>
count <= count + 1;
q <= crc(6);
for i in 1 to 6 loop
crc(i) <= crc(i - 1);
end loop;
crc(0) <= '1';
if count = 47 then
stat <= SC_FINISH;
q <= '1';
finish <= '1';
end if;
when others => null;
end case;
end if;
end process;
--===========================================================
process(CLK_IN,send)
begin
if send = '0' or finish = '1' or CLK_IN = '1' then
CLK_OUT <= '1';
else
CLK_OUT <= '0';
end if;
end process;
--===========================================================

FINISH_OUT <= finish;
--===========================================================
end arch;


FPGA顶层电路图:

 

第一版PCB:

 

 

 

关键词: FPGA读写SD卡  4线SD模式  SD卡读写