URL
https://opencores.org/ocsvn/onewire/onewire/trunk
Subversion Repositories onewire
Compare Revisions
- This comparison shows the changes necessary to convert path
/onewire
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
/trunk/HDL/ds1820_mstr.vhd
0,0 → 1,266
---------------------------------------------------------------------------------- |
-- <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: ds1820_mstr.vhd |
-- description: interfaces to the ds1820 devices on the one wire bus. |
-- this includes discovering the devices, configuring them, and reading the temperatures |
-- |
-- The design consists of the following major blocks: |
-- ow_mstr - low level interface to the one wire bus including byte and bit accesses |
-- ow_search - discovers devices on the one wire bus, both ds1820 types and others |
-- ow_temp - configures the ds1820 devices on the bus and reads the temperatures |
-- ow_idram - a ram for storing the 64 bit long device ids |
----------------------------- |
|
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
use IEEE.numeric_std.all; |
|
------------------------------------------------------------------------------------- |
-- Entity declaration |
------------------------------------------------------------------------------------- |
entity ds1820_mstr is |
port ( |
--global signals |
clk : in std_logic; |
srst : in std_logic; --synchronous reset |
stb1us : in std_logic; --1us strobe, used to time transactions |
busy : out std_logic; --device is in middle of read,write or init |
err : out std_logic; --something went wrong, this is cleared by next command |
--controls from upper level of hierarchy |
search_stb : in std_logic; --searches for devices on bus |
temp_init : in std_logic; --starts initialization of all sensors |
temp_conv : in std_logic; --starts temperature conversion on all sensors |
temp_read : in std_logic; --starts temperature read from all sensors |
--response to upper level of hierarchy |
temp : out signed(15 downto 0); --temperature of the current sensor |
tempidx : out unsigned(4 downto 0); --index of the current temp sensor |
tempstb : out std_logic; --temperature available strobe |
--one wire bus interface |
owin : in std_logic; --one wire input |
owout : out std_logic --one wire output |
--dio : inout std_logic |
); |
end ds1820_mstr; |
|
------------------------------------------------------------------------------------- |
-- Architecture declaration |
------------------------------------------------------------------------------------- |
architecture rtl of ds1820_mstr is |
--bit module signals |
type s16ary is array (integer range <>) of signed(15 downto 0); |
signal ow_zbit : std_logic; |
signal ow_rbit : std_logic; |
signal ow_obit : std_logic; |
signal ow_wbit : std_logic; |
signal ow_ibit : std_logic; |
signal ow_rbyte : std_logic; |
signal ow_obyte : std_logic_vector(7 downto 0); |
signal ow_wbyte : std_logic; |
signal ow_ibyte : std_logic_vector(7 downto 0); |
signal ow_busy : std_logic; |
signal ow_ppwr : std_logic; |
|
--search module signals |
signal ows_wbit : std_logic; |
signal ows_obit : std_logic; |
signal ows_rbit : std_logic; |
signal ows_zbit : std_logic; |
signal ows_busy : std_logic; |
signal ows_err : std_logic; |
signal ows_wbyte : std_logic; |
signal ows_obyte : std_logic_vector(7 downto 0); |
signal ows_idnum : std_logic_vector(4 downto 0); |
signal ows_idbit : std_logic_vector(5 downto 0); |
|
--temp module signals |
signal owt_wbit : std_logic; |
signal owt_obit : std_logic; |
signal owt_zbit : std_logic; |
signal owt_busy : std_logic; |
signal owt_err : std_logic; |
signal owt_wbyte : std_logic; |
signal owt_obyte : std_logic_vector(7 downto 0); |
signal owt_rbyte : std_logic; |
signal owt_idnum : std_logic_vector(4 downto 0); |
signal owt_idbit : std_logic_vector(5 downto 0); |
|
signal id_we : std_logic; |
signal id_ibit : std_logic; |
signal id_obit : std_logic; |
signal id_num : std_logic_vector(4 downto 0); |
signal id_bit : std_logic_vector(5 downto 0); |
|
--byte module signals |
signal ow8_rbit : std_logic; |
signal ow8_wbit : std_logic; |
|
begin |
------------------------------------- |
-- signal decoding --- |
------------------------------------- |
-- ows is the search module, owt is the temp module |
-- rbit, rbyte, wbit, wbyte are the read and write strobes that initiate commands |
-- ibit,obit, ibyte, obyte are the bit and byte input and output values |
|
|
-- the following signals are muxed with priorities, allowing both the temperture and search modules |
-- (owt and ows) to control the one wire interface. |
ow_rbit <= ows_rbit; |
ow_wbit <= ows_wbit when ows_busy = '1' else owt_wbit; |
ow_ibit <= ows_obit when ows_busy = '1' else owt_obit; |
ow_zbit <= ows_zbit when ows_busy = '1' else owt_zbit; |
ow_wbyte <= ows_wbyte when ows_busy = '1' else owt_wbyte; |
ow_ibyte <= ows_obyte when ows_busy = '1' else owt_obyte; |
ow_rbyte <= owt_rbyte; |
id_bit <= ows_idbit when ows_busy = '1' else owt_idbit ; |
id_num <= ows_idnum when ows_busy = '1' else owt_idnum ; |
|
|
------------------------------------- |
-- one wire controller --- |
------------------------------------- |
--ow_mstr - interfaces to the one wire bus, handles reset, rd/wr byte, rd/wr bit |
u_onewire : entity work.ow_mstr(rtl) |
port map ( |
--global signals |
clk => clk, |
srst => srst, |
stb1us => stb1us, -- 1us timing strobe |
busy => ow_busy, --indicates the one wire interface is busy |
init_stb => ow_zbit, --sends an init/reset pulse to bus |
wrbit => ow_wbit, --write a single bit to the bus |
inbit => ow_ibit, --data bit to write |
rdbit => ow_rbit, --read a single bit from the bus |
outbit => ow_obit, --read bit |
wrbyte => ow_wbyte, --write a byte to the bus |
inbyte => ow_ibyte, --data byte to write |
rdbyte => ow_rbyte, --read a byte from the bus |
outbyte => ow_obyte, --read byte |
--one wire bus interface |
owin => owin, --one wire input |
owout => owout --one wire output |
); |
|
------------------------------------- |
-- search controller --- |
------------------------------------- |
--ow_search - searches the one wire bus for all the one wire devices |
-- this detects the ds1820 temp sensors and other devices with 64 bit ids |
u_ows : entity work.ow_search(rtl) |
port map ( |
--global signals |
clk => clk, |
srst => srst, |
start => search_stb, --iniitates the ow bus search for devices |
busyin => ow_busy, --(input) indicates the ow_mstr is busy |
busy => ows_busy, --(output) indicates the search is busy |
error => ows_err, --the search algorithm hit a snag |
--ow1 & ow8 interfaces |
rdbit => ows_rbit, --read command to ow1 |
wrbit => ows_wbit, --write command to ow1 |
zzbit => ows_zbit, --reset pulse command to ow1 |
obit => ows_obit, --write value to ow1 |
ibit => ow_obit, --value read from ow1 |
wrbyte => ows_wbyte, --write command to ow8 |
obyte => ows_obyte, --write value to ow8 |
--id ram interface, |
id_num => ows_idnum, --current device index (0=31) |
id_bit => ows_idbit, --current bit index (0-63) |
id_rbit => id_obit, --bit read from RAM |
id_wbit => id_ibit, --bit written to RAM |
id_we => id_we --write enable to RAM |
|
); |
|
------------------------------------- |
-- temp sensor controller --- |
------------------------------------- |
--ow_temp - handles the temperature reading from devices. |
--performs initialization, conversion start, and read back of results. |
u_owt : entity work.ow_temp(rtl) |
port map ( |
--globals |
clk => clk, |
srst => srst, |
busyin => ow_busy, --(input) os_mstr is busy |
--signals to upper layer hierarchy |
init => temp_init, --command strobe to initialize sensors |
conv => temp_conv, --command strobe to start conversions |
read => temp_read, --command strobe to read the temps |
busy => owt_busy, --(output) temp module is busy |
error => owt_err, --indicates temp module error |
--temp values output on a muxed bus |
temp => temp, --output temp value |
tempidx => tempidx, --temp index |
tempstb => tempstb, --temp strobe |
--ow1 and ow8 interfaces |
zzbit => owt_zbit, --reset pulse command to ow1 |
wrbit => owt_wbit, --write command to ow1 |
obit => owt_obit, --write value to ow1 |
ibit => ow_ibit, --value read from ow1 |
wrbyte => owt_wbyte, --write command to ow8 |
rdbyte => owt_rbyte, --read command to ow8 |
ibyte => ow_obyte, --read value from ow8 |
obyte => owt_obyte, --write value to ow8 |
--id ram interface, |
id_num => owt_idnum, --current device index (0=31) |
id_bit => owt_idbit, --current bit index (0-63) |
id_rbit => id_obit --bit read from RAM |
); |
|
------------------------------------- |
-- ID RAM --- |
------------------------------------- |
-- ow_idram - store and recalls the device ids for devices on the ow bus. |
-- this is implemented in a seperate module to ensure that it uses a internal ram |
-- which greatly reduces the FPGA utilization (saves a lot of FFs and LUTs) |
u_idram : entity work.ow_idram(rtl) |
port map( |
--globals |
clk => clk, |
--srst => srst, |
--ram signals |
mode => ows_busy, --1=search,0=other, used to compute read addresses |
idnum => id_num, --index of the id to read or write |
idbit => id_bit, --index of the bit within the id to read or write |
we => id_we, --write the currently indexed bit |
wdat => id_ibit, --bit value to write to the currently indexed bit |
rdat => id_obit --bit value of the currently indexed bit |
); |
|
-- crc8 - computes the CRC for the ow command and responses. |
-- not yet implemented |
--u_crc : entity work.crc8(rtl) |
--port map ( |
-- clk => clk, |
-- srst => srst, |
-- clken => stb1us, |
-- crcen => owc_en, |
-- crcclr => ow1_init, |
-- rdstb => ow1_rbit, |
-- busyin => ow1_busy, |
-- din => ow1_odat, |
-- crc => owc_crc |
--); |
|
|
err <= ows_err or owt_err; |
busy <= owt_busy or ows_busy; |
|
end rtl; |
/trunk/HDL/ds1820_mstr_tb.vhd
0,0 → 1,318
---------------------------------------------------------------------------------- |
-- <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: ds1820_mstr_tb.vhd |
-- description: Testbench for both the ow_mstr and ds1820_mster modules |
-- |
------------------------------------------------------------------------------------- |
|
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
use IEEE.numeric_std.all; |
use ieee.std_logic_textio.all; |
library std; |
use STD.textio.all; |
|
------------------------------------------------------------------------------------- |
-- Entity declaration |
------------------------------------------------------------------------------------- |
entity ds1820_mstr_tb is |
end ds1820_mstr_tb; |
|
------------------------------------------------------------------------------------- |
-- Architecture declaration |
------------------------------------------------------------------------------------- |
architecture sim of ds1820_mstr_tb is |
|
------------------------------------- |
-- Check Temps Proceedure --- |
------------------------------------- |
--check_temp - proceedure to check the output data, temp and tempidx, against expected values |
procedure check_temp ( |
signal temp : in signed(15 downto 0); --the temp reported from the DUT |
signal idx : in unsigned(4 downto 0); --the index of the sensor (sensor number) from the DUT |
exptemp : in signed(15 downto 0); --expected temperature value |
expidx : in unsigned(4 downto 0)) --expected index value |
is |
variable myline : line; |
variable dec : integer; |
variable frac : integer; |
begin |
--line := ""; |
if idx /= expidx then |
write(myline,string'("Error: wrong idx, expected ")); |
write(myline,to_integer(expidx)); |
write(myline,string'(", got ")); |
write(myline,to_integer(idx)); |
writeline(output,myline); |
assert false report "bad tempidx value" severity error; |
end if; |
if temp /= exptemp then |
--write(output, std_logic_vector(temp)); |
write(myline,string'("Error: wrong temp on sensor ")); |
write(myline,to_integer(expidx)); |
write(myline,string'(", expected ")); |
dec := to_integer(exptemp) / 16; |
frac := ((to_integer(exptemp) - 16*dec)*100)/16; |
write(myline,dec); |
write(myline,string'(".")); |
write(myline,frac); |
write(myline,string'(", got ")); |
dec := to_integer(temp) / 16; |
frac := ((to_integer(temp) - 16*dec)*100)/16; |
write(myline,dec); |
write(myline,string'(".")); |
write(myline,frac); |
write(myline,string'(", got ")); |
writeline(output,myline); |
assert false report "bad temp value" severity error; |
end if; |
end procedure check_temp; |
|
------------------------------------------- |
--- Signal declaration --- |
------------------------------------------- |
constant clkfreqmhz : integer := 100; --clock frequency in mhz |
constant halfperiodns : time := 1000 ns /(clkfreqmhz*2);--half the clock period |
signal clk : std_logic; |
|
constant CONVERSION_TIME : integer := 188; --ADC conversion time in ms |
|
signal srst : std_logic := '0'; --synchronous reset |
signal rst_cntr : unsigned(7 downto 0):= x"ff"; |
signal stb1us_cntr : integer range 1 to clkfreqmhz := 1; --counter used to generate stb1us |
signal stb1us : std_logic := '0'; --strobe 1 us, goes high for one clock every 1 us |
|
signal search_init : std_logic := '0'; --triggers the search module |
signal temp_init : std_logic := '0'; --triggers the initialization module |
signal temp_conv : std_logic := '0'; --triggers the temperature conversion |
signal temp_read : std_logic := '0'; --triggers the reading of the temperature results |
signal ow_busy : std_logic; -- the one wire bus is busy |
signal ow_err : std_logic; --there is an error on the one wire bus |
signal temp : signed(15 downto 0); --signed temp from sensor, value is 16 times the temp in C |
signal tempidx : unsigned(4 downto 0); --index of the current temp sensor |
signal tempstb : std_logic; --strobe to indicate an updated temp sensor value |
signal owin : std_logic; --one wire input to dut |
signal owout : std_logic; --one wire output from dut |
signal dio : std_logic; --one wire bus |
|
begin |
|
------------------------------------- |
-- global timing signals --- |
------------------------------------- |
|
p_osc : process |
begin |
clk <= '0'; |
wait for halfperiodns; |
clk <= '1'; |
wait for halfperiodns; |
end process p_osc; |
|
p_rst : process |
begin |
srst <= '1'; |
wait for 5 us; |
wait until clk = '1'; |
srst <= '0'; |
wait; |
end process p_rst; |
|
--generate a 1 us strobe for timing |
p_stb1us : process(clk) |
begin |
if rising_edge(clk) then |
if srst = '1' then |
stb1us <= '0'; |
stb1us_cntr <= 1; |
else |
if stb1us_cntr = clkfreqmhz then |
stb1us <= '1'; |
stb1us_cntr <= 1; |
else |
stb1us <= '0'; |
stb1us_cntr <= stb1us_cntr + 1; |
end if; |
end if; |
end if; |
end process p_stb1us; |
|
------------------------------------- |
-- DUT --- |
------------------------------------- |
--ow_mstr - DUT (device under test) |
-- one wire master - this performs all the one wire logic |
-- such as configuring and reading the DS1820 devices |
u_dut : entity work.ds1820_mstr(rtl) |
port map( |
--global signals |
clk => clk, |
srst => srst, |
stb1us => stb1us, --1 us strobe |
busy => ow_busy, |
err => ow_err, |
--high level interfaces, lets this module do the heavy lifting. For microprocessor control, |
search_stb => search_init, --searches for devices on bus |
temp_init => temp_init, --initiates temperature read from all devices |
temp_conv => temp_conv, --initiates temperature read from all devices |
temp_read => temp_read, --initiates temperature read from all devices |
temp => temp, --temperatures read from temp devices |
tempidx => tempidx, --temperatures index |
tempstb => tempstb, --temperatures ready strobe |
--one wire bus interface, requires external 5k resistor on bus |
owin => owin, --one wire input |
owout => owout --one wire output |
); |
|
----------------------------------------- |
-- one wire bus, open collector --- |
----------------------------------------- |
--handle in/out nature of one wire interface |
dio <= '0' when owout = '0' else 'Z'; --output, only drives low, tristates when not low, external 5k pullup |
owin <= '0' when dio = '0' else '1'; --input, make sure H,Z,1 all map to '1' for simulation |
dio <= 'H'; --simulates the external pullup resistor |
|
----------------------------------------- |
-- test bench control and checks --- |
----------------------------------------- |
|
--p_control - controls the testing, initiates commands to the DUT |
p_control : process |
begin |
search_init <= '0'; --searches for devices on bus |
temp_init <= '0'; --initiates temperature read from all devices |
temp_conv <= '0'; --initiates temperature read from all devices |
temp_read <= '0'; --initiates temperature read from all devices |
--wait for reset and a bit of time to settle |
wait for 10 us; |
--initiate a search of the one wire devices on the bus |
wait until clk = '0'; |
search_init <= '1'; |
wait until clk = '0'; |
search_init <= '0'; |
wait until clk = '0'; |
--wait for search to complete |
wait until ow_busy = '0'; |
wait until clk = '0'; |
--initialize all the temperature sensors on the bus |
wait until clk = '0'; |
temp_init <= '1'; |
wait until clk = '0'; |
temp_init <= '0'; |
wait until clk = '0'; |
--wait for search to complete |
wait until ow_busy = '0'; |
wait for 5 us; |
--start conversions on all the sensors |
wait until clk = '0'; |
temp_conv <= '1'; |
wait until clk = '0'; |
temp_conv <= '0'; |
wait until clk = '0'; |
--wait for conversion commands to complete |
wait until ow_busy = '0'; |
--now wait until the conversions are actually complete |
wait for 190 ms; |
--read the temp from all the sensors |
wait until clk = '0'; |
temp_read <= '1'; |
wait until clk = '0'; |
temp_read <= '0'; |
wait until clk = '0'; |
--wait for all reads to take place |
wait until ow_busy = '0'; |
wait until clk = '0'; |
--now wait until the conversions are actually complete |
wait; |
end process p_control; |
|
--p_check - checks the output of the DUT and alerts if it is incorrect |
p_check : process |
variable exptemp : signed(15 downto 0); |
variable expidx : unsigned(4 downto 0); |
begin |
--check data from sensor 1 |
wait until tempstb = '1'; |
exptemp := to_signed(-24,16); -- -1.5C |
expidx := to_unsigned(0,5); |
check_temp(temp,tempidx,exptemp,expidx); |
--check data from sensor 2 |
wait until tempstb = '1'; |
exptemp := to_signed(1844,16); -- +115.25C |
expidx := to_unsigned(1,5); |
check_temp(temp,tempidx,exptemp,expidx); |
--check data from sensor 2 |
wait until tempstb = '1'; |
exptemp := to_signed(916,16); -- +57.25C |
expidx := to_unsigned(2,5); |
check_temp(temp,tempidx,exptemp,expidx); |
wait for 5 us; |
assert false report "Test completed" severity note; |
wait; |
end process; |
|
p_error : process |
begin |
wait until ow_err = '1'; |
assert true report "Bus error reported" severity error; |
end process; |
|
-------------------------------------------- |
-- Simulated OW bus devices, ds1820 --- |
-------------------------------------------- |
--simulated temperature sensor |
u_ds18b20_1 : entity work.ds18b20_sim(sim) |
generic map ( |
timing => "min", |
devid => x"00a0458d3ea2be28" |
) |
port map ( |
--dio => dio1, |
pwrin => '1', |
dio => dio, |
tempin => -1.54 |
); |
|
--simulated temperature sensor |
u_ds18b20_2 : entity work.ds18b20_sim(sim) |
generic map ( |
timing => "min", |
devid => x"002984456a32bf28" |
) |
port map ( |
--dio => dio2, |
pwrin => '1', |
dio => dio, |
tempin => 115.3 |
); |
|
--simulated temperature sensor |
u_ds18b20_3 : entity work.ds18b20_sim(sim) |
generic map ( |
timing => "min", |
devid => x"0083726dab32bf28" |
) |
port map ( |
--dio => dio3, |
pwrin => '1', |
dio => dio, |
tempin => 57.25 |
); |
|
end sim; |
/trunk/HDL/ds18b20_sim.vhd
0,0 → 1,676
---------------------------------------------------------------------------------- |
-- <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: ds18b20_sim.vhd |
-- description: A simulation model for the DS18B20 temperature probe |
-- |
-- Generics are used to set the device ID, the NVROM, and the timing model |
-- inputs are used to set the temperature to report back |
-- |
-- This only simulates the SEARCH, ROM, SKIP, CONFIG, CONV, and READ commands |
-- save and recall to/from EEPROM were started, but not tested |
-- it is not a complete model. It does not validate timing. |
----------------------------- |
|
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
|
------------------------------------------------------------------------------------- |
-- Entity declaration |
------------------------------------------------------------------------------------- |
entity ds18b20_sim is |
generic ( |
timing : in string := "ave"; |
devid : in std_logic_vector(63 downto 0) := x"0000000000000128"; |
nvrom : in std_logic_vector(23 downto 0) := x"3f0064" |
); |
port ( |
--global signals |
pwrin : in std_logic; --tie to '1' if power provided, '0' if using parasitic power |
tempin : in real; |
dio : inout std_logic --synchronous reset |
); |
end ds18b20_sim; |
|
|
--library unisim; |
--use unisim.vcomponents.all; |
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
use IEEE.numeric_std.all; |
library work; |
|
architecture sim of ds18b20_sim is |
|
--low time to trigger a reaset |
constant tmin_rstl : time := 240 us; |
constant tave_rstl : time := 400 us; |
constant tmax_rstl : time := 480 us; |
signal trstl : time := tmin_rstl; |
--high time between reset pulse and presence pulse |
signal tpdih : time; |
constant tmin_pdih : time := 15 us; |
constant tave_pdih : time := 45 us; |
constant tmax_pdih : time := 60 us; |
--presence pulse low time |
signal tpdlo : time; |
constant tmin_pdlo : time := 60 us; |
constant tave_pdlo : time := 180 us; |
constant tmax_pdlo : time := 240 us; |
--write 0 low time |
signal tlow0 : time; |
constant tmin_low0 : time := 60 us; |
constant tave_low0 : time := 100 us; |
constant tmax_low0 : time := 120 us; |
--write 1 low time |
signal tlow1 : time; |
constant tmin_low1 : time := 1 us; |
constant tave_low1 : time := 10 us; |
constant tmax_low1 : time := 15 us; |
--master write data sample time |
signal tsamp : time := 1 us; |
constant tmin_samp : time := 15 us; |
constant tave_samp : time := 30 us; |
constant tmax_samp : time := 60 us; |
--slave read recovery time |
signal trec : time := 1 us; |
constant tmin_rec : time := 1 us; |
constant tave_rec : time := 3 us; |
constant tmax_rec : time := 6 us; |
--slave read data valid time |
signal trdv : time := 15 us; |
constant tmin_rdv : time := 15 us; |
constant tave_rdv : time := 30 us; |
constant tmax_rdv : time := 60 us; |
|
--recall from eeprom timing |
--note: dallas part does not spec this timing |
signal trecall : time := 100 us; |
|
--convert time |
signal tconv : time := 15 us; |
signal tconv9 : time := 15 us; |
constant tmax_conv9 : time := 93.75 us; |
constant tave_conv9 : time := tmax_conv9 * 2/3; |
constant tmin_conv9 : time := tmax_conv9 * 1/2; |
signal tconv10 : time := 15 us; |
constant tmax_conv10 : time := 93.75 us; |
constant tave_conv10 : time := tmax_conv10 * 2/3; |
constant tmin_conv10 : time := tmax_conv10 * 1/2; |
signal tconv11 : time := 15 us; |
constant tmax_conv11 : time := 93.75 us; |
constant tave_conv11 : time := tmax_conv11 * 2/3; |
constant tmin_conv11 : time := tmax_conv11 * 1/2; |
signal tconv12 : time := 15 us; |
constant tmax_conv12 : time := 93.75 us; |
constant tave_conv12 : time := tmax_conv12 * 2/3; |
constant tmin_conv12 : time := tmax_conv12 * 1/2; |
signal tcopy : time := 1 us; |
constant tmax_copy : time := 10 ms; |
constant tave_copy : time := 2 ms; |
constant tmin_copy : time := 1 ms; |
|
signal clk10m : std_logic; |
signal rstdet : std_logic := '0'; --indicates a detected a reset pulse from the master |
signal trise : time := now; |
signal tfall : time := now; |
signal rstdly : std_logic := '1'; |
--signal tdif : time; |
signal timertime : time; |
signal timer : unsigned(15 downto 0); |
signal timertrig : std_logic := '0'; |
signal timerdone : std_logic := '1'; |
|
|
type state_type is (S_IDLE, S_RSTRESP,S_RSTRESP2,S_RSTRESP3, |
S_GETBYTE, S_GETBYTE2, S_PARSE, |
S_READROM, S_READROM2, S_SRCHROM, S_SRCHROMNOT, S_SRCHROMWR, |
S_MATCHROM, S_MATCHROM2, S_SRCHALARM, S_SKIPROM, |
S_PARSE2, S_CONV, S_COPY, S_WRITE1, S_WRITE2, S_WRITE3, |
S_READ, S_READRCVR, S_CRC, S_RECALL, S_RDPWR, |
S_START, S_MID, S_END); |
signal state : state_type := S_IDLE; |
signal nxt_state : state_type := S_IDLE; |
signal dout : std_logic := 'Z'; --read output bit from slave to master |
signal rstdout : std_logic := '1'; --read output bit from main process |
signal recalldout : std_logic := '1'; --read output bit from recall process |
signal copydout : std_logic := '1'; --read output bit from copy process |
signal convdout : std_logic := '1'; --read output bit from conv process |
signal readdout : std_logic := '1'; -- output data from read state machine |
signal din : std_logic := '1'; --resolved input data bit |
--signal rstout : std_logic := 'Z'; |
signal bitcnt : integer; |
signal shiftbyte : std_logic_vector(7 downto 0); |
signal shiftid : std_logic_vector(63 downto 0); |
signal busy : std_logic := '0'; |
|
--These signals are for the read state machine |
signal bitout : std_logic := '1'; --bit value to be read by master |
signal wrbitin : std_logic := '0'; -- the bit value written by the master |
signal wrbiterr : std_logic := '0'; -- indicates a master write pulse with an illegal timing |
signal writedet : std_logic := '0'; -- strobe indicating the master wrote a bit |
signal readen : std_logic := '0'; --enables the slave responses to the master read pulses |
signal readdet : std_logic := '0'; -- strobe indicating the master read a bit |
signal readdly : std_logic := '0'; -- delayed version of din for detecting read strobes |
signal readbit : std_logic := '0'; -- data to output from read state machine |
--signal readbit : std_logic := '0'; -- bit to drive the read output |
|
signal res : integer range 9 to 12; --high alram value in volatile mem |
signal alarmhi : std_logic := '0'; |
signal alarmlo : std_logic := '0'; |
signal trighi : std_logic_vector(7 downto 0) := nvrom(7 downto 0); |
signal triglo : std_logic_vector(7 downto 0) := nvrom(15 downto 8); |
--signal temp : std_logic_vector(15 downto 0); --last temperature conversion |
signal slvtemp : std_logic_vector(15 downto 0) := x"0190"; --the temperature read from device, default to 25C |
signal config : std_logic_vector(7 downto 0) := nvrom(23 downto 16); |
signal convtrig : std_logic := '0'; |
signal convdone : std_logic := '1'; |
signal copytrig : std_logic := '0'; |
signal copydone : std_logic := '1'; |
signal recalltrig : std_logic := '0'; |
signal recalldone : std_logic := '1'; |
signal eeprom : std_logic_vector(23 downto 0) := nvrom; |
signal scratch : std_logic_vector(63 downto 0) := x"1000ff" & nvrom & x"0000"; |
|
signal crc : std_logic_vector(7 downto 0); |
begin |
trstl <= tmin_rstl when timing = "MIN" else tave_rstl when timing = "AVE" else tmax_rstl; |
tpdih <= tmin_pdih when timing = "MIN" else tave_pdih when timing = "AVE" else tmax_pdih; |
tpdlo <= tmin_pdlo when timing = "MIN" else tave_pdlo when timing = "AVE" else tmax_pdlo; |
tsamp <= tmin_samp when timing = "MIN" else tave_samp when timing = "AVE" else tmax_samp; |
trdv <= tmin_rdv when timing = "MIN" else tave_rdv when timing = "AVE" else tmax_rdv; |
tconv9 <= tmin_conv9 when timing = "MIN" else tave_conv9 when timing = "AVE" else tmax_conv9; |
tconv10 <= tmin_conv10 when timing = "MIN" else tave_conv10 when timing = "AVE" else tmax_conv10; |
tconv11 <= tmin_conv11 when timing = "MIN" else tave_conv11 when timing = "AVE" else tmax_conv11; |
tconv12 <= tmin_conv12 when timing = "MIN" else tave_conv12 when timing = "AVE" else tmax_conv12; |
tconv <= tconv9 when res = 9 else tconv10 when res=10 else tconv11 when res = 11 else tconv12; |
tcopy <= tmin_copy when timing = "MIN" else tave_copy when timing = "AVE" else tmax_copy; |
--rstdly <= dio after trstl; |
--rst <= '1' when rstdly = '0' and dio = '0' else '1'; |
|
res <= 9 + to_integer(unsigned(config(6 downto 5))); |
|
p_clk10m : process |
begin |
clk10m <= '0'; |
wait for 50 ns; |
clk10m <= '1'; |
wait for 50 ns; |
end process; |
|
p_edges : process |
begin |
wait until din = '0'; |
tfall <= now; |
wait until din = '1'; |
trise <= now; |
end process; |
|
|
--this handles the master reseting this slave |
rstdly <= transport din after trstl; |
|
p_rst : process |
begin |
wait until rstdly = '0'; |
--if last transition was falling edge and it was long ago... |
if tfall > trise and now - tfall >= trstl then |
rstdet <= '1'; |
wait until din <= '1'; |
rstdet <= '0'; |
end if; |
end process; |
|
--p_readstb and p_read - work together to facilitate a read |
-- readen is set high to enable a read, then if din is low for 1 us the readdet signal triggers |
-- which causes readout to be driven low for a bit time if shift(0) is low |
-- after the bit time expires, din returns high, causing readdet to go low, and cycle is complete |
readdly <= transport din after 1us; |
p_readstb : process |
begin |
wait until readdly = '0'; |
if tfall > trise and now - tfall >= 1us and readen = '1' then |
readdet <= '1'; |
wait until din <= '1'; |
readdet <= '0'; |
end if; |
end process; |
|
p_read : process |
begin |
wait until readdet = '1' and readen = '1'; |
readdout <= readbit; |
wait for trdv; |
readdout <= '1'; |
end process; |
|
--this handles the master writing bits to this slave |
p_write : process |
begin |
wait until din = '1'; |
--dont detect writes during read operations |
if readen = '0' and readdet = '0' then |
if now - tfall > tmin_low0 and now-tfall < tmax_low0 then |
wrbitin <= '0'; |
writedet <= '1'; |
wrbiterr <= '0'; |
elsif now - tfall > tmin_low1 and now-tfall < tmax_low1 then |
wrbitin <= '1'; |
writedet <= '1'; |
wrbiterr <= '0'; |
elsif now - tfall < trstl then |
wrbiterr <= '1'; |
end if; |
end if; |
wait until din = '0'; |
writedet <= '0'; |
end process; |
|
|
p_timer : process(clk10m) |
begin |
if rising_edge(clk10m) then |
if timertrig = '1' then |
timer <= to_unsigned(integer(timertime/100 ns),16); |
timerdone <= '0'; |
elsif timer > 1 then |
timer <= timer -1; |
else |
timerdone <= '1'; |
end if; |
end if; |
end process; |
|
--this handles the master reading a bit from this slave |
--dout <= '0' when rdbiten = '1' and dout = '0' and now-tfall < trdv else '1'; |
|
p_state :process(clk10m) |
begin |
if rising_edge (clk10m) then |
if rstdet = '1' then |
state <= S_RSTRESP; |
rstdout <= '1'; |
readen <= '0'; |
else |
case state is |
when S_IDLE => |
rstdout <= '1'; |
readen <= '0'; |
bitcnt <= 0; |
convtrig <= '0'; |
copytrig <= '0'; |
recalltrig <= '0'; |
shiftbyte <= x"00"; |
shiftid <= devid; |
when S_RSTRESP => |
readen <= '0'; |
bitcnt <= 0; |
rstdout <= '1'; |
shiftbyte <= x"00"; |
shiftid <= devid; |
if timertrig = '0' and din = '1' then |
timertime <= tpdih; |
timertrig <= '1'; |
elsif timertrig = '1' then |
timertrig <= '0'; |
state <= S_RSTRESP2; |
end if; |
when S_RSTRESP2 => |
if timertrig = '0' and timerdone = '1' then |
rstdout <= '0'; |
timertime <= tpdlo; |
timertrig <= '1'; |
elsif timertrig = '1' then |
timertrig <= '0'; |
state <= S_RSTRESP3; |
end if; |
when S_RSTRESP3 => |
if timerdone = '1' then |
rstdout <= '1'; |
state <= S_GETBYTE; |
nxt_state <= S_PARSE; |
end if; |
when S_GETBYTE => |
if writedet = '0' then |
state <= S_GETBYTE2; |
end if; |
when S_GETBYTE2 => |
if writedet = '1' then |
shiftbyte <= wrbitin & shiftbyte(7 downto 1); |
if bitcnt < 7 then |
bitcnt <= bitcnt + 1; |
state <= S_GETBYTE; |
else |
bitcnt <= 0; |
state <= nxt_state; |
end if; |
end if; |
when S_PARSE => |
shiftid <= devid; |
case shiftbyte is |
when x"33" => --read the rom id from the device, can only be used on single device bus |
state <= S_READROM; |
when x"55" => --match rom, used to address a single device on the bus |
state <= S_MATCHROM; |
when x"F0" => --use to find the devices on a multiple device bus |
state <= S_SRCHROM; |
when x"EC" => --search alarm, used to find devices that have active alarms |
if alarmhi = '1' or alarmlo = '1' then |
state <= S_SRCHROM; |
else |
state <= S_IDLE; |
end if; |
when x"CC" => --skip rom, skips rom addressing, for single device busses or broadcast commands |
state <= S_GETBYTE; |
nxt_state <= S_PARSE2; |
when others => |
state <= S_IDLE; |
end case; |
when S_READROM => |
readen <= '1'; |
if readdet = '1' then |
shiftid <= shiftid(0) & shiftid(63 downto 1); |
if bitcnt < 55 then |
bitcnt <= bitcnt + 1; |
state <= S_READRCVR; |
nxt_state <= S_READROM; |
else |
state <= S_CRC; |
nxt_state <= S_READROM2; |
shiftid <= x"00000000000000" & crc; |
end if; |
end if; |
when S_READROM2 => |
state <= S_GETBYTE; |
nxt_state <= S_PARSE2; |
when S_MATCHROM => |
if writedet = '0' then |
state <= S_MATCHROM2; |
end if; |
when S_MATCHROM2 => |
if writedet = '1' then |
if wrbitin /= shiftid(0) then |
state <= S_IDLE; --this part is removed from search, goto idle, wait for rstdet |
else |
shiftid <= shiftid(0) & shiftid(63 downto 1); |
if bitcnt < 63 then |
bitcnt <= bitcnt + 1; |
state <= S_MATCHROM; |
else |
bitcnt <= 0; |
state <= S_GETBYTE; |
nxt_state <= S_PARSE2; |
end if; |
end if; |
end if; |
when S_SRCHROM => |
readen <= '1'; |
readbit <= shiftid(0); |
if readdet = '1' then |
state <= S_READRCVR; |
nxt_state <= S_SRCHROMNOT; |
end if; |
when S_SRCHROMNOT => |
readen <= '1'; |
readbit <= not shiftid(0); |
if readdet = '1' then |
state <= S_READRCVR; |
nxt_state <= S_SRCHROMWR; |
end if; |
when S_SRCHROMWR => |
readen <= '0'; |
if writedet = '1' then |
if wrbitin /= shiftid(0) then |
state <= S_IDLE; --this part is removed from search, goto idle, wait for rstdet |
else |
shiftid <= shiftid(0) & shiftid(63 downto 1); |
if bitcnt < 63 then |
bitcnt <= bitcnt + 1; |
state <= S_SRCHROM; |
else |
bitcnt <= 0; |
state <= S_GETBYTE; |
nxt_state <= S_PARSE2; |
end if; |
end if; |
end if; |
when S_PARSE2 => |
case shiftbyte is |
when x"44" => --convert temp |
convtrig <= '1'; |
state <= S_CONV; |
when x"48" => --copy scratchpad to eeprom |
copytrig <= '1'; |
state <= S_COPY; |
when x"4e" => --write scratchpad |
state <= S_GETBYTE; -- data in order is Thi,Tlo,config |
nxt_state <= S_WRITE1; |
when x"be" => --read scratchpad |
state <= S_READ; --data in order is TempLSB,TempMSB,AlarmHi,AlarmLo,config,FF,00,F0,CRC |
shiftid <= x"1000ff" & config & trighi & triglo & slvtemp; |
bitcnt <= 0; |
when x"b8" => --recall scratchpad from eeprom |
recalltrig <= '1'; |
state <= S_RECALL; |
when x"b4" => --read the power bit to determine if parasitic;y powered |
state <= S_RDPWR; |
when others => |
state <= S_IDLE; |
end case; |
when S_CONV => |
if convtrig = '1' then |
convtrig <= '0'; |
elsif convdone = '1' then |
state <= S_IDLE; |
end if; |
when S_COPY => |
if copytrig = '1' then |
copytrig <= '0'; |
elsif copydone = '1' then |
state <= S_IDLE; |
end if; |
when S_WRITE1 => |
scratch(7 downto 0) <= shiftbyte; |
state <= S_GETBYTE; |
nxt_state <= S_WRITE2; |
when S_WRITE2 => |
scratch(15 downto 8) <= shiftbyte; |
state <= S_GETBYTE; |
nxt_state <= S_WRITE3; |
when S_WRITE3 => |
scratch(23 downto 16) <= '0' & shiftbyte(6 downto 5) & "11111"; |
state <= S_IDLE; |
when S_RECALL => |
if recalltrig = '1' then |
recalltrig <= '0'; |
elsif recalldone = '1' then |
config <= eeprom(23 downto 16); |
trighi <= eeprom(15 downto 8); |
triglo <= eeprom(7 downto 0); |
state <= S_IDLE; |
end if; |
when S_READ => |
readen <= '1'; |
readbit <= shiftid(0); |
if readdet = '1' then |
shiftid <= shiftid(0) & shiftid(63 downto 1); |
if bitcnt < 63 then |
bitcnt <= bitcnt + 1; |
state <= S_READRCVR; |
nxt_state <= S_READ; |
else |
state <= S_CRC; |
nxt_state <= S_IDLE; |
bitcnt <= 0; |
shiftid <= x"00000000000000" & crc; |
end if; |
end if; |
when S_READRCVR => |
readen <= '0'; |
if readdet = '0' then |
state <= nxt_state; |
end if; |
when S_RDPWR => |
readen <= '1'; |
if readdet = '1' then |
state <= S_READRCVR; |
nxt_state <= S_IDLE; |
end if; |
when S_CRC => |
readen <= '1'; |
if readdet = '1' then |
shiftid <= shiftid(0) & shiftid(63 downto 1); |
if bitcnt < 7 then |
bitcnt <= bitcnt + 1; |
state <= S_READRCVR; |
nxt_state <= S_READ; |
else |
state <= S_READRCVR; |
nxt_state <= S_IDLE; |
bitcnt <= 0; |
shiftid <= x"00000000000000" & crc; |
end if; |
end if; |
when others => |
state <= S_IDLE; |
end case; |
end if; |
end if; |
end process; |
|
p_crc : process |
begin |
crc <= x"00"; |
wait until state = S_READ or state = S_READROM; |
crc <= x"00"; |
while state = S_READ or state = S_READROM loop |
wait until din = '0' or (state /= S_READ and state /= S_READROM); |
if din = '0' then |
if (crc(0) xor shiftid(0)) = '1' then |
crc <= ('0' & crc(7 downto 1)) xor x"8c"; |
else |
crc <= ('0' & crc(7 downto 1)); |
end if; |
end if; |
end loop; |
end process; |
|
|
p_convert : process |
variable tstart : time := 0 us; |
begin |
convdout <= '1'; |
convdone <= '1'; |
wait until convtrig = '1'; |
convdone <= '0'; |
tstart := now; |
while state = S_CONV loop |
assert (din = '1' or pwrin = '1') report "power fail during parasitic powered conversion" severity error; |
wait for 1 us; |
if now - tstart > tconv then |
convdone <= '1'; |
if res = 9 then |
slvtemp <= std_logic_vector(to_signed(integer(tempin*2.0),13)) &"000"; |
elsif res = 10 then |
slvtemp <= std_logic_vector(to_signed(integer(tempin*4.0),14)) &"00"; |
elsif res = 11 then |
slvtemp <= std_logic_vector(to_signed(integer(tempin*8.0),15)) &'0'; |
else |
slvtemp <= std_logic_vector(to_signed(integer(tempin*16.0),16)); |
end if; |
if signed(slvtemp(11 downto 4)) < signed(trighi) then |
alarmhi <= '0'; |
else |
alarmhi <= '1'; |
end if; |
if signed(slvtemp(11 downto 4)) > signed(triglo) then |
alarmlo <= '0'; |
else |
alarmlo <= '1'; |
end if; |
elsif rstdet = '1' then |
convdone <= '1'; |
elsif din = '0' and pwrin = '1' then |
--master is reading convert ready bit |
wait for 1 us; |
convdout <= '0'; |
wait for trdv; |
convdout <= '1'; |
end if; |
end loop; |
end process; |
|
p_copy : process |
variable tstart : time := 0 us; |
begin |
copydout <= '1'; |
wait until copytrig = '1'; |
copydone <= '0'; |
tstart := now; |
wait for 10 us; |
while state = S_COPY loop |
assert (din = '1' or pwrin = '1') report "power fail during parasitic powered copy to eeprom" severity error; |
wait for 1 us; |
if now - tstart > tcopy then |
copydone <= '1'; |
eeprom <= config & trighi & triglo; |
elsif rstdet = '1' then |
copydone <= '1'; |
elsif din = '0' then |
--master is reading copy ready bit |
wait for 1 us; |
copydout <= '0'; |
wait for trdv; |
copydout <= '1'; |
end if; |
end loop; |
end process; |
|
|
|
p_recall : process |
variable tstart : time := 0 us; |
begin |
recalldout <= '1'; |
wait until recalltrig = '1'; |
recalldone <= '0'; |
tstart := now; |
wait for 10 us; |
while state = S_RECALL loop |
assert (din = '1' or pwrin = '1') report "power fail during parasitic recall from eeprom" severity error; |
wait for 1 us; |
if now - tstart > trecall then |
recalldone <= '1'; |
elsif rstdet = '1' then |
recalldone <= '1'; |
elsif din = '0' then |
--master is reading recall ready bit |
wait for 1 us; |
recalldout <= '0'; |
wait for trdv; |
recalldout <= '1'; |
end if; |
end loop; |
end process; |
|
din <= '0' when dio = '0' else '1'; |
dout <= rstdout and copydout and convdout and recalldout and readdout; |
dio <= '0' when dout = '0' else 'Z'; |
busy <= '0' when state = S_IDLE else '1'; |
|
end sim; |
/trunk/HDL/ow_bit.vhd
0,0 → 1,231
---------------------------------------------------------------------------------- |
-- <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: onewire_bit.vhd |
-- description: handles single bit transactions on the one wire bus |
-- it is used by higher level entities to initialize, search, read, and write the one |
-- wire devices on the one wire bus. |
-- Each operation consists of a start, that is always low, middle, which for reads |
-- represents the time for the slave to respond, and the end, which allows for |
-- the slave to finish its operation and provides spacing between bit patterns. |
-- For reads and resets, the data is sampled at the end of the mid time |
-- |
----------------------------- |
|
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
use IEEE.numeric_std.all; |
library work; |
|
------------------------------------------------------------------------------------- |
-- Entity declaration |
------------------------------------------------------------------------------------- |
entity ow_bit is |
port ( |
--globals |
clk : in std_logic; |
srst : in std_logic; |
clken : in std_logic; |
--interface to higher level |
rstb : in std_logic; |
wstb : in std_logic; |
istb : in std_logic; |
din : in std_logic; |
dout : out std_logic; |
busy : out std_logic; |
--one wire bus |
owout : out std_logic; --one wire input |
owin : in std_logic --one wire output |
); |
end ow_bit; |
|
------------------------------------------------------------------------------------- |
-- Architecture declaration |
------------------------------------------------------------------------------------- |
architecture rtl of ow_bit is |
type pulse_state_type is (S_IDLE, S_START, S_MID, S_END); --, S_DONE |
signal pulse_state : pulse_state_type := S_IDLE; |
|
|
constant r_start : unsigned(11 downto 0) := to_unsigned(5,12); --low time |
constant r_mid : unsigned(11 downto 0) := to_unsigned(10,12); --high z until sample time |
constant r_end : unsigned(11 downto 0) := to_unsigned(65,12); --recovery time |
constant w_start : unsigned(11 downto 0) := to_unsigned(5,12); --low time |
constant w_mid : unsigned(11 downto 0) := to_unsigned(65,12); --dout time |
constant w_end : unsigned(11 downto 0) := to_unsigned(10,12); --recovery time |
constant rw_cnt : unsigned(11 downto 0) := to_unsigned(1,12); --number of samples for read or write |
constant i_start : unsigned(11 downto 0) := to_unsigned(500,12); --reset low time |
constant i_mid : unsigned(11 downto 0) := to_unsigned(100,12); --high z till sample time |
constant i_end : unsigned(11 downto 0) := to_unsigned(220,12); --recovery time till end of rst response |
constant i_cnt : unsigned(3 downto 0) := to_unsigned(1,4); --number of samples (i_end each) to wait for init response |
|
signal start_time : unsigned(11 downto 0); -- low pulse time |
signal mid_time : unsigned(11 downto 0); -- high pulse time |
signal end_time : unsigned(11 downto 0); -- time between samples, or the last sample and the end |
--signal rd_count : unsigned(4 downto 0) := to_unsigned(30,5); -- number of read smaples for this bit |
|
|
signal owo : std_logic := '0'; --one wire output bit |
--signal owo2 : std_logic := '0'; --one wire output bit combined with one wire power |
--signal owi : std_logic := '0'; --one wire input bit |
--signal owt : std_logic := '0'; --one wire tristate, implements open collector bus |
signal wstb_cap : std_logic := '0'; --captures and holds write requests |
signal rstb_cap : std_logic := '0'; --captures and holds read requests |
signal istb_cap : std_logic := '0'; --captures and holds init requests (reset/presence sequence) |
signal din_cap : std_logic := '0'; --captures and holds input data |
signal pulse_end : std_logic; |
signal busy_int : std_logic; |
signal timer : unsigned(11 downto 0) := x"000"; --used to time one wire bus transactions |
--signal rdcntr : unsigned(4 downto 0); --used to count samples in the read mode |
--signal owopwr : std_logic; --internal state of dout combined with power input |
signal samp : std_logic; --AND'ed value of owi samples |
|
attribute mark_debug : string; |
attribute mark_debug of pulse_state : signal is "true"; |
attribute mark_debug of timer : signal is "true"; |
attribute mark_debug of samp : signal is "true"; |
attribute mark_debug of din : signal is "true"; |
attribute mark_debug of dout : signal is "true"; |
attribute mark_debug of rstb_cap: signal is "true"; |
attribute mark_debug of wstb_cap : signal is "true"; |
attribute mark_debug of istb_cap : signal is "true"; |
attribute mark_debug of busy_int : signal is "true"; |
attribute mark_debug of pulse_end : signal is "true"; |
|
|
begin |
------------------------------------- |
-- strobe captures --- |
------------------------------------- |
-- p_capstb - captures the pulse strobes, and clears then when the pulse is complete |
-- this is necessary if the clken is used because the strobes happen on the system clk and |
-- the pulse is timed by the stb1us. We need to hold the strobes throughout the pulse because the active |
-- strobe is used to zelect the timing for the pulse. |
p_capstb : process (clk) |
begin |
if rising_edge(clk) then |
if srst = '1' then |
rstb_cap <= '0'; |
wstb_cap <= '0'; |
istb_cap <= '0'; |
din_cap <= '0'; |
elsif busy_int = '0' then |
if rstb = '1' then |
rstb_cap <= '1'; |
elsif wstb = '1' then |
wstb_cap <= '1'; |
din_cap <= din; |
elsif istb = '1' then |
istb_cap <= '1'; |
end if; |
elsif pulse_state = S_END then |
rstb_cap <= '0'; |
wstb_cap <= '0'; |
istb_cap <= '0'; |
din_cap <= '0'; |
end if; |
end if; |
end process p_capstb; |
|
------------------------------------- |
-- control muxing --- |
------------------------------------- |
--busy_int indicates that a pulse is pending (one of the strobe captures is high) or the pulse is active |
busy_int <= '0' when rstb_cap = '0' and wstb_cap = '0' and istb_cap = '0' |
and pulse_state = S_IDLE |
else '1'; |
|
start_time <= w_start when wstb_cap = '1' else i_start when istb_cap = '1' else r_start; |
mid_time <= w_mid when wstb_cap = '1' else i_mid when istb_cap = '1' else r_mid; |
end_time <= w_end when wstb_cap = '1' else i_end when istb_cap = '1' else r_end; |
|
|
------------------------------------- |
-- pulse generator --- |
------------------------------------- |
--p_pulse - generates the pulse, and if needed captures the read bit or read presence pulse |
-- all pulses consist of a start time, a middle time, and an end time. |
-- for read, write, and init, the start time is always low, and starts the timing for the pulse |
-- for a read or init, the middle time is used for the slave to react. data is sampled at the end of the mid time |
-- for the write, the middle time is where the actual data, zero or one, is output. |
-- the end time is used to space between pulses. |
-- |start| middle |end| |
-- Write one ----_____------------- |
-- Write zero ----______________---- |
-- read ----_____xxxxxxxxx---- |
-- init ----_____---------____ |
p_pulse : process (clk) |
begin |
if rising_edge(clk) then |
if srst = '1' then |
pulse_state <= S_IDLE; |
timer <= x"000"; |
--rdcntr <= "00000"; |
owo <= '1'; |
samp <= '1'; |
elsif clken = '1' then |
case pulse_state is |
when S_IDLE => |
samp <= '1'; |
if busy_int = '1' then |
pulse_state <= S_START; |
timer <= start_time; |
owo <= '0'; |
end if; |
when S_START => |
if timer > 0 then |
timer <= timer -1; |
else |
if wstb_cap = '1' then |
owo <= din_cap; |
else |
owo <= '1'; |
end if; |
timer <= mid_time; |
pulse_state <= S_MID; |
end if; |
when S_MID => |
if timer > 0 then |
timer <= timer -1; |
else |
samp <= owin; |
timer <= end_time; |
--rdcntr <= rd_count; |
pulse_state <= S_END; |
owo <= '1'; |
end if; |
when S_END => |
if timer > 0 then |
timer <= timer -1; |
else |
pulse_state <= S_IDLE; |
end if; |
--when S_DONE => |
-- pulse_state <= S_IDLE; |
end case; |
end if; |
end if; |
end process p_pulse; |
|
dout <= samp; --this is the value read back from a read pulse or a reset pulse |
busy <= busy_int or rstb or wstb or istb; |
|
--The output is driven high when pwr = 1, otherwise is only driven low when owo is low |
owout <= owo; |
|
end rtl; |
/trunk/HDL/ow_byte.vhd
0,0 → 1,136
---------------------------------------------------------------------------------- |
-- <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_byte.vhd |
-- description: handles read and write byte operations on the one wire bus |
-- |
----------------------------- |
|
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
use IEEE.numeric_std.all; |
library work; |
|
------------------------------------------------------------------------------------- |
-- Entity declaration |
------------------------------------------------------------------------------------- |
entity ow_byte is |
port ( |
--globals |
clk : in std_logic; |
srst : in std_logic; |
--clken : in std_logic; |
--ow1 interface |
rdbit : out std_logic; -- rd bit strobe |
wrbit : out std_logic; -- wr bit strobe |
ibit : in std_logic; -- rd bit data |
obit : out std_logic; -- wr bit data |
busyin : in std_logic; -- busy from the bit interface |
--high level interface to owt,owi, or external |
rdbyte : in std_logic; -- read byte strobe |
obyte : out std_logic_vector(7 downto 0); -- result of the byte read |
wrbyte : in std_logic; -- write byte strobe |
ibyte : in std_logic_vector(7 downto 0); -- write data |
busy : out std_logic -- busy signal the to external modules |
); |
end ow_byte; |
|
------------------------------------------------------------------------------------- |
-- Architecture declaration |
------------------------------------------------------------------------------------- |
architecture rtl of ow_byte is |
type state_type is (S_IDLE, S_STROBE, S_SHIFT); |
signal state : state_type := S_IDLE; |
|
signal bitcnt : integer range 0 to 7 := 0; --counts the bytes during the transfer |
signal shift : std_logic_vector(7 downto 0); -- used to shift in and out data |
signal rdwr_n : std_logic; -- 1 for read, 0 for write |
signal irdbit : std_logic; -- internal state of rdbit strobe |
signal iwrbit : std_logic; -- internal state of wrbit strobe |
|
attribute mark_debug : string; |
attribute mark_debug of state : signal is "true"; |
attribute mark_debug of rdwr_n : signal is "true"; |
attribute mark_debug of shift : signal is "true"; |
attribute mark_debug of bitcnt : signal is "true"; |
attribute mark_debug of irdbit : signal is "true"; |
attribute mark_debug of iwrbit : signal is "true"; |
|
begin |
------------------------------------- |
-- bit shifter --- |
------------------------------------- |
-- p_shifty - shifts data in and out the shift register, and counts down bits |
p_shifty : process (clk) |
begin |
if rising_edge(clk) then |
if srst = '1' then |
shift <= (others => '0'); |
bitcnt <= 0; |
rdwr_n <= '1'; |
irdbit <= '0'; |
iwrbit<= '0'; |
state <= S_IDLE; |
else |
case state is |
when S_IDLE => |
--wait for read byte or write byte strobe |
if busyin = '0' and (rdbyte = '1' or wrbyte = '1') then |
rdwr_n <= rdbyte; --remember whether it was read or write |
shift <= ibyte; --load the byte to shift out(not needed for read) |
bitcnt <= 0; --set bit counter |
state <= S_STROBE; |
end if; |
when S_STROBE => |
if irdbit = '0' and iwrbit = '0' then |
--if we havent started the read or write yet |
irdbit <= rdwr_n; --read one bit if it is a read |
iwrbit <= not rdwr_n; --write one bit if its a write |
else |
--if we are the bit operation has already started, clear the strobes |
irdbit <= '0'; |
iwrbit<= '0'; |
state <= S_SHIFT; |
end if; |
when S_SHIFT => |
if busyin = '0' then --wait for the bit operation to finish |
shift <= ibit & shift(7 downto 1); --shift the bit in or out |
if bitcnt = 7 then --check for last bit |
state <= S_IDLE; --return to idle when finished |
else |
bitcnt <= bitcnt +1; --more bits to go, count down bits |
state <= S_STROBE; --strobe the next bit operatoin |
end if; |
end if; |
end case; |
end if; |
end if; |
end process p_shifty; |
|
------------------------------------- |
-- IO signals --- |
------------------------------------- |
--copy the internal signals to the external ports |
rdbit <= irdbit; |
wrbit <= iwrbit; |
obit <= shift(0); --the output bit to the ow_bit module |
obyte <= shift; --the read byte after shifting in all bits |
busy <= '0' when state = S_IDLE and rdbyte = '0' and wrbyte = '0' else '1'; --if we are not idle we are busy |
|
|
end rtl; |
/trunk/HDL/ow_idram.vhd
0,0 → 1,102
---------------------------------------------------------------------------------- |
-- <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_idram.vhd |
-- description: stores the list of one wire ids. Each id is 64 bits long. holds upto 32 ids. |
-- controls reset the bit counter, inc the bit counter, and write to the current location |
-- |
----------------------------- |
|
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
use IEEE.numeric_std.all; |
library work; |
|
------------------------------------------------------------------------------------- |
-- Entity declaration |
------------------------------------------------------------------------------------- |
entity ow_idram is |
port ( |
--global signals |
clk : in std_logic; |
--srst : in std_logic; --synchronous reset |
mode : in std_logic; --mode, 1=search, 0=other, used to calc read addr |
idnum : in std_logic_vector(4 downto 0); --index of the id to read or write |
idbit : in std_logic_vector(5 downto 0); --index of the bit within the id to read or write |
we : in std_logic; --write the currently indexed bit |
wdat : in std_logic; --bit value to write to the currently indexed bit |
rdat : out std_logic --bit value of the currently indexed bit |
); |
end ow_idram; |
|
|
------------------------------------------------------------------------------------- |
-- Architecture declaration |
------------------------------------------------------------------------------------- |
architecture rtl of ow_idram is |
|
type mem_type is array (2047 downto 0) of std_logic; |
signal mem : mem_type ; |
attribute syn_ramstyle: string; |
attribute syn_ramstyle of mem: signal is "no_rw_check"; |
|
signal rd_addr : integer range 0 to 2047; |
signal wr_addr : integer range 0 to 2047; |
signal mem_rdat : std_logic; |
begin |
|
|
------------------------------------------------------ |
-- ADDRESSES --- |
------------------------------------------------------ |
--the read idnum has to be calculated for the search mode. In search, we write to the current id, |
-- but read from the previous id. The previous id is needed in order to decide certain branches |
-- in the search algorithm. When we are at the 0th id, there is no previous id, so we just override |
-- this with zeros. |
wr_addr <= to_integer( unsigned(idnum) & unsigned(idbit) ); |
rd_addr <= to_integer( unsigned(idnum) & unsigned(idbit) ) when mode = '0' |
else to_integer( (unsigned(idnum)-1) & unsigned(idbit) ); |
|
--if in search mode and there is no previous id, then return '0' |
rdat <= '0' when mode = '1' and idnum = "00000" else mem_rdat; |
|
|
------------------------------------------------------ |
--- WRITE --- |
------------------------------------------------------ |
process (clk) -- Write memory. |
begin |
if rising_edge(clk) then |
if (we = '1') then |
--mem(to_integer(unsigned(idnum & idbit))) <= wdat; |
mem(wr_addr) <= wdat; |
end if; |
end if; |
end process; |
|
------------------------------------------------------ |
--- READ --- |
------------------------------------------------------ |
process (clk) -- Read memory. |
begin |
if rising_edge(clk) then |
mem_rdat <= mem(rd_addr); |
end if; |
end process; |
|
end rtl; |
/trunk/HDL/ow_mstr.vhd
0,0 → 1,138
---------------------------------------------------------------------------------- |
-- <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: onewire_mstr.vhd |
-- description: reading and writing devies on a one wire bus |
-- |
-- To simplify the design, there is a low level entity, ow_bit, that handles the |
-- read/write/init bit patterns. There is also a byte level entity, |
-- ow_byte, that operates on bytes by controlling the ow_bit entity. |
-- Controllers of this module can use bit or byte accesses to the one wire bus. |
-- to execute both byte and bit level operations, it is necessary to mux the control |
-- to the ow_bit interface to the various higher level functions. |
----------------------------- |
|
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
use IEEE.numeric_std.all; |
|
------------------------------------------------------------------------------------- |
-- Entity declaration |
------------------------------------------------------------------------------------- |
entity ow_mstr is |
port ( |
--global signals |
clk : in std_logic; |
srst : in std_logic; --synchronous reset |
stb1us : in std_logic; --1us strobe, used to time transactions |
busy : out std_logic; --device is in middle of read,write or init |
--low level interfaces, used for micro processor control of bus |
init_stb : in std_logic; --sends an init/reset pulse to bus |
wrbyte : in std_logic; --write a byte to the bus |
inbyte : in std_logic_vector(7 downto 0); --data byte to write |
wrbit : in std_logic; --write a single bit to the bus |
inbit : in std_logic; --data bit to write |
rdbyte : in std_logic; --read a byte from the bus |
outbyte : out std_logic_vector(7 downto 0); --read byte |
rdbit : in std_logic; --read a single bit from the bus |
outbit : out std_logic; --read bit |
--one wire bus interface, requires external 5k resistor on bus |
owin : in std_logic; --one wire input |
owout : out std_logic --one wire output |
); |
end ow_mstr; |
|
------------------------------------------------------------------------------------- |
-- Architecture declaration |
------------------------------------------------------------------------------------- |
architecture rtl of ow_mstr is |
|
signal busyout : std_logic; |
|
--bit module signals |
signal ow1_rbit : std_logic; |
signal ow1_obit : std_logic; |
signal ow1_wbit : std_logic; |
signal ow1_ibit : std_logic; |
signal ow1_zbit : std_logic; |
signal ow1_busy : std_logic; |
|
--byte module signals |
signal ow8_rbit : std_logic; |
signal ow8_wbit : std_logic; |
signal ow8_obit : std_logic; |
signal ow8_busy : std_logic; |
|
begin |
------------------------------------- |
-- signal decoding --- |
------------------------------------- |
-- the following signals are muxed with priorities, allowing ow8 or external control of the bit interface |
ow1_rbit <= ow8_rbit when ow8_busy = '1' else rdbit; |
ow1_wbit <= ow8_wbit when ow8_busy = '1' else wrbit; |
ow1_ibit <= ow8_obit when ow8_busy = '1' else inbit; |
ow1_zbit <= init_stb; |
|
------------------------------------- |
-- u_ow1 --- |
------------------------------------- |
--handles single bit read/write/reset of the one wire bus |
u_ow1 : entity work.ow_bit(rtl) |
port map( |
--globals |
clk => clk, |
srst => srst, |
clken => stb1us, |
--interface to higher level |
rstb => ow1_rbit, |
wstb => ow1_wbit, |
istb => ow1_zbit, |
din => ow1_ibit, |
dout => ow1_obit, |
busy => ow1_busy, |
--one wire bus |
owin => owin, --one wire input |
owout => owout --one wire output |
); |
|
------------------------------------- |
-- u_ow8 --- |
------------------------------------- |
u_ow8 : entity work.ow_byte(rtl) |
port map( |
--globals |
clk => clk, |
srst => srst, |
--ow1 interface |
rdbit => ow8_rbit, |
wrbit => ow8_wbit, |
ibit => ow1_obit, |
obit => ow8_obit, |
busyin => ow1_busy, |
--high level interface to owt,owi, or external |
rdbyte => rdbyte, |
obyte => outbyte, |
wrbyte => wrbyte, |
ibyte => inbyte, |
busy => ow8_busy |
); |
|
outbit <= ow1_obit; |
busy <= ow8_busy or ow1_busy; |
|
end rtl; |
/trunk/HDL/ow_search.vhd
0,0 → 1,339
---------------------------------------------------------------------------------- |
-- <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_SKIP, 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 63; |
signal lastzero : integer range 0 to 63; |
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 lastzero : 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 |
-- "restart" resets all parameters to rediscover all ROM iDs |
-- "hunt" searches for the next ROM ID in the sort order |
p_hunt : process (clk) |
begin |
if rising_edge(clk) then |
if srst = '1' or restart = '1' then |
h_state <= H_IDLE; |
idbitnum <= 0; |
lastfork <= 0; |
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 => |
idbitnum <= 0; |
lastzero <= 0; |
rxpat <= "00"; |
iwrbyte <= '0'; |
irdbit <= '0'; |
iwrbit <= '0'; |
iwe <= '0'; |
iobit <= '0'; |
obyte <= x"00"; |
if h_start = '1' then |
if lastdev = '0' then |
h_state <= H_RST; |
izzbit <= '1'; |
h_err <= '0'; |
else |
h_state <= H_FILL; |
iwe <= '1'; |
iobit <= '0'; |
end if; |
else |
izzbit <= '0'; |
end if; |
when H_RST => |
if izzbit = '1' then |
izzbit <= '0'; |
elsif busyin = '0' then |
if ibit = '1' then |
h_state <= H_ERROR; |
else |
obyte <= x"f0"; |
iwrbyte <= '1'; |
h_state <= H_SKIP; |
end if; |
end if; |
when H_SKIP => |
if iwrbyte = '1' then |
iwrbyte <= '0'; |
elsif busyin = '0' then |
irdbit <= '1'; |
h_state <= H_READBIT; |
end if; |
when H_READBIT => |
if irdbit = '1' then |
irdbit <= '0'; |
elsif busyin = '0' then |
rxpat(1) <= ibit; |
irdbit <= '1'; |
h_state <= H_READCMP; |
end if; |
when H_READCMP => |
if irdbit = '1' then |
irdbit <= '0'; |
elsif busyin = '0' then |
rxpat(0) <= ibit; |
h_state <= H_PARSE; |
end if; |
when H_PARSE => |
case rxpat is |
when "11" => |
h_state <= H_ERROR; |
when "00" => |
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'; |
lastzero <= 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 |
lastzero <= 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 => |
if iwrbit = '1' or iwe = '1' then |
iwrbit <= '0'; |
iwe <= '0'; |
elsif busyin = '0' then |
if idbitnum = 63 then |
h_state <= H_IDLE; |
lastfork <= lastzero; |
if lastzero = 0 then |
lastdev <= '1'; |
end if; |
else |
idbitnum <= idbitnum + 1; |
irdbit <= '1'; |
h_state <= H_READBIT; |
end if; |
end if; |
when H_FILL => |
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; |
restart <= '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 => |
if h_start = '1' then |
h_start <= '0'; |
elsif h_busy = '0' then |
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; |
/trunk/HDL/ow_temp.vhd
0,0 → 1,392
---------------------------------------------------------------------------------- |
-- <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_temp.vhd |
-- description: configures each ds1820 device, starts a conversion on each device, or reads the results |
-- of each device. temps are set to 10 bit to shorten conversion times (and who needs 1/16 C resolution |
-- when the accuracy is +-0.5C ). The temperatures are output on a bus with a strobe and a device index. |
----------------------------- |
|
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
use IEEE.numeric_std.all; |
--use work.p_ow_types.all; |
|
------------------------------------------------------------------------------------- |
-- Entity declaration |
------------------------------------------------------------------------------------- |
entity ow_temp is |
generic ( |
BITS : integer := 12; |
DEFTEMP : std_logic_vector(11 downto 0) := x"7ff"; |
CRC : boolean := false |
); |
port ( |
--global signals |
clk : in std_logic; |
srst : in std_logic; |
busyin : in std_logic; --busy signal from either ow_byte or ow_bit |
--signals to upper layer hierarchy |
init : in std_logic; --init a device for temp reading |
conv : in std_logic; --send convert command to the device |
read : in std_logic; --read a device |
temp : out signed(15 downto 0); --current device temp |
tempidx : out unsigned(4 downto 0); --current device index |
tempstb : out std_logic; --stobe indicating a temperature output |
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) |
zzbit : out std_logic; --reset strobe to ow_bit interface |
wrbit : out std_logic; --write strobe to ow_bit interface |
ibit : in std_logic; --the data read from the ow_bit interface |
obit : out std_logic; --the data written to the ow_bit interface |
rdbyte : out std_logic; --read strobe to ow_byte interface |
wrbyte : out std_logic; --write strobe to ow_byte interface |
obyte : out std_logic_vector(7 downto 0); --data to write to the ow_byte |
ibyte : in std_logic_vector(7 downto 0); --data read from 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 |
); |
end ow_temp; |
|
------------------------------------------------------------------------------------- |
-- Architecture declaration |
------------------------------------------------------------------------------------- |
architecture rtl of ow_temp is |
|
type t_state_type is (T_IDLE, T_GETTYPE, T_TXID, T_RST, T_TXTOUT, T_TXTOUT2, T_ERROR, |
T_INIT, T_INIT1, T_INIT2, T_INIT3, T_INIT4, |
T_CONV, T_CONV1, T_CONV2, T_CONV3, T_CONV4, |
T_READ, T_READ1, T_READ2, T_READ3, T_READ4, T_READ5, T_READ6, T_READ7 |
); |
signal t_state : t_state_type := T_IDLE; |
signal t_next : t_state_type := T_IDLE; |
|
type slv8ary is array (integer range <>) of std_logic_vector(7 downto 0); |
|
constant ROMSTR : integer := 1; |
constant ROMTXT : std_logic_vector( 7 downto 0) := x"55"; |
constant ROMTXTLEN : integer := 1; |
constant INITSTR : integer := 2; |
constant INITTXT : slv8ary(1 to 4) := ( x"4e",x"7f",x"80",x"3f"); |
constant INITTXTLEN : integer := INITTXT'length; |
constant CONVSTR : integer := 3; |
constant CONVTXT : std_logic_vector( 7 downto 0) := x"44"; |
constant CONVTXTLEN : integer := 1; |
constant READSTR : integer := 4; |
constant READTXT : std_logic_vector( 7 downto 0) := x"be"; |
constant READTXTLEN : integer := 1; --READTXT'length; |
constant LASTSTR : integer := READSTR; |
|
constant DS1822 : std_logic_vector(7 downto 0) := x"28"; |
|
signal txtlen : integer range 1 to 4; |
signal txtstr : integer range 1 to LASTSTR; |
signal txtptr : integer range 1 to 4; |
signal txbyte : std_logic_vector(7 downto 0); |
|
signal ididx : integer range 0 to 31; --idx of the current device |
signal t_err : std_logic := '0'; |
signal irdbyte : std_logic := '0'; |
signal iwrbyte : std_logic := '0'; |
signal izzbit : std_logic := '0'; |
signal iwrbit : std_logic := '0'; |
--signal iobit : std_logic := '0'; |
|
signal readbits : integer range 1 to 10; |
signal shift : std_logic_vector(15 downto 0); |
signal bytecnt : integer range 0 to 9; |
signal bitcnt : integer range 0 to 63; |
signal curid : std_logic_vector(71 downto 0); |
|
signal stall : std_logic := '0'; -- this signal is used to stall the state machine one clock after each action |
|
|
--attribute mark_debug : string; |
--attribute mark_debug of pulse_state : signal is "true"; |
--attribute mark_debug of timer : signal is "true"; |
|
|
begin |
------------------------------------------------------ |
-- TX MUX - mux between output commands --- |
------------------------------------------------------ |
--select the byte to transmit from the text strings or the rom value |
txbyte <= CONVTXT when txtstr = CONVSTR else READTXT when txtstr = READSTR |
else ROMTXT when txtstr = ROMSTR else INITTXT(txtptr); |
txtlen <= CONVTXTLEN when txtstr = CONVSTR else READTXTLEN when txtstr = READSTR |
else ROMTXTLEN when txtstr = ROMSTR else INITTXTLEN; |
|
------------------------------------------------------ |
-- P_TEMP - INIT, CONV, READ temp sensors --- |
------------------------------------------------------ |
--p_temp - sends rom match command followed by init command, convert command or |
-- read command to the targeted temp sensor and reads data back (if a read command) |
p_temp : process (clk) |
begin |
if rising_edge(clk) then |
if srst = '1' then |
tempstb <= '0'; |
t_state <= T_IDLE; |
t_err <= '0'; |
izzbit <= '0'; |
iwrbit <= '0'; |
irdbyte <= '0'; |
iwrbyte <= '0'; |
ididx <= 0; |
bytecnt <= 0; |
bitcnt <= 0; |
elsif stall = '1' then |
tempstb <= '0'; |
iwrbit <= '0'; |
izzbit <= '0'; |
iwrbyte <= '0'; |
irdbyte <= '0'; |
stall <= '0'; |
else |
--allow 1 extra clock for ram read, temperature conversions |
-- but not when idle or we will miss the triggers |
if t_state /= T_IDLE then |
stall <= '1'; |
end if; |
case t_state is |
when T_IDLE => |
tempstb <= '0'; |
obyte <= x"00"; |
--shift <= x"000000000000000000"; |
shift <= x"0000"; |
izzbit <= '0'; |
irdbyte <= '0'; |
iwrbyte <= '0'; |
izzbit <= '0'; |
ididx <= 0; |
--shift <= x"00" & ids(ididx); |
--idtype <= x"00"; |
bytecnt <= 0; |
bitcnt <= 0; |
if init = '1' then |
t_state <= T_GETTYPE; |
t_next <= T_INIT; |
t_err <= '0'; |
elsif conv = '1' then |
t_state <= T_GETTYPE; |
t_next <= T_CONV; |
t_err <= '0'; |
elsif read = '1' then |
t_state <= T_GETTYPE; |
t_next <= T_READ; |
t_err <= '0'; |
end if; |
when T_GETTYPE => |
--get the device type from the idrom |
shift(7 downto 0) <= id_rbit & shift(7 downto 1); |
if bitcnt = 7 then |
bitcnt <= 0; |
t_state <= t_next; |
else |
bitcnt <= bitcnt + 1; |
end if; |
when T_TXID => |
if busyin = '0' then |
iwrbit <= '1'; |
if bitcnt = 63 then |
t_state <= t_next; |
bitcnt <= 0; |
else |
bitcnt <= bitcnt + 1; |
end if; |
end if; |
when T_INIT => |
if busyin = '0' then |
if shift(7 downto 0) = DS1822 then |
t_state <= T_RST; |
t_next <= T_INIT1; |
izzbit <= '1'; |
else |
t_state <= T_INIT4; |
end if; |
end if; |
when T_INIT1 => |
txtptr <= 1; |
txtstr <= ROMSTR; |
t_state <= T_TXTOUT; |
t_next <= T_INIT2; |
when T_INIT2 => |
t_state <= T_TXID; |
t_next <= T_INIT3; |
when T_INIT3 => |
txtptr <= 1; |
txtstr <= INITSTR; |
t_state <= T_TXTOUT; |
t_next <= T_INIT4; |
when T_INIT4 => |
if ididx = 31 then |
t_state <= T_IDLE; |
else |
ididx <= ididx + 1; |
t_state <= T_GETTYPE; |
t_next <= T_INIT; |
end if; |
when T_CONV => |
--this state cycles through all devices and initiates a conversion on all ds1822s |
if busyin = '0' then |
if shift(7 downto 0) = DS1822 then |
t_state <= T_RST; |
t_next <= T_CONV1; |
izzbit <= '1'; |
else |
t_state <= T_CONV4; |
end if; |
end if; |
when T_CONV1 => |
txtptr <= 1; |
txtstr <= ROMSTR; |
t_state <= T_TXTOUT; |
t_next <= T_CONV2; |
when T_CONV2 => |
t_state <= T_TXID; |
t_next <= T_CONV3; |
when T_CONV3 => |
txtptr <= 1; |
txtstr <= CONVSTR; |
t_state <= T_TXTOUT; |
t_next <= T_CONV4; |
when T_CONV4 => |
if ididx = 31 then |
t_state <= T_IDLE; |
else |
ididx <= ididx + 1; |
t_state <= T_GETTYPE; |
t_next <= T_CONV; |
end if; |
when T_READ => |
--this state cycles through all devices and reads all ds18B20s |
if busyin = '0' then |
if shift(7 downto 0) = DS1822 then |
t_state <= T_RST; |
t_next <= T_READ1; |
izzbit <= '1'; |
else |
t_state <= T_READ7; |
end if; |
end if; |
when T_READ1 => |
txtptr <= 1; |
txtstr <= ROMSTR; |
t_state <= T_TXTOUT; |
t_next <= T_READ2; |
when T_READ2 => |
t_state <= T_TXID; |
t_next <= T_READ3; |
when T_READ3 => |
txtptr <= 1; |
txtstr <= READSTR; |
t_state <= T_TXTOUT; |
t_next <= T_READ4; |
bytecnt <= 0; |
when T_READ4 => |
if busyin = '0' then |
irdbyte <= '1'; |
bytecnt <= 0; |
t_state <= T_READ5; |
end if; |
when T_READ5 => |
--this state cycles through the 9 bytes to read |
if busyin = '0' then |
--if CRC = true then |
-- shift <= ibyte & shift(71 downto 8); |
--else |
-- shift <= x"00000000000000" & ibyte & shift(15 downto 8); |
--end if; |
shift <= ibyte & shift(15 downto 8); |
if (bytecnt = 1 and CRC = false) or (bytecnt = 9 and CRC = true) then |
t_state <= T_READ6; |
else |
bytecnt <= bytecnt + 1; |
irdbyte <= '1'; |
end if; |
end if; |
when T_READ6 => |
tempstb <= '1'; |
t_state <= T_READ7; |
when T_READ7 => |
tempstb <= '0'; |
if ididx = 31 then |
t_state <= T_IDLE; |
else |
ididx <= ididx + 1; |
t_state <= T_GETTYPE; |
t_next <= T_READ; |
end if; |
when T_RST => |
if busyin = '0' then |
if ibit = '1' then |
t_state <= T_ERROR; |
else |
t_state <= t_next; |
end if; |
end if; |
when T_TXTOUT => |
if busyin = '0' then |
--if txtstr = ROMSTR and txtptr > 1 then |
-- obyte <= shift(7 downto 0); |
-- shift <= shift(7 downto 0) & shift(71 downto 8); |
--else |
obyte <= txbyte; |
--end if; |
iwrbyte <= '1'; |
t_state <= T_TXTOUT2; |
end if; |
when T_TXTOUT2 => |
iwrbyte <= '0'; |
if txtptr = txtlen then |
t_state <= t_next; |
txtptr <= 1; |
else |
txtptr <= txtptr + 1; |
t_state <= T_TXTOUT; |
end if; |
when T_ERROR => |
t_err <= '1'; |
t_state <= T_IDLE; |
end case; |
end if; |
end if; |
end process p_temp; |
|
------------------------------------------------------ |
-- External Signals --- |
------------------------------------------------------ |
|
temp <= signed(shift(15 downto 0)); |
tempidx <= to_unsigned(ididx,5); |
|
busy <= '0' when t_state = T_IDLE and conv = '0' and init = '0' and read = '0' else '1'; |
wrbyte <= iwrbyte; |
rdbyte <= irdbyte; |
zzbit <= izzbit; |
wrbit <= iwrbit; |
obit <= id_rbit; |
id_num <= std_logic_vector(to_unsigned(ididx,5)); |
id_bit <= std_logic_vector(to_unsigned(bitcnt,6)); |
|
error <= t_err; |
|
end rtl; |