⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spi_control_sm.vhd

📁 SPI.zip
💻 VHD
📖 第 1 页 / 共 2 页
字号:

    case spi_state is
    
        --********************* IDLE State *****************
        when IDLE =>
            if start = '1' and xmit_empty = '0' then
                next_spi_state <= ASSERT_SSN1;
            end if;

        --********************* ASSERT_SSN1 State *****************
        when ASSERT_SSN1 =>
            -- this state asserts SS_N and waits for first edge of SCK_INT
            -- SS_N must be asserted ~1 SCK before SCK is output from chip

            if sck_int_re = '1' then
                next_spi_state <= ASSERT_SSN2;
            end if;
            
         --********************* ASSERT_SSN2 State *****************
        when ASSERT_SSN2 =>
            -- this state asserts SS_N and waits for next edge of SCK_INT
            -- SS_N must be asserted ~1 SCK before SCK is output from chip

            if sck_int_fe = '1' then
                next_spi_state <= UNMASK_SCK;
            end if;
            
       --********************* UNMASK_SCK State *****************
        when UNMASK_SCK =>
            bit_cnt_rst <= not(RESET_ACTIVE); -- release bit counter from reset
            bit_cnt_en <= '1';  -- enable bit counter
            clk1_mask <= '1';   -- unmask sck_1
            xmit_load <= '1';   -- load SPI shift register
        
            if sck_int_re = '1' then
                -- first rising edge of CPHA=1 clock with SS_N asserted
                -- transition to XFER_BIT state and unmask CPHA=0 clk
                next_spi_state <= XFER_BIT;
            end if;

        --********************* XFER_BIT State *****************
        when XFER_BIT =>
            clk0_mask <= '1';   -- unmask CPHA=0 clock
            clk1_mask <= '1';   -- unmask CPHA=1 clock
            bit_cnt_en <= '1';  -- enable bit counter
            bit_cnt_rst <= not(RESET_ACTIVE); -- release bit counter from reset
            
            xmit_shift <= '1';  -- enable shifting of SPI shift registers
            
            if bit_cnt = EIGHT  then
                -- all 8 bits have transferred
                next_spi_state <= ASSERT_DONE;
            end if;

        --********************* ASSERT_DONE State *****************
        when ASSERT_DONE =>
            -- this state asserts done to the uC so that new data
            -- can be written into the transmit register or data
            -- can be read from the receive register
            done <= '1';
            clk0_mask <= '1';
            clk1_mask <= '1';
            xmit_shift <= '1';
            if sck_int_fe = '1' then
                next_spi_state <= CHK_START;
            end if;
            
        --********************* CHK_START State *****************
        when CHK_START =>
            clk0_mask <= '1';
            clk1_mask <= '1';
            done <= '1';
            bit_cnt_en <= '1';
            bit_cnt_rst <= not(RESET_ACTIVE); -- release bit counter from reset
            if cpha = '0' then
                -- when CPHA = 0, have to negate slave select and then
                -- re-assert it. Need to wait for last SCK pulse to complete
                -- and mask SCK before negating SS_N. 
                if (sck_re = '1' and cpol = '1') or (sck_fe = '1' and cpol = '0') then
                    clk0_mask <= '0';
                    clk1_mask <= '0';
                    next_spi_state <= MASK_SCK;
                end if;
            elsif start = '1' and xmit_empty = '0' then 
                -- CPHA=1 and have more data to transfer, go back to 
                -- UNMASK_CK state
                clk1_mask <= '1';
            xmit_load <= '1';   -- load SPI shift register
                next_spi_state <= UNMASK_SCK;
            else 
                -- CPHA=1 and no more data to transfer
                -- wait for last SCKs and then mask SCK
                if (sck_re = '1' and cpol = '1') or (sck_fe = '1' and cpol = '0') then
                    clk0_mask <= '0';
                    clk1_mask <= '0';
                    next_spi_state <= MASK_SCK;
                end if;
                clk0_mask <= '0';
                clk1_mask <= '1';
            end if;
            
        --********************* MASK_SCK State *****************
        when MASK_SCK =>
            done <= '1';
            -- wait for next internal SCK edge 
            -- to help provide SS_N hold time
            if sck_int_fe <= '1' then
                next_spi_state <= HOLD_SSN1;
            end if;
            
        --********************* HOLD_SSN1 State *****************
        when HOLD_SSN1 =>
            -- This state waits for another SCK edge
            -- to provide SS_N hold time
            if  sck_int_fe = '1' then
                next_spi_state <= HOLD_SSN2;
            end if;
            
        --********************* HOLD_SSN2 State *****************
        when HOLD_SSN2 =>
            -- This state waits for another SCK edge
            -- to provide SS_N hold time
            if  sck_int_fe = '1' then
                next_spi_state <= NEGATE_SSN;
            end if;

        --********************* NEGATE_SSN State *****************
        when NEGATE_SSN =>
            -- SS_N should negate for an entire SCK
            -- This state waits for an SCK edge
            if sck_int_fe = '1' then
                next_spi_state <= IDLE;
            end if;
    
        --********************* Default State *****************
        when others =>
                next_spi_state <= IDLE;
    end case;
