URL
https://opencores.org/ocsvn/onewire/onewire/trunk
Subversion Repositories onewire
[/] [onewire/] [trunk/] [HDL/] [ow_search.vhd] - Rev 4
Compare with Previous | Blame | View Log
---------------------------------------------------------------------------------- -- <c>2018 william b hunter -- This file is part of ow2rtd. -- -- ow2rtd is free software: you can redistribute it and/or modify -- it under the terms of the GNU Lessor General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- ow2rtd is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU Lessor General Public License -- along with ow2rtd. If not, see <https://www.gnu.org/licenses/>. ----------------------------------------------------------------------------------- -- Create Date: 5/15/2018 -- file: ow_search.vhd -- description: searches a one wire bus for up to 8 one wire devices, and reports -- the 8 IDs. If there are more than 8 IDs or if a device disapears during the -- search it will activate the err flag. Only DS1820 devices are supported -- ----------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.numeric_std.all; ------------------------------------------------------------------------------------- -- Entity declaration ------------------------------------------------------------------------------------- entity ow_search is port ( --global signals clk : in std_logic; srst : in std_logic; --signals to upper layer hierarchy start : in std_logic; busyin : in std_logic; --busy signal from either ow_byte or ow_bit busy : out std_logic; --busy indication to higher level modules error : out std_logic; --indicates a problem on the bus --signals to lower layer hierarchy (ow_bit and ow_byte) rdbit : out std_logic; --strobe to read a bit from ow_bit wrbit : out std_logic; --strobe to write a bit to ow_bit zzbit : out std_logic; --strobe to send/recieve init/response pulses obit : out std_logic; --the bit to write in a wrbit command to ow_bit ibit : in std_logic; --the data recieved from a rdbit command to the ow_bit wrbyte : out std_logic; --strobe to wrte a byte to ow_byte obyte : out std_logic_vector(7 downto 0); --data to write to the ow_byte --interface to id ram id_num : out std_logic_vector(4 downto 0); --index of the id to read or write id_bit : out std_logic_vector(5 downto 0); --index of the bit to read or write id_rbit : in std_logic; --bit value of the currently indexed bit of the current rom id_wbit : out std_logic; --bit value to write to the currently indexed bit id_we : out std_logic --write the currently indexed bit ); end ow_search; ------------------------------------------------------------------------------------- -- Architecture declaration ------------------------------------------------------------------------------------- architecture rtl of ow_search is type h_state_type is (H_IDLE, H_RST, H_WRCMD, H_READBIT, H_READCMP, H_PARSE, H_INCLOOP, H_FILL, H_ERROR); signal h_state : h_state_type := H_IDLE; type f_state_type is (F_IDLE, F_FIND, F_INC); signal f_state : f_state_type := F_IDLE; signal idcnt : integer range 0 to 31; signal lastfork : integer range 0 to 64; signal zerofork : integer range 0 to 64; signal idbitnum : integer range 0 to 63; signal lastdev : std_logic := '0'; signal h_err : std_logic := '0'; signal f_err : std_logic := '0'; signal irdbit : std_logic := '0'; signal iwrbit : std_logic := '0'; signal iwe : std_logic := '0'; signal iobit : std_logic := '0'; signal iwrbyte : std_logic := '0'; signal izzbit : std_logic := '0'; signal rxpat : std_logic_vector(1 downto 0); signal h_start : std_logic := '0'; signal restart : std_logic := '0'; signal h_busy : std_logic := '0'; constant scan_cmd : std_logic_vector(7 downto 0) := x"f0"; attribute mark_debug : string; attribute mark_debug of f_state : signal is "true"; attribute mark_debug of h_state : signal is "true"; attribute mark_debug of idbitnum : signal is "true"; attribute mark_debug of lastfork : signal is "true"; attribute mark_debug of zerofork : signal is "true"; attribute mark_debug of rxpat : signal is "true"; attribute mark_debug of iwrbyte : signal is "true"; attribute mark_debug of irdbit : signal is "true"; attribute mark_debug of iwrbit : signal is "true"; attribute mark_debug of iwe : signal is "true"; attribute mark_debug of iobit : signal is "true"; attribute mark_debug of id_rbit : signal is "true"; attribute mark_debug of obyte : signal is "true"; attribute mark_debug of lastdev : signal is "true"; attribute mark_debug of start : signal is "true"; attribute mark_debug of busyin : signal is "true"; begin ------------------------------------------------------ -- HUNT - search for the next device on bus --- ------------------------------------------------------ --p_hunt - hunts for the next device using the algorithm described in Maxim (Analog Devices) app note APP187 -- the app note is modified slightly for optimization in VHDL -- the algorithm works by taking successive passes through the address field with each pass revealing the next device -- address in alphabetic order. The first pass takes the 0 path at each conflicting address bit (or fork). By keeping -- track of the last conflicting bit in variable zerofork/lastfork, the algorithm knows were to deviate from the -- present address on the next pass. On subsequent passes, for all conflicts up to the lastfork, -- the same fork is taken as was taken on the previous pass, which could be a 1 or 0. At the fork at the lastfork, -- the 1 path is taken, because the 0 path was taken in the previous pass. The variable zerofork is used to keep track -- of the last fork for this pass at which a zero path was taken, and lastfork is the zerofork from the previous pass. -- zerofork and lastfork are set to 64 if there are no zero forks taken. -- If no zero forks were taken, then the last device was found and the lastdev is set, afterwhich the FILL state -- is used to zero out the remaining unused ID memeory locations -- p_hunt : process (clk) begin if rising_edge(clk) then if srst = '1' or restart = '1' then --Start a new search, put all signals into default state, and start in H_IDLE state h_state <= H_IDLE; idbitnum <= 0; lastfork <= 64; zerofork <= 64; lastdev <= '0'; rxpat <= "00"; h_err <= '0'; iwrbyte <= '0'; izzbit <= '0'; irdbit <= '0'; iwrbit <= '0'; iwe <= '0'; iobit <= '0'; obyte <= x"00"; else case h_state is when H_IDLE => --when in idle, all signals in default state idbitnum <= 0; zerofork <= 64; rxpat <= "00"; iwrbyte <= '0'; irdbit <= '0'; iwrbit <= '0'; iwe <= '0'; iobit <= '0'; obyte <= x"00"; if h_start = '1' then --detected command to search for next onewire device if lastdev = '0' then --first time thorough, reset the one-wire bus h_state <= H_RST; izzbit <= '1'; --send reset signal h_err <= '0'; else h_state <= H_FILL; iwe <= '1'; iobit <= '0'; end if; else izzbit <= '0'; end if; when H_RST => --reset the bus at start of each pass, all devices are activated if izzbit = '1' then izzbit <= '0'; --terminate the reset request elsif busyin = '0' then --reset is completed, the devices should have responded if ibit = '1' then --no response, no devices on bus, so error out h_state <= H_ERROR; else --send "search rom" command obyte <= x"f0"; iwrbyte <= '1'; h_state <= H_WRCMD; end if; end if; when H_WRCMD => --waits for end write command byte, then reads a response bit if iwrbyte = '1' then iwrbyte <= '0'; --terminate write "search rom" command request elsif busyin = '0' then -- when the write command is completed -- read a bit, this will be the AND of the -- first address bit of all devices on the bus irdbit <= '1'; h_state <= H_READBIT; end if; when H_READBIT => --reads the address bit if irdbit = '1' then irdbit <= '0'; --terminate the read bit request elsif busyin = '0' then --wait until bit is read --save the AND of the address bit of all devices rxpat(1) <= ibit; --and read the AND of the compliment of the address bit of all devices irdbit <= '1'; h_state <= H_READCMP; end if; when H_READCMP => --reads the complement of the address bit if irdbit = '1' then irdbit <= '0'; --terminate the read complement bit request elsif busyin = '0' then --when bit is read, --save the AND of the complimented address bit of all devices rxpat(0) <= ibit; h_state <= H_PARSE; end if; when H_PARSE => --with the AND of the address bit and the AND of the complimented address bit -- decide how to proceed (see APP note) case rxpat is when "11" => --no device responded h_state <= H_ERROR; when "00" => --00 indicates a conflict, devices disagree on this bit if idbitnum = lastfork then --last_romid(63 downto 0) <= last_romid(0) & last_romid(63 downto 1); --new_romid(63 downto 0) <= '1' & new_romid(63 downto 1); iobit <= '1'; iwrbit <= '1'; iwe <= '1'; h_state <= H_INCLOOP; elsif idbitnum > lastfork then --last_romid(63 downto 0) <= last_romid(0) & last_romid(63 downto 1); --new_romid(63 downto 0) <= '0' & new_romid(63 downto 1); iobit <= '0'; iwrbit <= '1'; iwe <= '1'; zerofork <= idbitnum; h_state <= H_INCLOOP; else --last_romid(63 downto 0) <= last_romid(0) & last_romid(63 downto 1); --new_romid(63 downto 0) <= last_romid(0) & new_romid(63 downto 1); iobit <= id_rbit; iwrbit <= '1'; iwe <= '1'; if id_rbit = '0' then zerofork <= idbitnum; end if; h_state <= H_INCLOOP; end if; when others => --last_romid(63 downto 0) <= last_romid(0) & last_romid(63 downto 1); --new_romid(63 downto 0) <= rxpat(1) & new_romid(63 downto 1); iobit <= rxpat(1); iwrbit <= '1'; iwe <= '1'; h_state <= H_INCLOOP; end case; when H_INCLOOP => --increments the search to the next bit and terminates when all bits are finished if iwrbit = '1' or iwe = '1' then --terminate the write request of the current bit iwrbit <= '0'; iwe <= '0'; elsif busyin = '0' then if idbitnum = 63 then --at end of the address, go back to idle, and move lastzero to lastfork h_state <= H_IDLE; lastfork <= zerofork; if zerofork = 64 then lastdev <= '1'; --make last device if there no zero forks were taken end if; else -- continue on with next bit by requesting a read of the next address bit idbitnum <= idbitnum + 1; irdbit <= '1'; h_state <= H_READBIT; end if; end if; when H_FILL => --this fills the unused address feilds with zeros after the last device is found. if iwe = '1' then iwe <= '0'; elsif idbitnum = 63 then h_state <= H_IDLE; else idbitnum <= idbitnum + 1; iobit <= '0'; iwe <= '1'; end if; when others => h_err <= '1'; h_state <= H_IDLE; end case; end if; end if; end process p_hunt; h_busy <= '0' when h_state = H_IDLE and h_start = '0' else '1'; ------------------------------------------------------ -- FINDALL - find all devices, one by one --- ------------------------------------------------------ --p_findall - finds all (at least up to 8) of the roms on the bus -- this process initiates up to 8 searches, each finds the next device -- in the sorted (by device ID) order. p_findall : process(clk) begin if rising_edge(clk) then if srst = '1' then idcnt <= 0; f_state <= F_IDLE; h_start <= '0'; restart <= '0'; f_err <= '0'; else case f_state is when F_IDLE => if start = '1' then restart <= '1'; elsif restart = '1' then restart <= '0'; h_start <= '1'; f_state <= F_FIND; idcnt <= 0; f_err <= '0'; end if; when F_FIND => --terminate the h_start and wait for hunt state to finish if h_start = '1' then h_start <= '0'; elsif h_busy = '0' then --hunt is finished, go to inc state if no error --error also indicates there are no more one-wire devices if h_err = '1' then f_state <= F_IDLE; f_err <= '1'; else f_state <= F_INC; end if; end if; when F_INC => if idcnt = 31 then idcnt <= 0; f_state <= F_IDLE; else idcnt <= idcnt + 1; f_state <= F_FIND; h_start <= '1'; end if; end case; end if; end if; end process p_findall; ------------------------------------------------------ -- External Signals --- ------------------------------------------------------ id_num <= std_logic_vector(to_unsigned(idcnt,5)); id_bit <= std_logic_vector(to_unsigned(idbitnum,6)); id_we <= iwe; id_wbit <= iobit; rdbit <= irdbit; wrbit <= iwrbit; zzbit <= izzbit; obit <= iobit; wrbyte <= iwrbyte; busy <= '0' when f_state = F_IDLE and h_state = H_IDLE and start = '0' and restart = '0' else '1'; error <= f_err; end rtl;