SDH C CARD - Инициализация - PullRequest
       50

SDH C CARD - Инициализация

0 голосов
/ 01 апреля 2020

В последнее время я пытаюсь инициализировать мою SDH c карту с моей FPGA (DE1 - altera), используя VHDL

И я видел много последовательности, в которой люди Рекомендуем, например: CM0, CMD8, CMD55, ACMD41 на этой странице или CMD0, CMD8, CMD55, CMD1 На этой странице или на этой странице и еще несколько .

Возвращаясь к делу, проблема в ACMD41, который возвращает 0x01 вместо 0x00, почему?

И какова правильная последовательность для моей моей SDH c карты .

В дополнение к этому я увидел, что должен получить ответ R7 (0x01, 0x00, 0x00, 0x01 и 0xAA) от CMD8 на этой странице и я получаю его, но я должен читать всю эту последовательность или ее окей, чтобы прочитать первый байт, а затем отправить следующую команду?

ТАКЖЕ, я попытался проверить свой код на modelsim, и все ясно.

частота, которую я использую для инициализации, составляет 312,5 кГц, используя системные часы 50 МГц.

1026 * Это мой код - я использую Dig Связь ikey SPI
---------------------------------------------- NOTE ---------------------------------------------------------------
--slave_s IS REPLACING ss_n TO HAVE CONTROL ON THE SLAVE CHOICE,
--INSTEAD OF STOPPING COMMUNICATION TO SET CS back to HIGH and then LOW
library ieee;
use ieee.std_logic_1164.all;

entity sdcard_init is
    port(
        clk, rst : in std_logic; -- 50M[Hz]
        sclk     : buffer std_logic; -- SHOULD BE ATLEAST 100KHZ - 400KHZ, 400khz is preferred
        miso     : in std_logic;
        mosi     : out std_logic;
        ss_n     : buffer std_logic_vector(0 downto 0);
        slave_s  : out std_logic:='1';
        busy_o   : out std_logic;
        r_leds   : out std_logic_vector(7 downto 0):=(others => '0');
        g_leds   : out std_logic_vector(7 downto 0):=(others => '0')
        );

    attribute chip_pin : string;
    attribute chip_pin of clk       : signal is "L1"; -- 50 Mhz
    attribute chip_pin of rst       : signal is "P18"; -- push button
    attribute chip_pin of sclk      : signal is "G20";
    attribute chip_pin of miso      : signal is "E18";
    attribute chip_pin of mosi      : signal is "E19";
    attribute chip_pin of slave_s   : signal is "G18";
    attribute chip_pin of r_leds    : signal is "R17,R18,U18,Y18,V19,T18,Y19,U19";
    attribute chip_pin of g_leds    : signal is "Y21,Y22,W21,W22,V21,V22,U21,U22";
end entity;

architecture arch of sdcard_init is
    ----------- connects to SPI_MASTER -----------
    signal enable_com : std_logic:='0';
    constant cpol_o : std_logic:='0';
    constant cpha_o : std_logic:='0';
    signal cont_mode : std_logic:='0';
    signal addr_slave : integer;
    signal tx_data_w : std_logic_vector(7 downto 0);
    signal spi_rx_data : std_logic_vector(7 downto 0);
    signal busy_in : std_logic;
    ----------- connects to SPI_MASTER -----------

    type state_type is (delay, comm ,power_up, spare_cycle1, send_CMD0, check_CMD0, spare_cycle2,
                        send_CMD8, check_CMD8, spare_cycle3, send_CMD55, check_CMD55, spare_cycle4,
                        send_ACMD41, check_ACMD41, init_done);
    signal state_init : state_type:=delay;
    signal check_TRUE : std_logic:='0';
    constant freq     : integer:= 50; -- system clock
    constant clk_div  : integer:= 80;
