Line 132... |
Line 132... |
-- frequency sequential circuits, to preserve clocking resources and avoid path delay glitches.
|
-- frequency sequential circuits, to preserve clocking resources and avoid path delay glitches.
|
-- 2011/07/10 v1.00.0098 [JD] implemented SCK clock divider circuit to generate spi clock directly from system clock.
|
-- 2011/07/10 v1.00.0098 [JD] implemented SCK clock divider circuit to generate spi clock directly from system clock.
|
-- 2011/07/10 v1.10.0075 [JD] verified spi_master_slave in silicon at 50MHz, 25MHz, 16.666MHz, 12.5MHz, 10MHz, 8.333MHz,
|
-- 2011/07/10 v1.10.0075 [JD] verified spi_master_slave in silicon at 50MHz, 25MHz, 16.666MHz, 12.5MHz, 10MHz, 8.333MHz,
|
-- 7.1428MHz, 6.25MHz, 1MHz and 500kHz. The core proved very robust at all tested frequencies.
|
-- 7.1428MHz, 6.25MHz, 1MHz and 500kHz. The core proved very robust at all tested frequencies.
|
-- 2011/07/16 v1.11.0080 [JD] verified both spi_master and spi_slave in loopback at 50MHz SPI clock.
|
-- 2011/07/16 v1.11.0080 [JD] verified both spi_master and spi_slave in loopback at 50MHz SPI clock.
|
|
-- 2011/07/17 v1.11.0080 [JD] BUG: CPOL='1', CPHA='1' @50MHz causes MOSI to be shifted one bit earlier.
|
|
-- BUG: CPOL='0', CPHA='1' causes SCK to have one extra pulse with one sclk_i width at the end.
|
|
-- 2011/07/18 v1.12.0105 [JD] CHG: spi sck output register changed to remove glitch at last clock when CPHA='1'.
|
|
-- for CPHA='1', max spi clock is 25MHz. for CPHA= '0', max spi clock is >50MHz.
|
--
|
--
|
-----------------------------------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------
|
-- TODO
|
-- TODO
|
-- ====
|
-- ====
|
--
|
--
|
Line 205... |
Line 209... |
signal spi_2x_ce : std_logic := '1'; -- spi_2x clock enable
|
signal spi_2x_ce : std_logic := '1'; -- spi_2x clock enable
|
signal spi_clk : std_logic := '0'; -- spi bus output clock
|
signal spi_clk : std_logic := '0'; -- spi bus output clock
|
signal spi_clk_reg : std_logic := '0'; -- output pipeline delay for spi sck
|
signal spi_clk_reg : std_logic := '0'; -- output pipeline delay for spi sck
|
-- core fsm clock enables
|
-- core fsm clock enables
|
signal fsm_ce : std_logic := '1'; -- fsm clock enable
|
signal fsm_ce : std_logic := '1'; -- fsm clock enable
|
|
signal ena_sck_ce : std_logic := '1'; -- SCK clock enable
|
signal samp_ce : std_logic := '1'; -- data sampling clock enable
|
signal samp_ce : std_logic := '1'; -- data sampling clock enable
|
--
|
--
|
-- GLOBAL RESET:
|
-- GLOBAL RESET:
|
-- all signals are initialized to zero at GSR (global set/reset) by giving explicit
|
-- all signals are initialized to zero at GSR (global set/reset) by giving explicit
|
-- initialization values at declaration. This is needed for all Xilinx FPGAs, and
|
-- initialization values at declaration. This is needed for all Xilinx FPGAs, and
|
Line 367... |
Line 372... |
if CPHA = '1' generate
|
if CPHA = '1' generate
|
begin
|
begin
|
fsm_ce <= core_ce; -- for CPHA=1, latch registers at rising edge of positive core clock enable
|
fsm_ce <= core_ce; -- for CPHA=1, latch registers at rising edge of positive core clock enable
|
end generate;
|
end generate;
|
|
|
|
ena_sck_ce <= core_n_ce; -- for CPHA=1, SCK is advanced one-half cycle
|
|
|
--=============================================================================================
|
--=============================================================================================
|
-- REGISTERED INPUTS
|
-- REGISTERED INPUTS
|
--=============================================================================================
|
--=============================================================================================
|
-- rx bit flop: capture rx bit after SAMPLE edge of sck
|
-- rx bit flop: capture rx bit after SAMPLE edge of sck
|
--
|
--
|
-- ATTENTION: REMOVING THE FLIPFLOP (DIRECT CONNECTION) WE GET HIGHER PERFORMANCE DUE TO
|
-- ATTENTION: REMOVING THE FLIPFLOP (DIRECT CONNECTION) WE GET HIGHER PERFORMANCE DUE TO
|
-- REDUCED DEMAND ON MISO SETUP TIME.
|
-- REDUCED DEMAND ON MISO SETUP TIME.
|
--
|
--
|
rx_bit_proc : process (sclk_i, spi_miso_i) is
|
rx_bit_proc : process (sclk_i, spi_miso_i) is
|
begin
|
begin
|
-- if sclk_i'event and sclk_i = '1' then
|
if sclk_i'event and sclk_i = '1' then
|
-- if samp_ce = '1' then
|
if samp_ce = '1' then
|
rx_bit_reg <= spi_miso_i;
|
rx_bit_reg <= spi_miso_i;
|
-- end if;
|
end if;
|
-- end if;
|
end if;
|
end process rx_bit_proc;
|
end process rx_bit_proc;
|
|
|
--=============================================================================================
|
--=============================================================================================
|
-- CROSS-CLOCK PIPELINE TRANSFER LOGIC
|
-- CROSS-CLOCK PIPELINE TRANSFER LOGIC
|
--=============================================================================================
|
--=============================================================================================
|
Line 446... |
Line 453... |
state_reg <= 0; -- only provide local reset for the state machine
|
state_reg <= 0; -- only provide local reset for the state machine
|
elsif fsm_ce = '1' then -- fsm_ce is clock enable for the fsm
|
elsif fsm_ce = '1' then -- fsm_ce is clock enable for the fsm
|
state_reg <= state_next; -- state register
|
state_reg <= state_next; -- state register
|
end if;
|
end if;
|
end if;
|
end if;
|
-- FF registers clocked on rising edge
|
-- FF registers clocked synchronous to the fsm state
|
if sclk_i'event and sclk_i = '1' then
|
if sclk_i'event and sclk_i = '1' then
|
if fsm_ce = '1' then
|
if fsm_ce = '1' then
|
sh_reg <= sh_next; -- shift register
|
sh_reg <= sh_next; -- shift register
|
ena_ssel_reg <= ena_ssel_next; -- spi select enable
|
ena_ssel_reg <= ena_ssel_next; -- spi select enable
|
ena_sck_reg <= ena_sck_next; -- spi clock enable
|
ena_sck_reg <= ena_sck_next; -- spi clock enable
|
Line 458... |
Line 465... |
do_transfer_reg <= do_transfer_next; -- output data transferred to buffer
|
do_transfer_reg <= do_transfer_next; -- output data transferred to buffer
|
di_req_reg <= di_req_next; -- input data request
|
di_req_reg <= di_req_next; -- input data request
|
wren_ack_reg <= wren_ack_next; -- wren ack for data load synchronization
|
wren_ack_reg <= wren_ack_next; -- wren ack for data load synchronization
|
end if;
|
end if;
|
end if;
|
end if;
|
|
-- FF registers clocked one-half cycle earlier than the fsm state
|
|
-- if sclk_i'event and sclk_i = '1' then
|
|
-- if ena_sck_ce = '1' then
|
|
-- ena_sck_reg <= ena_sck_next; -- spi clock enable
|
|
-- end if;
|
|
-- end if;
|
end process core_reg_proc;
|
end process core_reg_proc;
|
|
|
--=============================================================================================
|
--=============================================================================================
|
-- RTL combinatorial LOGIC PROCESSES
|
-- RTL combinatorial LOGIC PROCESSES
|
--=============================================================================================
|
--=============================================================================================
|
Line 537... |
Line 550... |
-----------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------
|
-- This is a MUX with an output register. The register gives us a pipeline delay for the SCK line,
|
-- This is a MUX with an output register. The register gives us a pipeline delay for the SCK line,
|
-- enabling higher SCK frequency. The MOSI and SCK phase are compensated by the pipeline delay.
|
-- enabling higher SCK frequency. The MOSI and SCK phase are compensated by the pipeline delay.
|
spi_sck_o_gen_proc : process (sclk_i, ena_sck_reg, spi_clk, spi_clk_reg) is
|
spi_sck_o_gen_proc : process (sclk_i, ena_sck_reg, spi_clk, spi_clk_reg) is
|
begin
|
begin
|
if sclk_i'event and sclk_i = '1' then
|
-- if sclk_i'event and sclk_i = '1' then
|
|
-- if ena_sck_reg = '1' then
|
|
-- spi_clk_reg <= spi_clk; -- copy the selected clock polarity
|
|
-- else
|
|
-- spi_clk_reg <= CPOL; -- when clock disabled, set to idle polarity
|
|
-- end if;
|
|
-- end if;
|
if ena_sck_reg = '1' then
|
if ena_sck_reg = '1' then
|
|
if sclk_i'event and sclk_i = '1' then
|
spi_clk_reg <= spi_clk; -- copy the selected clock polarity
|
spi_clk_reg <= spi_clk; -- copy the selected clock polarity
|
|
end if;
|
else
|
else
|
spi_clk_reg <= CPOL; -- when clock disabled, set to idle polarity
|
spi_clk_reg <= CPOL; -- when clock disabled, set to idle polarity
|
end if;
|
end if;
|
end if;
|
|
spi_sck_o <= spi_clk_reg; -- connect register to output
|
spi_sck_o <= spi_clk_reg; -- connect register to output
|
end process spi_sck_o_gen_proc;
|
end process spi_sck_o_gen_proc;
|
|
|
--=============================================================================================
|
--=============================================================================================
|
-- DEBUG LOGIC PROCESSES
|
-- DEBUG LOGIC PROCESSES
|