ossc/ip/altera_up_sd_card_avalon_in.../hdl/Altera_UP_SD_Card_Control_F...

348 lines
13 KiB
VHDL

-- (C) 2001-2015 Altera Corporation. All rights reserved.
-- Your use of Altera Corporation's design tools, logic functions and other
-- software and tools, and its AMPP partner logic functions, and any output
-- files any of the foregoing (including device programming or simulation
-- files), and any associated documentation or information are expressly subject
-- to the terms and conditions of the Altera Program License Subscription
-- Agreement, Altera MegaCore Function License Agreement, or other applicable
-- license agreement, including, without limitation, that your use is for the
-- sole purpose of programming logic devices manufactured by Altera and sold by
-- Altera or its authorized distributors. Please refer to the applicable
-- agreement for further details.
----------------------------------------------------------------------------------------------------------------
-- This is an FSM that controls the SD Card interface circuitry.
--
-- On reset, the FSM will initiate a predefined set of commands in an attempt to connect to the SD Card.
-- When successful, it will allow commands to be issued to the SD Card, otherwise it will return a signal that
-- no card is present in the SD Card slot.
--
-- NOTES/REVISIONS:
----------------------------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity Altera_UP_SD_Card_Control_FSM is
generic (
PREDEFINED_COMMAND_GET_STATUS : STD_LOGIC_VECTOR(3 downto 0) := "1001"
);
port
(
-- Clock and Reset signals
i_clock : in STD_LOGIC;
i_reset_n : in STD_LOGIC;
-- FSM Inputs
i_user_command_ready : in std_logic;
i_response_received : in STD_LOGIC;
i_response_timed_out : in STD_LOGIC;
i_response_crc_passed : in STD_LOGIC;
i_command_sent : in STD_LOGIC;
i_powerup_busy_n : in STD_LOGIC;
i_clocking_pulse_enable : in std_logic;
i_current_clock_mode : in std_logic;
i_user_message_valid : in std_logic;
i_last_cmd_was_55 : in std_logic;
i_allow_partial_rw : in std_logic;
-- FSM Outputs
o_generate_command : out STD_LOGIC;
o_predefined_command_ID : out STD_LOGIC_VECTOR(3 downto 0);
o_receive_response : out STD_LOGIC;
o_drive_CMD_line : out STD_LOGIC;
o_SD_clock_mode : out STD_LOGIC; -- 0 means slow clock for card identification, 1 means fast clock for transfer mode.
o_resetting : out std_logic;
o_card_connected : out STD_LOGIC;
o_command_completed : out std_logic;
o_clear_response_register : out std_logic;
o_enable_clock_generator : out std_logic
);
end entity;
architecture rtl of Altera_UP_SD_Card_Control_FSM is
-- Build an enumerated type for the state machine. On reset always reset the DE2 and read the state
-- of the switches.
type state_type is (s_RESET, s_WAIT_74_CYCLES, s_GENERATE_PREDEFINED_COMMAND, s_WAIT_PREDEFINED_COMMAND_TRANSMITTED, s_WAIT_PREDEFINED_COMMAND_RESPONSE,
s_GO_TO_NEXT_COMMAND, s_TOGGLE_CLOCK_FREQUENCY, s_AWAIT_USER_COMMAND, s_REACTIVATE_CLOCK,
s_GENERATE_COMMAND, s_SEND_COMMAND, s_WAIT_RESPONSE, s_WAIT_FOR_CLOCK_EDGE_BEFORE_DISABLE, s_WAIT_DEASSERT,
s_PERIODIC_STATUS_CHECK);
-- Register to hold the current state
signal current_state : state_type;
signal next_state : state_type;
-------------------
-- Local signals
-------------------
-- REGISTERED
signal SD_clock_mode, waiting_for_vdd_setup : std_logic;
signal id_sequence_step_index : std_logic_vector(3 downto 0);
signal delay_counter : std_logic_vector(6 downto 0);
signal periodic_status_check : std_logic_vector(23 downto 0);
-- UNREGISTERED
begin
-- Define state transitions.
state_transitions: process (current_state, i_command_sent, i_response_received, id_sequence_step_index,
i_response_timed_out, i_response_crc_passed, delay_counter, waiting_for_vdd_setup,
i_user_command_ready, i_clocking_pulse_enable, i_current_clock_mode,
i_user_message_valid, i_last_cmd_was_55, periodic_status_check)
begin
case current_state is
when s_RESET =>
-- Reset local registers and begin identification process.
next_state <= s_WAIT_74_CYCLES;
when s_WAIT_74_CYCLES =>
-- Wait 74 cycles before the card can be sent commands to.
if (delay_counter = "1001010") then
next_state <= s_GENERATE_PREDEFINED_COMMAND;
else
next_state <= s_WAIT_74_CYCLES;
end if;
when s_GENERATE_PREDEFINED_COMMAND =>
-- Generate a predefined command to the SD card. This is the identification process for the SD card.
next_state <= s_WAIT_PREDEFINED_COMMAND_TRANSMITTED;
when s_WAIT_PREDEFINED_COMMAND_TRANSMITTED =>
-- Send a predefined command to the SD card. This is the identification process for the SD card.
if (i_command_sent = '1') then
next_state <= s_WAIT_PREDEFINED_COMMAND_RESPONSE;
else
next_state <= s_WAIT_PREDEFINED_COMMAND_TRANSMITTED;
end if;
when s_WAIT_PREDEFINED_COMMAND_RESPONSE =>
-- Wait for a response from SD card.
if (i_response_received = '1') then
if (i_response_timed_out = '1') then
if (waiting_for_vdd_setup = '1') then
next_state <= s_GO_TO_NEXT_COMMAND;
else
next_state <= s_RESET;
end if;
else
if (i_response_crc_passed = '0') then
next_state <= s_GENERATE_PREDEFINED_COMMAND;
else
next_state <= s_GO_TO_NEXT_COMMAND;
end if;
end if;
else
next_state <= s_WAIT_PREDEFINED_COMMAND_RESPONSE;
end if;
when s_GO_TO_NEXT_COMMAND =>
-- Process the next command in the ID sequence.
if (id_sequence_step_index = PREDEFINED_COMMAND_GET_STATUS) then
next_state <= s_TOGGLE_CLOCK_FREQUENCY;
else
next_state <= s_GENERATE_PREDEFINED_COMMAND;
end if;
when s_TOGGLE_CLOCK_FREQUENCY =>
-- Now that the card has been initialized, increase the SD card clock frequency to 25MHz.
-- Wait for the clock generator to switch operating mode before proceeding further.
if (i_current_clock_mode = '1') then
next_state <= s_AWAIT_USER_COMMAND;
else
next_state <= s_TOGGLE_CLOCK_FREQUENCY;
end if;
when s_AWAIT_USER_COMMAND =>
-- Wait for the user to send a command to the SD card
if (i_user_command_ready = '1') then
next_state <= s_REACTIVATE_CLOCK;
else
-- Every 5 million cycles, or 0.1 of a second.
if (periodic_status_check = "010011000100101101000000") then
next_state <= s_PERIODIC_STATUS_CHECK;
else
next_state <= s_AWAIT_USER_COMMAND;
end if;
end if;
when s_PERIODIC_STATUS_CHECK =>
-- Update status every now and then.
next_state <= s_GENERATE_PREDEFINED_COMMAND;
when s_REACTIVATE_CLOCK =>
-- Activate the clock signal and wait 8 clock cycles.
if (delay_counter = "0001000") then
next_state <= s_GENERATE_COMMAND;
else
next_state <= s_REACTIVATE_CLOCK;
end if;
when s_GENERATE_COMMAND =>
-- Generate user command. If valid, proceed further. Otherwise, indicate that the command is invalid.
if (i_user_message_valid = '0') then
next_state <= s_WAIT_DEASSERT;
else
next_state <= s_SEND_COMMAND;
end if;
when s_SEND_COMMAND =>
-- Wait for the command to be sent.
if (i_command_sent = '1') then
next_state <= s_WAIT_RESPONSE;
else
next_state <= s_SEND_COMMAND;
end if;
when s_WAIT_RESPONSE =>
-- Wait for the SD card to respond.
if (i_response_received = '1') then
if (i_response_timed_out = '1') then
next_state <= s_WAIT_DEASSERT;
else
next_state <= s_WAIT_FOR_CLOCK_EDGE_BEFORE_DISABLE;
end if;
else
next_state <= s_WAIT_RESPONSE;
end if;
when s_WAIT_FOR_CLOCK_EDGE_BEFORE_DISABLE =>
-- Wait for a positive clock edge before you disable the clock.
if (i_clocking_pulse_enable = '1') then
next_state <= s_WAIT_DEASSERT;
else
next_state <= s_WAIT_FOR_CLOCK_EDGE_BEFORE_DISABLE;
end if;
when s_WAIT_DEASSERT =>
-- wait for the user to release command generation request.
if (i_user_command_ready = '1') then
next_state <= s_WAIT_DEASSERT;
else
if (i_last_cmd_was_55 = '1') then
next_state <= s_AWAIT_USER_COMMAND;
else
-- Send a get status command to obtain the result of sending the last command.
next_state <= s_GENERATE_PREDEFINED_COMMAND;
end if;
end if;
when others =>
-- Make sure to start in the reset state if the circuit powers up in an odd state.
next_state <= s_RESET;
end case;
end process;
-- State registers.
state_registers: process (i_clock, i_reset_n)
begin
if (i_reset_n = '0') then
current_state <= s_RESET;
elsif (rising_edge(i_clock)) then
current_state <= next_state;
end if;
end process;
-- Local FFs:
local_ffs:process ( i_clock, i_reset_n, i_powerup_busy_n, current_state,
id_sequence_step_index, i_response_received, i_response_timed_out,
i_allow_partial_rw)
begin
if (i_reset_n = '0') then
SD_clock_mode <= '0';
id_sequence_step_index <= (OTHERS => '0');
periodic_status_check <= (OTHERS => '0');
waiting_for_vdd_setup <= '0';
elsif (rising_edge(i_clock)) then
-- Set SD clock mode to 0 initially, thereby using a clock with frequency between 100 kHz and 400 kHz as
-- per SD card specifications. When the card is initialized change the clock to run at 25 MHz.
if (current_state = s_WAIT_DEASSERT) then
periodic_status_check <= (OTHERS => '0');
elsif (current_state = s_AWAIT_USER_COMMAND) then
periodic_status_check <= periodic_status_check + '1';
end if;
if (current_state = s_RESET) then
SD_clock_mode <= '0';
elsif (current_state = s_TOGGLE_CLOCK_FREQUENCY) then
SD_clock_mode <= '1';
end if;
-- Update the ID sequence step as needed.
if (current_state = s_RESET) then
id_sequence_step_index <= (OTHERS => '0');
elsif (current_state = s_GO_TO_NEXT_COMMAND) then
if ((i_powerup_busy_n = '0') and (id_sequence_step_index = "0010")) then
id_sequence_step_index <= "0001";
else
if (id_sequence_step_index = "0110") then
if (i_allow_partial_rw = '0') then
-- If partial read-write not allowed, then skip SET_BLK_LEN command - it will fail.
id_sequence_step_index <= "1000";
else
id_sequence_step_index <= "0111";
end if;
else
id_sequence_step_index <= id_sequence_step_index + '1';
end if;
end if;
elsif (current_state = s_WAIT_DEASSERT) then
if (i_last_cmd_was_55 = '0') then
-- After each command execute a get status command.
id_sequence_step_index <= PREDEFINED_COMMAND_GET_STATUS;
end if;
elsif (current_state = s_PERIODIC_STATUS_CHECK) then
id_sequence_step_index <= PREDEFINED_COMMAND_GET_STATUS;
end if;
-- Do not reset the card when SD card is having its VDD set up. Wait for it to respond, this may take some time.
if (id_sequence_step_index = "0010") then
waiting_for_vdd_setup <= '1';
elsif ((id_sequence_step_index = "0011") or (current_state = s_RESET)) then
waiting_for_vdd_setup <= '0';
end if;
end if;
end process;
-- Counter that counts to 74 to delay any commands.
initial_delay_counter: process(i_clock, i_reset_n, i_clocking_pulse_enable )
begin
if (i_reset_n = '0') then
delay_counter <= (OTHERS => '0');
elsif (rising_edge(i_clock)) then
if ((current_state = s_RESET) or (current_state = s_AWAIT_USER_COMMAND))then
delay_counter <= (OTHERS => '0');
elsif (((current_state = s_WAIT_74_CYCLES) or (current_state = s_REACTIVATE_CLOCK)) and
(i_clocking_pulse_enable = '1')) then
delay_counter <= delay_counter + '1';
end if;
end if;
end process;
-- FSM outputs.
o_SD_clock_mode <= SD_clock_mode;
o_generate_command <= '1' when ((current_state = s_GENERATE_PREDEFINED_COMMAND) or
(current_state = s_GENERATE_COMMAND))
else '0';
o_receive_response <= '1' when ((current_state = s_WAIT_PREDEFINED_COMMAND_RESPONSE) or
(current_state = s_WAIT_RESPONSE))
else '0';
o_drive_CMD_line <= '1' when ( (current_state = s_WAIT_PREDEFINED_COMMAND_TRANSMITTED) or
(current_state = s_SEND_COMMAND)) else '0';
o_predefined_command_ID <= id_sequence_step_index;
o_card_connected <= '1' when (id_sequence_step_index(3) = '1') and (
(id_sequence_step_index(2) = '1') or
(id_sequence_step_index(1) = '1') or
(id_sequence_step_index(0) = '1'))
else '0';
o_resetting <= '1' when (current_state = s_RESET) else '0';
o_command_completed <= '1' when (current_state = s_WAIT_DEASSERT) else '0';
o_enable_clock_generator <= '0' when (current_state = s_AWAIT_USER_COMMAND) else '1';
o_clear_response_register <= '1' when (current_state = s_REACTIVATE_CLOCK) else '0';
end rtl;