begin
    spimaster: entity work.spi_master
        generic map(slaves => 1, d_width => 8)
        port map(
                clock => clk, reset_p => rst, enable => enable_com, cpol => cpol_o, cpha => cpha_o,
                cont => cont_mode, clk_div => clk_div, addr => addr_slave, tx_data => tx_data_w, miso => miso, 
                sclk => sclk, ss_n => ss_n, mosi => mosi, busy => busy_in, rx_data => spi_rx_data
                );
    process(clk,rst)
        variable count : integer range 0 to 50e6:=0;
        -- THIS PROCEDURE SHOULD SEND BEFORE EACH COMMAND(cmd)
        procedure spare_cycle(next_state : state_type) is
        begin
            count := count + 1;
            if(count < 16 * clk_div) then -- send dummy byte
                tx_data_w <= x"FF";
            elsif(count < 31 * clk_div) then -- send dummy byte
                tx_data_w <= x"FF";
                slave_s <= '1';
            elsif(count < 48 * clk_div) then -- send dummy byte
                tx_data_w <= x"FF";
                slave_s <= '0';
            else
                count := 0;
                state_init <= next_state;
            end if;
        end procedure;
    begin
        if(rst = '1') then
            tx_data_w <= (others => '0'); -- clear output line, data from MASTER
            g_leds <= (others => '0'); -- clear output line
            r_leds <= (others => '0'); -- clear output line
            enable_com <= '0'; -- DISABLE SPI COMMUNICATION
            cont_mode <= '0'; -- deactive continous mode
            slave_s <= '1'; -- NOT ACTIVE
            check_TRUE <= '0'; -- clear output line
            state_init <= delay; -- default state
            count := 0;
        elsif rising_edge(clk) then
            ------------------------------------------- INIT -------------------------------------------
            ------------------------------------------ BEGIN -------------------------------------------
            case state_init is
                when delay => -- wait 1ms until VDD will rise
                    if(count < freq * 1000) then
                        count := count + 1;
                    else
                        count := 0;
                        state_init <= comm;
                    end if;
                when comm => -- set prope settings to start SPI COMMUNICATION
                    addr_slave <= 0; -- choosing slave 0(signal - slave_s is replacing this command)
                    cont_mode <= '1'; -- active continous mode transaction
                    slave_s <= '1'; -- NOT ACTIVE
                    state_init <= power_up;
                when power_up =>
                    enable_com <= '1'; -- enable SPI COMMUNICATION
                    if(count < 159 * clk_div) then -- send 80 dummy clocks
                        count := count + 1;
                        tx_data_w <= x"FF";
                    else
                        count := 0;
                        state_init <= spare_cycle1;
                    end if;
                when spare_cycle1 =>
                    spare_cycle(send_CMD0);
                when send_CMD0 =>
                    count := count + 1;
                    if(count < 16 * clk_div) then -- send byte 0x40
                        tx_data_w <= x"40";
                    elsif(count < 80 * clk_div) then -- send 4 bytes 0x00
                        tx_data_w <= x"00";
                    elsif(count < 96 * clk_div) then -- send CRC byte 0x95
                        tx_data_w <= x"95";
                    else
                        count := 0;
                        tx_data_w <= x"FF"; -- send dummy byte
                        state_init <= check_CMD0;
                    end if;
                when check_CMD0 =>
                    if(count < 160 * clk_div) then -- check for 10 times if sd card response (R1 = 0x01)
                        count := count + 1;
                        tx_data_w <= x"FF"; -- send dummy byte
                        if(spi_rx_data = x"01") then
                            count := 0;
                            state_init <= spare_cycle2;
                        end if;
                    else
                       count := 0;
                       state_init <= spare_cycle1;
                    end if;
                when spare_cycle2 => -- send twice x"FF", twice with slave = '0' and once with slave = '1'
                    spare_cycle(send_CMD8);
                when send_CMD8 =>
                    count := count + 1;
                    if(count < 16 * clk_div) then -- send 1 byte 0x40
                        tx_data_w <= x"48";
                    elsif(count < 48 * clk_div) then -- send 2 bytes 0x00
                        tx_data_w <= x"00";
                    elsif(count < 64 * clk_div) then -- send 1 byte 0x01
                        tx_data_w <= x"01";
                    elsif(count < 80 * clk_div) then -- send 1 byte 0xAA
                        tx_data_w <= x"AA";
                    elsif(count < 96 * clk_div) then -- send CRC byte 0x87 
                        tx_data_w <= x"87";
                    else
                        count := 0;
                        tx_data_w <= x"FF"; -- send dummy byte
                        state_init <= check_CMD8;
                    end if;
                when check_CMD8 =>
                    if(count < 160 * clk_div) then -- check for 10 times if sd card response (R1 = 0x01)
                        count := count + 1;
                        tx_data_w <= x"FF"; -- send dummy byte
                        if(spi_rx_data = x"01") then
                            count := 0;
                            state_init <= spare_cycle3;
                        end if;
                    else
                        count := 0;
                        state_init <= spare_cycle2;--send_CMD8;
                    end if;
                when spare_cycle3 => -- send twice x"FF", twice with slave = '0' and once with slave = '1'
                    spare_cycle(send_CMD55);
                when send_CMD55 => -- tells to sd that we are going to send speacial(ACMD41)
                    count := count + 1;
                    if(count < 16 * clk_div) then -- send 1 byte 0x77
                        tx_data_w <= x"77";
                    elsif(count < 80 * clk_div) then -- send 4 bytes 0x00
                        tx_data_w <= x"00";
                    elsif(count < 96 * clk_div) then -- send CRC byte 0x65(ANY)
                        tx_data_w <= x"65";
                    else
                        count := 0;
                        tx_data_w <= x"FF"; -- send dummy byte
                        state_init <= check_CMD55;
                    end if;
                when check_CMD55 =>
                    if(count < 160 * clk_div) then -- check for 10 times if sd card response (R1 = 0x01/R1 = 0x00 when ACMD41)
                        count := count + 1;
                        tx_data_w <= x"FF"; -- send dummy byte
                        if(spi_rx_data = x"01") then
                            count := 0;
                            state_init <= spare_cycle4;
                        elsif(spi_rx_data = x"00" and check_TRUE = '1') then
                            count := 0;
                            check_TRUE <= '0';
                            state_init <= init_done;
                        end if;
                    else
                        count := 0;
                        state_init <= spare_cycle3;--send_CMD55;
                    end if;
                when spare_cycle4 => -- send twice x"FF", twice with slave = '0' and once with slave = '1'
                    spare_cycle(send_ACMD41);
                when send_ACMD41 =>
                    count := count + 1;
                    if(count < 16 * clk_div) then -- send 1 byte 0x69
                        tx_data_w <= x"69";
                    elsif(count < 31 * clk_div) then -- send 1 byte 0x00
                        tx_data_w <= x"00";
                    elsif(count < 48 * clk_div) then -- send 1 byte 0x10
                        tx_data_w <= x"10";
                    elsif(count < 80 * clk_div) then -- send 2 bytes 0x00
                        tx_data_w <= x"00";
                    elsif(count < 96 * clk_div) then -- send CRC byte 0x5F
                        tx_data_w <= x"77";--x"5F";--x"CD"
                    else
                        count := 0;
                        tx_data_w <= x"FF"; -- send dummy byte
                        state_init <= check_ACMD41;
                    end if;
                when check_ACMD41 =>
                    if(count < 160 * clk_div) then -- check for 10 times if sd card response (R1 = 0x00)
                        count := count + 1;
                        tx_data_w <= x"FF"; -- send dummy byte
                        if(spi_rx_data = x"00") then
                            count := 0;
                            state_init <= init_done;
                            g_leds(6) <= '1';
                        END IF;
                    else
                        count := 0;
                        check_TRUE <= '1';
                        state_init <= spare_cycle3;--send_ACMD41;
                    end if;
                when init_done => -- done to initialize sd card
                    g_leds <= "10101010"; -- set led's as proper to know when initialize is done
                when others =>
                    null;
            end case;
            ------------------------------------------- DONE -------------------------------------------
            ------------------------------------------- INIT -------------------------------------------

            if((spi_rx_data = x"00") and (state_init = check_ACMD41)) then -- led check
                r_leds <= (others => '1');
            end if;
        end if;
    end process;
    busy_o <= busy_in;
