打印

GSM给您一个能用SPI模式的SD读卡程序(VHDL)

[复制链接]
3050|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
GoldSunMonkey|  楼主 | 2012-8-21 22:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
经测试能用,只是SPI的方式, 供大家使用。
sd.rar (1.92 KB)

-- VHDL SD card interface
-- by Steven J. Merrifield, June 2008

-- Reads and writes a single block of data, and also writes continuous data
-- Tested on Xilinx Spartan 3 hardware, using Transcend and SanDisk Ultra II cards
-- Read states are derived from the Apple II emulator by Stephen Edwards

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity sd_controller is
port (
        cs : out std_logic;
        mosi : out std_logic;
        miso : in std_logic;
        sclk : out std_logic;

        rd : in std_logic;
        wr : in std_logic;
        dm_in : in std_logic;        -- data mode, 0 = write continuously, 1 = write single block
        reset : in std_logic;
        din : in std_logic_vector(7 downto 0);
        dout : out std_logic_vector(7 downto 0);
        clk : in std_logic        -- twice the SPI clk
);

end sd_controller;

architecture rtl of sd_controller is
type states is (
        RST,
        INIT,
        CMD0,
        CMD55,
        CMD41,
        POLL_CMD,
  
        IDLE,        -- wait for read or write pulse
        READ_BLOCK,
        READ_BLOCK_WAIT,
        READ_BLOCK_DATA,
        READ_BLOCK_CRC,
        SEND_CMD,
        RECEIVE_BYTE_WAIT,
        RECEIVE_BYTE,
        WRITE_BLOCK_CMD,
        WRITE_BLOCK_INIT,                -- initialise write command
        WRITE_BLOCK_DATA,                -- loop through all data bytes
        WRITE_BLOCK_BYTE,                -- send one byte
        WRITE_BLOCK_WAIT                -- wait until not busy
);


-- one start byte, plus 512 bytes of data, plus two FF end bytes (CRC)
constant WRITE_DATA_SIZE : integer := 515;


signal state, return_state : states;
signal sclk_sig : std_logic := '0';
signal cmd_out : std_logic_vector(55 downto 0);
signal recv_data : std_logic_vector(7 downto 0);
signal address : std_logic_vector(31 downto 0);
signal cmd_mode : std_logic := '1';
signal data_mode : std_logic := '1';
signal response_mode : std_logic := '1';
signal data_sig : std_logic_vector(7 downto 0) := x"00";

