library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; library i2c; library utils; use work.ssd1306_pkg.all; entity ssd1306_counter is generic ( CLK_FREQ : integer := 100000000; -- Input clock frequency I2C_CLK_FREQ : integer := 5000000; COUNT_FREQ : integer := 1; DELAY : integer := 20; EXPECT_ACK : std_logic := '1'; SCL_MIN_STABLE_CYCLES : natural := 50); port ( clk_i : in std_logic; rst_i : in std_logic; start_i : in std_logic; err_noack_data_o : out std_logic; err_noack_address_o : out std_logic; err_arbitration_o : out std_logic; err_general_o : out std_logic; state_o : out std_logic_vector(3 downto 0); substate_o : out std_logic_vector(2 downto 0); bus_busy_o : out std_logic; dev_busy_o : out std_logic; waiting_o : out std_logic; sda_io : inout std_logic; scl_io : inout std_logic); end entity ssd1306_counter; architecture a1 of ssd1306_counter is constant ADDRESS : std_logic_vector(6 downto 0) := "0111100"; signal rst_n : std_logic; signal rst_sync : std_logic; signal i2c_clk : std_logic; signal master_start, master_stop, master_run : std_logic; signal rw : std_logic; signal tx_valid, tx_ready, tx_clear_buffer : std_logic; signal tx_data : std_logic_vector(7 downto 0); signal rx_valid, rx_confirm : std_logic; signal rx_data : std_logic_vector(7 downto 0); signal err_noack_data : std_logic; signal err_noack_address : std_logic; signal err_arbitration : std_logic; signal err_general : std_logic; signal any_err : std_logic; signal waiting : std_logic; signal dev_busy : std_logic; signal sda, scl : std_logic; signal sda_enable, scl_enable : std_logic; type state_t is (IDLE, INIT_DISPLAY, INIT_ADDRESSING_MODE, ZERO_OUT_RAM, SET_ADR_ZERO, DIGIT_N, SEC_DELAY); signal curr_state : state_t; signal next_state : state_t; signal curr_digit : natural; signal next_digit : natural; type substate_t is (IDLE, START, DATA, STOP, ALT); signal curr_substate : substate_t; signal next_substate : substate_t; constant DIGITS : natural := 3; signal count : std_logic_vector(DIGITS * 4 - 1 downto 0); signal digit_data : data_arr_t(0 to 8); signal curr_index : natural; signal next_index : natural; signal max_index : natural; begin -- architecture a+ state_o <= std_logic_vector(to_unsigned(state_t'pos(curr_state), 4)); substate_o <= std_logic_vector(to_unsigned(substate_t'pos(curr_substate), 3)); tx_clear_buffer <= '0'; master_run <= '1'; rst_n <= not rst_sync; waiting_o <= waiting; dev_busy_o <= dev_busy; err_noack_data_o <= err_noack_data; err_noack_address_o <= err_noack_address; err_arbitration_o <= err_arbitration; err_general_o <= err_general; any_err <= err_general or err_arbitration or err_noack_address or err_noack_data; rw <= '0'; max_index <= SSD1306_INIT'length when curr_state = INIT_DISPLAY else SSD1306_HORIZONTAL_ADDRESSING_MODE'length when curr_state = INIT_ADDRESSING_MODE else 9 when curr_state = DIGIT_N else SSD1306_CURSOR_TO_ZERO'length when curr_state = SET_ADR_ZERO else I2C_CLK_FREQ/2 when curr_state = SEC_DELAY else SSD1306_ZERO_LEN when curr_state = ZERO_OUT_RAM else 0; next_index <= 0 when curr_substate = IDLE else (curr_index + 1) when curr_substate = ALT and curr_index < max_index else (curr_index + 1) when tx_ready = '1' and curr_index < max_index and curr_substate = DATA else curr_index; tx_valid <= '1' when tx_ready = '1' and curr_index < max_index and curr_substate = DATA else '0'; tx_data <= SSD1306_INIT(curr_index) when curr_state = INIT_DISPLAY and curr_index < max_index else SSD1306_HORIZONTAL_ADDRESSING_MODE(curr_index) when curr_state = INIT_ADDRESSING_MODE and curr_index < max_index else SSD1306_ZERO(0) when curr_state = ZERO_OUT_RAM and curr_index = 0 else SSD1306_ZERO(1) when curr_state = ZERO_OUT_RAM and curr_index /= 0 else SSD1306_CURSOR_TO_ZERO(curr_index) when curr_state = SET_ADR_ZERO and curr_index < max_index else digit_data(curr_index) when curr_state = DIGIT_N and curr_index < max_index else "00000000"; next_digit <= 0 when curr_state /= DIGIT_N else (curr_digit + 1) when curr_state = DIGIT_N and curr_substate = STOP and curr_digit < DIGITS - 1 else curr_digit; digit_data <= ssd1306_bcd_digit_data(count(((DIGITS - 1 - curr_digit) + 1) * 4 - 1 downto (DIGITS - 1 - curr_digit) * 4)); master_start <= '1' when curr_substate = START else '0'; master_stop <= '1' when curr_substate = STOP else '0'; set_next_state: process (all) is begin -- process set_next_state next_state <= curr_state; if curr_state = IDLE then next_state <= INIT_DISPLAY; elsif curr_state = INIT_DISPLAY then if curr_substate = STOP then next_state <= INIT_ADDRESSING_MODE; end if; elsif curr_state = INIT_ADDRESSING_MODE then if curr_substate = STOP then next_state <= ZERO_OUT_RAM; end if; elsif curr_state = ZERO_OUT_RAM then if curr_substate = STOP then next_state <= SET_ADR_ZERO; end if; elsif curr_state = SET_ADR_ZERO then if curr_substate = STOP then next_state <= DIGIT_N; end if; elsif curr_state = DIGIT_N then if curr_substate = STOP and curr_digit = DIGITS - 1 then next_state <= SEC_DELAY; end if; elsif curr_state = SEC_DELAY then if curr_index = max_index then next_state <= SET_ADR_ZERO; end if; end if; if any_err = '1' then next_state <= IDLE; end if; end process set_next_state; set_next_substate: process (all) is begin -- process set_next_state next_substate <= curr_substate; if curr_state /= IDLE and curr_state /= SEC_DELAY then if curr_substate = IDLE then if dev_busy = '0' then next_substate <= START; end if; elsif curr_substate = START then next_substate <= DATA; elsif curr_substate = DATA and curr_index = max_index then if waiting = '1' then next_substate <= STOP; end if; elsif curr_substate = STOP then next_substate <= IDLE; elsif curr_substate = ALT then next_substate <= IDLE; end if; else next_substate <= ALT; end if; end process set_next_substate; counter: entity utils.counter generic map ( MAX => 9, DIGITS => DIGITS, IN_FREQ => CLK_FREQ, OUT_FREQ => COUNT_FREQ) port map ( clk_i => clk_i, rst_in => rst_n, value_o => count); divider: entity utils.clock_divider generic map ( IN_FREQ => CLK_FREQ, OUT_FREQ => I2C_CLK_FREQ) port map ( clk_i => clk_i, clk_o => i2c_clk); i2c_master: entity i2c.master generic map ( SCL_FALLING_DELAY => DELAY, SCL_MIN_STABLE_CYCLES => SCL_MIN_STABLE_CYCLES) port map ( clk_i => i2c_clk, rst_in => rst_n, -- slave_address_i => ADDRESS, -- generate_ack_i => '1', expect_ack_i => EXPECT_ACK, -- rx_valid_o => rx_valid, rx_data_o => rx_data, rx_confirm_i => rx_confirm, -- tx_ready_o => tx_ready, tx_valid_i => tx_valid, tx_data_i => tx_data, tx_clear_buffer_i => tx_clear_buffer, -- err_noack_data_o => err_noack_data, err_noack_address_o => err_noack_address, err_arbitration_o => err_arbitration, err_general_o => err_general, -- stop_i => master_stop, start_i => master_start, run_i => master_run, rw_i => rw, -- dev_busy_o => dev_busy, bus_busy_o => bus_busy_o, waiting_o => waiting, -- sda_i => sda, scl_i => scl, sda_enable_o => sda_enable, scl_enable_o => scl_enable); sync_reset: entity utils.metastability_filter port map ( clk_i => clk_i, signal_i => rst_i, signal_o => rst_sync); sda_open_buffer: entity utils.open_drain_buffer port map ( pad_io => sda_io, enable_i => sda_enable, state_o => sda); scl_open_buffer: entity utils.open_drain_buffer port map ( pad_io => scl_io, enable_i => scl_enable, state_o => scl); set_regs: process (i2c_clk) is begin -- process set_regs if rising_edge(i2c_clk) then -- rising clock edge if rst_n = '0' then -- synchronous reset (active low) curr_state <= IDLE; curr_substate <= IDLE; curr_digit <= 0; curr_index <= 0; else curr_state <= next_state; curr_substate <= next_substate; curr_digit <= next_digit; curr_index <= next_index; end if; end if; end process set_regs; end architecture a1;