end architecture;

DIGIKEY SPI CODE:

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
USE ieee.std_logic_unsigned.all;

ENTITY spi_master IS
  GENERIC(
    slaves  : INTEGER := 4;  --number of spi slaves
    d_width : INTEGER := 2); --data bus width
  PORT(
    clock   : IN     STD_LOGIC;                             --system clock
    reset_p : IN     STD_LOGIC;                             --asynchronous reset
    enable  : IN     STD_LOGIC;                             --initiate transaction
    cpol    : IN     STD_LOGIC;                             --spi clock polarity
    cpha    : IN     STD_LOGIC;                             --spi clock phase
    cont    : IN     STD_LOGIC;                             --continuous mode command
    clk_div : IN     INTEGER;                               --system clock cycles per 1/2 period of sclk
    addr    : IN     INTEGER;                               --address of slave
    tx_data : IN     STD_LOGIC_VECTOR(d_width-1 DOWNTO 0);  --data to transmit
    miso    : IN     STD_LOGIC;                             --master in, slave out
    sclk    : BUFFER STD_LOGIC;                             --spi clock
    ss_n    : BUFFER STD_LOGIC_VECTOR(slaves-1 DOWNTO 0);   --slave select
    mosi    : OUT    STD_LOGIC;                             --master out, slave in
    busy    : OUT    STD_LOGIC;                             --busy / data ready signal
    rx_data : OUT    STD_LOGIC_VECTOR(d_width-1 DOWNTO 0)); --data received