end process;


-- assert slave select when spi_state machine is in any state but IDLE or NEGATE_SSN
ss_n_int <= '1' when (spi_state = IDLE or spi_state = NEGATE_SSN) else '0';

--xmit_load <= '1' when (spi_state = UNMASK_SCK) else '0';


--************************** Register Full/Empty flags *******************************
-- When data is loaded into the SPI transmit shift register from SPITR, the XMIT_EMPTY
-- flag is set, indicating to the uC that new data can be written into SPITR. Note that
-- the SPI transmit shift register is clocked from SCK, therefore, this flag is clocked
-- from SCK.
mt_flag_process: process (sck_int, xmit_empty_reset, reset)
begin
    if xmit_empty_reset = RESET_ACTIVE or reset = RESET_ACTIVE then
        xmit_empty <= '0';
    elsif sck_int'event and sck_int = '1' then
        if xmit_empty_reset = RESET_ACTIVE then
            -- reset empty flag because uC has written data to SPITR
            xmit_empty <= '0';
        elsif xmit_load = '1' then
            -- set empty flag because SPITR data has been loaded into 
            -- SPI transmit shift register
            xmit_empty <= '1';
        end if;
    end if;
end process;



-- When data is loaded into SPIRR, the RCV_FULL flag is set, indicating to the uC that
-- new data from the SPI bus has been received.
full_flag_process: process (reset, clk)
begin
    if reset = RESET_ACTIVE then
        rcv_full <= '0';
    elsif clk'event and clk = '1' then
        if rcv_full_reset = RESET_ACTIVE then
            -- reset the full flag because the spirr has been read
            rcv_full <= '0';
        elsif rcv_load = '1' then
            -- set the full flag because data has been loaded in spirr
            rcv_full <= '1';
        end if;
    end if;
end process;

--************************** Slave Selects *******************************
-- The internal slave select signal generated by the SPI Control state machine 
-- is masked by the uC slave select register. The SS_N outputs are clocked on the
-- falling edge of the system clock. 
ss_n_process: process ( reset, clk)
variable i : integer;

begin
    if reset = RESET_ACTIVE then
        ss_n_out <= (others => '1');
    elsif clk'event and clk = '0' then
        for i in 0 to 7 loop
            if ss_n_int = '0' and ss_mask_reg (i) = '1' then
                ss_n_out(i) <= '0';  -- assert corresponding slave select
            else
                ss_n_out(i) <= '1';
            end if;
        end loop;
    end if;
end process;
    
-- Slave selects are 3-stated if SS_IN_INT is asserted  
ss_n <= ss_n_out when ss_in_int = '1'
    else (others => 'Z');

end DEFINITION;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -