library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity onewire is generic ( CLK_FREQ : positive := 50_000_000 ); port ( clk : in std_logic; reset : in std_logic; ow_pin : inout std_logic; -- 4.7 kohm pull-up to 3.3 V externally start : in std_logic; op : in std_logic_vector(1 downto 0); -- "00" reset, "01" write, "10" read tx_byte : in std_logic_vector(7 downto 0); rx_byte : out std_logic_vector(7 downto 0); presence : out std_logic; busy : out std_logic; done : out std_logic ); end entity onewire; architecture rtl of onewire is constant us : positive := CLK_FREQ / 1_000_000; constant RESET_LOW_TICKS : positive := 480 * us; constant PRESENCE_WAIT_TICKS : positive := 15 * us; constant PRESENCE_SAMPLE_END : positive := 75 * us; constant RESET_RECOVER_TICKS : positive := 480 * us; constant WRITE0_LOW_TICKS : positive := 60 * us; constant WRITE1_LOW_TICKS : positive := 6 * us; constant SLOT_TICKS : positive := 70 * us; constant READ_INIT_TICKS : positive := 6 * us; constant READ_SAMPLE_TICKS : positive := 15 * us; type state_t is ( IDLE, RST_PULL, RST_RELEASE, RST_SAMPLE, RST_RECOVER, WR_PULL, WR_RELEASE, RD_PULL, RD_RELEASE, RD_SAMPLE, RD_RECOVER, BYTE_NEXT ); signal state : state_t := IDLE; signal ow_drive : std_logic := '0'; signal ow_sense : std_logic; signal timer : natural range 0 to RESET_LOW_TICKS + 1 := 0; signal bit_index : natural range 0 to 8 := 0; signal shift_reg : std_logic_vector(7 downto 0) := (others => '0'); signal cur_bit : std_logic := '0'; signal is_read : std_logic := '0'; signal rx_byte_i : std_logic_vector(7 downto 0) := (others => '0'); signal presence_internal : std_logic := '0'; begin ow_pin <= '0' when ow_drive = '1' else 'Z'; ow_sense <= ow_pin; presence <= presence_internal; rx_byte <= rx_byte_i; busy <= '0' when state = IDLE else '1'; process(clk) begin if rising_edge(clk) then done <= '0'; timer <= timer + 1; if reset = '1' then state <= IDLE; ow_drive <= '0'; timer <= 0; else case state is when IDLE => timer <= 0; if start = '1' then presence_internal <= '0'; case op is -- reset when "00" => timer <= 0; state <= RST_PULL; -- write when "01" => state <= WR_PULL; shift_reg <= tx_byte; bit_index <= 0; is_read <= '0'; -- read when "10" => state <= RD_PULL; bit_index <= 0; is_read <= '1'; when others => null; end case; end if; when RST_PULL => ow_drive <= '1'; if timer >= RESET_LOW_TICKS then state <= RST_RELEASE; end if; when RST_RELEASE => ow_drive <= '0'; timer <= 0; state <= RST_SAMPLE; when RST_SAMPLE => if ow_sense = '0' then presence_internal <= '1'; end if; if (ow_sense = '1' and presence_internal = '1') or timer >= PRESENCE_SAMPLE_END then state <= RST_RECOVER; end if; when RST_RECOVER => -- wait for 480us since RST_RELEASE if timer >= RESET_RECOVER_TICKS then done <= '1'; state <= IDLE; end if; when WR_PULL => ow_drive <= '1'; if (shift_reg(bit_index) = '1' and timer >= WRITE1_LOW_TICKS) or (shift_reg(bit_index) = '0' and timer >= WRITE0_LOW_TICKS) then state <= WR_RELEASE; end if; when WR_RELEASE => ow_drive <= '0'; if timer >= SLOT_TICKS then state <= BYTE_NEXT; end if; when RD_PULL => ow_drive <= '1'; if timer >= READ_INIT_TICKS then state <= RD_RELEASE; end if; when RD_RELEASE => ow_drive <= '0'; if timer >= READ_INIT_TICKS + 2 * us then state <= RD_SAMPLE; end if; when RD_SAMPLE => rx_byte_i <= ow_sense & rx_byte_i(7 downto 1); state <= RD_RECOVER; when RD_RECOVER => if timer >= SLOT_TICKS then state <= BYTE_NEXT; end if; when BYTE_NEXT => timer <= 0; if bit_index = 7 then bit_index <= 0; done <= '1'; state <= IDLE; else bit_index <= bit_index + 1; if is_read = '1' then state <= RD_PULL; else state <= WR_PULL; end if; end if; when others => state <= IDLE; end case; end if; end if; end process; end architecture rtl;