END spi_master;

ARCHITECTURE logic OF spi_master IS
  TYPE machine IS(ready, execute);                           --state machine data type
  SIGNAL state       : machine;                              --current state
  SIGNAL slave       : INTEGER;                              --slave selected for current transaction
  SIGNAL clk_ratio   : INTEGER;                              --current clk_div
  SIGNAL count       : INTEGER;                              --counter to trigger sclk from system clock
  SIGNAL clk_toggles : INTEGER RANGE 0 TO d_width*2 + 1;     --count spi clock toggles
  SIGNAL assert_data : STD_LOGIC;                            --'1' is tx sclk toggle, '0' is rx sclk toggle
  SIGNAL continue    : STD_LOGIC;                            --flag to continue transaction
  SIGNAL rx_buffer   : STD_LOGIC_VECTOR(d_width-1 DOWNTO 0); --receive data buffer
  SIGNAL tx_buffer   : STD_LOGIC_VECTOR(d_width-1 DOWNTO 0); --transmit data buffer
  SIGNAL last_bit_rx : INTEGER RANGE 0 TO d_width*2;         --last rx data bit location
BEGIN
  PROCESS(clock, reset_p)
  BEGIN

    IF(reset_p = '1') THEN        --reset system
      busy <= '1';                --set busy signal
      ss_n <= (OTHERS => '1');    --deassert all slave select lines
      mosi <= 'Z';                --set master out to high impedance
      rx_data <= (OTHERS => '0'); --clear receive data port
      state <= ready;             --go to ready state when reset is exited

    ELSIF(clock'EVENT AND clock = '1') THEN
      CASE state IS               --state machine

        WHEN ready =>
          busy <= '0';             --clock out not busy signal
          ss_n <= (OTHERS => '1'); --set all slave select outputs high
          mosi <= 'Z';             --set mosi output high impedance
          continue <= '0';         --clear continue flag

          --user input to initiate transaction
          IF(enable = '1') THEN       
            busy <= '1';             --set busy signal
            IF(addr < slaves) THEN   --check for valid slave address
              slave <= addr;         --clock in current slave selection if valid
            ELSE
              slave <= 0;            --set to first slave if not valid
            END IF;
            IF(clk_div = 0) THEN     --check for valid spi speed
              clk_ratio <= 1;        --set to maximum speed if zero
              count <= 1;            --initiate system-to-spi clock counter
            ELSE
              clk_ratio <= clk_div;  --set to input selection if valid
              count <= clk_div;      --initiate system-to-spi clock counter
            END IF;
            sclk <= cpol;            --set spi clock polarity
            assert_data <= NOT cpha; --set spi clock phase
            tx_buffer <= tx_data;    --clock in data for transmit into buffer
            clk_toggles <= 0;        --initiate clock toggle counter
            last_bit_rx <= d_width*2 + conv_integer(cpha) - 1; --set last rx data bit
            state <= execute;        --proceed to execute state
          ELSE
            state <= ready;          --remain in ready state
          END IF;

        WHEN execute =>
          busy <= '1';        --set busy signal
          ss_n(slave) <= '0'; --set proper slave select output

          --system clock to sclk ratio is met
          IF(count = clk_ratio) THEN        
            count <= 1;                     --reset system-to-spi clock counter
            assert_data <= NOT assert_data; --switch transmit/receive indicator
            IF(clk_toggles = d_width*2 + 1) THEN
              clk_toggles <= 0;               --reset spi clock toggles counter
            ELSE
              clk_toggles <= clk_toggles + 1; --increment spi clock toggles counter
            END IF;

            --spi clock toggle needed
            IF(clk_toggles <= d_width*2 AND ss_n(slave) = '0') THEN 
              sclk <= NOT sclk; --toggle spi clock
            END IF;

            --receive spi clock toggle
            IF(assert_data = '0' AND clk_toggles < last_bit_rx + 1 AND ss_n(slave) = '0') THEN 
              rx_buffer <= rx_buffer(d_width-2 DOWNTO 0) & miso; --shift in received bit
            END IF;

            --transmit spi clock toggle
            IF(assert_data = '1' AND clk_toggles < last_bit_rx) THEN 
              mosi <= tx_buffer(d_width-1);                     --clock out data bit
              tx_buffer <= tx_buffer(d_width-2 DOWNTO 0) & '0'; --shift data transmit buffer
            END IF;

            --last data receive, but continue
            IF(clk_toggles = last_bit_rx AND cont = '1') THEN 
              tx_buffer <= tx_data;                       --reload transmit buffer
              clk_toggles <= last_bit_rx - d_width*2 + 1; --reset spi clock toggle counter
              continue <= '1';                            --set continue flag
            END IF;

            --normal end of transaction, but continue
            IF(continue = '1') THEN  
              continue <= '0';      --clear continue flag
              busy <= '0';          --clock out signal that first receive data is ready
              rx_data <= rx_buffer; --clock out received data to output port    
            END IF;

            --end of transaction
            IF((clk_toggles = d_width*2 + 1) AND cont = '0') THEN   
              busy <= '0';             --clock out not busy signal
              ss_n <= (OTHERS => '1'); --set all slave selects high
              mosi <= 'Z';             --set mosi output high impedance
              rx_data <= rx_buffer;    --clock out received data to output port
              state <= ready;          --return to ready state
            ELSE                       --not end of transaction
              state <= execute;        --remain in execute state
            END IF;

          ELSE        --system clock to sclk ratio not met
            count <= count + 1; --increment counter
            state <= execute;   --remain in execute state
          END IF;

      END CASE;
    END IF;
  END PROCESS; 
END logic;
...