library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library i2c;
use work.ssd1306_pkg.all;
entity ssd1306_counter_master_logic is
generic (
DIGITS : natural;
I2C_CLK_FREQ : integer);
port (
clk_i : in std_logic;
rst_in : in std_logic;
start_i : in std_logic;
count_i : in std_logic_vector(DIGITS*4 - 1 downto 0);
master_start_o : out std_logic;
master_stop_o : out std_logic;
tx_valid_o : out std_logic;
tx_ready_i : in std_logic;
tx_data_o : out std_logic_vector(7 downto 0);
dev_busy_i : in std_logic;
waiting_i : in std_logic;
any_err_i : in std_logic;
state_o : out std_logic_vector(3 downto 0);
substate_o : out std_logic_vector(2 downto 0));
end entity ssd1306_counter_master_logic;
architecture a1 of ssd1306_counter_master_logic is
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;
signal digit_data : data_arr_t(0 to 8);
signal curr_index : natural;
signal next_index : natural;
signal max_index : natural;
begin -- architecture a1
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));
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_i = '1' and curr_index < max_index and curr_substate = DATA else
curr_index;
tx_valid_o <= '1' when tx_ready_i = '1' and curr_index < max_index and curr_substate = DATA else '0';
tx_data_o <= 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_i(((DIGITS - 1 - curr_digit) + 1) * 4 - 1 downto (DIGITS - 1 - curr_digit) * 4));
master_start_o <= '1' when curr_substate = START else '0';
master_stop_o <= '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_i = '1' then
next_state <= IDLE;
end if;
if start_i = '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_i = '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_i = '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;
set_regs: process (clk_i) is
begin -- process set_regs
if rising_edge(clk_i) then -- rising clock edge
if rst_in = '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;