~ruther/vhdl-i2c

37f25c631ded6dc90b171ba2c733eda51a5f31bc — Rutherther 1 year, 2 months ago 6df1d16
feat: split ssd1306 counter to logic entity
2 files changed, 189 insertions(+), 132 deletions(-)

M src/ssd1306/counter.vhd
A src/ssd1306/ssd1306_counter_master_logic.vhd
M src/ssd1306/counter.vhd => src/ssd1306/counter.vhd +18 -132
@@ 69,31 69,12 @@ architecture a1 of ssd1306_counter is
  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';
  rw <= '0';
  master_run <= '1';
  rst_n <= not rst_sync;
  waiting_o <= waiting;


@@ 105,101 86,23 @@ begin  -- architecture a+
  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_master_logic: entity work.ssd1306_counter_master_logic
    generic map (
      DIGITS       => DIGITS,
      I2C_CLK_FREQ => I2C_CLK_FREQ)
    port map (
      clk_i => i2c_clk,
      rst_in => rst_n,
      start_i => start_i,
      count_i => count,
      tx_valid_o => tx_valid,
      tx_ready_i => tx_ready,
      tx_data_o => tx_data,
      dev_busy_i => dev_busy,
      waiting_i => waiting,
      any_err_i => any_err,
      state_o    => state_o,
      substate_o => substate_o);

  counter: entity utils.counter
    generic map (


@@ 278,21 181,4 @@ begin  -- architecture a+
      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;

A src/ssd1306/ssd1306_counter_master_logic.vhd => src/ssd1306/ssd1306_counter_master_logic.vhd +171 -0
@@ 0,0 1,171 @@
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);

    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
  signal master_start, master_stop : 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;

  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 <= '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_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;

Do not follow this link