В последнее время я пытаюсь инициализировать мою 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;