begin
  
        process(clk,reset)
                variable byte_counter : integer range 0 to WRITE_DATA_SIZE;
                variable bit_counter : integer range 0 to 160;
        begin
                data_mode <= dm_in;

                if rising_edge(clk) then
                        if (reset='1') then
                                state <= RST;
                                sclk_sig <= '0';
                        else
                                case state is
                               
                                when RST =>
                                        sclk_sig <= '0';
                                        cmd_out <= (others => '1');
                                        address <= x"00000000";
                                        byte_counter := 0;
                                        cmd_mode <= '1'; -- 0=data, 1=command
                                        response_mode <= '1';        -- 0=data, 1=command
                                        bit_counter := 160;
                                        cs <= '1';
                                        state <= INIT;
                               
                                when INIT =>                -- CS=1, send 80 clocks, CS=0
                                        if (bit_counter = 0) then
                                                cs <= '0';
                                                state <= CMD0;
                                        else
                                                bit_counter := bit_counter - 1;
                                                sclk_sig <= not sclk_sig;
                                        end if;       
                               
                                when CMD0 =>
                                        cmd_out <= x"FF400000000095";
                                        bit_counter := 55;
                                        return_state <= CMD55;
                                        state <= SEND_CMD;

                                when CMD55 =>
                                        cmd_out <= x"FF770000000001";        -- 55d OR 40h = 77h
                                        bit_counter := 55;
                                        return_state <= CMD41;
                                        state <= SEND_CMD;
                               
                                when CMD41 =>
                                        cmd_out <= x"FF690000000001";        -- 41d OR 40h = 69h
                                        bit_counter := 55;
                                        return_state <= POLL_CMD;
                                        state <= SEND_CMD;
                       
                                when POLL_CMD =>
                                        if (recv_data(0) = '0') then
                                                state <= IDLE;
                                        else
                                                state <= CMD55;
                                        end if;
               
                                when IDLE =>
                                        if (rd = '1') then
                                                state <= READ_BLOCK;
                                        elsif (wr='1') then
                                                state <= WRITE_BLOCK_CMD;
                                        else
                                                state <= IDLE;
                                        end if;
                               
                                when READ_BLOCK =>
                                        cmd_out <= x"FF" & x"51" & address & x"FF";
                                        bit_counter := 55;
                                        return_state <= READ_BLOCK_WAIT;
                                        state <= SEND_CMD;
                               
                                when READ_BLOCK_WAIT =>
                                        if (sclk_sig='1' and miso='0') then
                                                state <= READ_BLOCK_DATA;
                                                byte_counter := 511;
                                                bit_counter := 7;
                                                return_state <= READ_BLOCK_DATA;
                                                state <= RECEIVE_BYTE;
                                        end if;
                                        sclk_sig <= not sclk_sig;

                                when READ_BLOCK_DATA =>
                                        if (byte_counter = 0) then
                                                bit_counter := 7;
                                                return_state <= READ_BLOCK_CRC;
                                                state <= RECEIVE_BYTE;
                                        else
                                                byte_counter := byte_counter - 1;
                                                return_state <= READ_BLOCK_DATA;
                                                bit_counter := 7;
                                                state <= RECEIVE_BYTE;
                                        end if;
                       
                                when READ_BLOCK_CRC =>
                                        bit_counter := 7;
                                        return_state <= IDLE;
                                        address <= std_logic_vector(unsigned(address) + x"200");
                                        state <= RECEIVE_BYTE;
               
                                when SEND_CMD =>
                                        if (sclk_sig = '1') then
                                                if (bit_counter = 0) then
                                                        state <= RECEIVE_BYTE_WAIT;
                                                else
                                                        bit_counter := bit_counter - 1;
                                                        cmd_out <= cmd_out(54 downto 0) & '1';
                                                end if;
                                        end if;
                                        sclk_sig <= not sclk_sig;
                               
                                when RECEIVE_BYTE_WAIT =>
                                        if (sclk_sig = '1') then
                                                if (miso = '0') then
                                                        recv_data <= (others => '0');
                                                        if (response_mode='0') then
                                                                bit_counter := 3; -- already read bits 7..4
                                                        else
                                                                bit_counter := 6; -- already read bit 7
                                                        end if;
                                                        state <= RECEIVE_BYTE;
                                                end if;
                                        end if;
                                        sclk_sig <= not sclk_sig;

                                when RECEIVE_BYTE =>
                                        if (sclk_sig = '1') then
                                                recv_data <= recv_data(6 downto 0) & miso;
                                                if (bit_counter = 0) then
                                                        state <= return_state;
                                                        dout <= recv_data(6 downto 0) & miso;
                                                else
                                                        bit_counter := bit_counter - 1;
                                                end if;
                                        end if;
                                        sclk_sig <= not sclk_sig;

                                when WRITE_BLOCK_CMD =>
                                        cmd_mode <= '1';
                                        if (data_mode = '0') then
                                                cmd_out <= x"FF" & x"59" & address & x"FF";        -- continuous
                                        else
                                                cmd_out <= x"FF" & x"58" & address & x"FF";        -- single block
                                        end if;
                                        bit_counter := 55;
                                        return_state <= WRITE_BLOCK_INIT;
                                        state <= SEND_CMD;
                                       
                                when WRITE_BLOCK_INIT =>
                                        cmd_mode <= '0';
                                        byte_counter := WRITE_DATA_SIZE;
                                        state <= WRITE_BLOCK_DATA;
                                       
                                when WRITE_BLOCK_DATA =>
                                        if byte_counter = 0 then
                                                state <= RECEIVE_BYTE_WAIT;
                                                return_state <= WRITE_BLOCK_WAIT;
                                                response_mode <= '0';
                                        else        
                                                if ((byte_counter = 2) or (byte_counter = 1)) then
                                                        data_sig <= x"FF"; -- two CRC bytes
                                                elsif byte_counter = WRITE_DATA_SIZE then
                                                        if (data_mode='0') then
                                                                data_sig <= x"FC"; -- start byte, multiple blocks
                                                        else
                                                                data_sig <= x"FE"; -- start byte, single block
                                                        end if;
                                                else
                                                        -- just a counter, get real data here
                                                        data_sig <= std_logic_vector(to_unsigned(byte_counter,8));
                                                end if;
                                                bit_counter := 7;
                                                state <= WRITE_BLOCK_BYTE;
                                                byte_counter := byte_counter - 1;
                                        end if;
                               
                                when WRITE_BLOCK_BYTE =>
                                        if (sclk_sig = '1') then
                                                if bit_counter=0 then
                                                        state <= WRITE_BLOCK_DATA;
                                                else
                                                        data_sig <= data_sig(6 downto 0) & '1';
                                                        bit_counter := bit_counter - 1;
                                                end if;
                                        end if;
                                        sclk_sig <= not sclk_sig;
                                       
                                when WRITE_BLOCK_WAIT =>
                                        response_mode <= '1';
                                        if sclk_sig='1' then
                                                if MISO='1' then
                                                        if (data_mode='0') then
                                                                state <= WRITE_BLOCK_INIT;
                                                        else
                                                                address <= std_logic_vector(unsigned(address) + x"200");
                                                                state <= IDLE;
                                                        end if;
                                                end if;
                                        end if;
                                        sclk_sig <= not sclk_sig;

                                when others => state <= IDLE;
        end case;
      end if;
    end if;
  end process;

  sclk <= sclk_sig;
  mosi <= cmd_out(55) when cmd_mode='1' else data_sig(7);
  
end rtl;
评分
参与人数 2威望 +6 收起 理由
星星之火红 + 5
shang651 + 1

相关帖子

沙发
jakfens| | 2012-8-22 08:49 | 只看该作者
:lol能翻译为verilog么

使用特权

评论回复
板凳
jialio| | 2012-8-22 16:30 | 只看该作者
附件里面和这贴的是一样吗 hoho 就问问哈MRO

使用特权

评论回复
地板
GoldSunMonkey|  楼主 | 2012-8-22 17:48 | 只看该作者
附件里面和这贴的是一样吗 hoho 就问问哈MRO
jialio 发表于 2012-8-22 16:30
一样的。

使用特权

评论回复
5
GoldSunMonkey|  楼主 | 2012-8-22 17:48 | 只看该作者
:lol能翻译为verilog么
jakfens 发表于 2012-8-22 08:49
哈哈,你翻译。我顶你的肺

使用特权

评论回复
评分
参与人数 1威望 +5 收起 理由
星星之火红 + 5
6
jakfens| | 2012-8-23 08:45 | 只看该作者
哈哈,你翻译。我顶你的肺
GoldSunMonkey 发表于 2012-8-22 17:48
:funk:

使用特权

评论回复
7
GoldSunMonkey|  楼主 | 2012-8-23 10:05 | 只看该作者
:lol

使用特权

评论回复
8
千山万水js| | 2013-4-1 15:38 | 只看该作者
前段时间一直在做这个,最后用MB控制器做的。

使用特权

评论回复
9
ifpga| | 2013-4-1 15:41 | 只看该作者
收下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:                     2014, 追逐梦想

264

主题

17215

帖子

523

粉丝