-------------------------------------------------------------------------------- -- File Name: lm75.vhd -------------------------------------------------------------------------------- -- Copyright (C) 2003 Free Model Foundry; http://www.FreeModelFoundry.com -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License version 2 as -- published by the Free Software Foundation. -- -- MODIFICATION HISTORY: -- -- version: | author: | mod date: | changes made: -- V1.0 M.Radmanovic 03 Nov 03 Initial release -- -------------------------------------------------------------------------------- -- PART DESCRIPTION: -- -- Library: MISC -- Technology: -- Part: LM75 -- Description: Digital Temperature Sensor and Thermal WATCHDOG with two -- wire Interface -------------------------------------------------------------------------------- LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; USE STD.textio.ALL; LIBRARY VITAL2000; USE VITAL2000.vital_timing.ALL; USE VITAL2000.vital_primitives.ALL; LIBRARY FMF; USE FMF.gen_utils.ALL; USE FMF.conversions.ALL; -------------------------------------------------------------------------------- -- ENTITY DECLARATION -------------------------------------------------------------------------------- ENTITY lm75 IS GENERIC ( -- tipd delays: interconnect path delays tipd_SCL : VitalDelayType01 := VitalZeroDelay01; tipd_SDA : VitalDelayType01 := VitalZeroDelay01; tipd_A0 : VitalDelayType01 := VitalZeroDelay01; tipd_A1 : VitalDelayType01 := VitalZeroDelay01; tipd_A2 : VitalDelayType01 := VitalZeroDelay01; -- tsetup values: setup times tsetup_SDA_SCL : VitalDelayType := UnitDelay; tsetup_SCL_SDAS : VitalDelayType := UnitDelay; tsetup_SCL_SDAP : VitalDelayType := UnitDelay; -- thold values: hold times thold_SDA_SCL : VitalDelayType := UnitDelay; thold_SCL_SDAS : VitalDelayType := UnitDelay; -- tpw values: pulse widths tpw_SCL_posedge : VitalDelayType := UnitDelay; tpw_SCL_negedge : VitalDelayType := UnitDelay; -- tperiod min (calculated as 1/max freq) tperiod_SCL : VitalDelayType := UnitDelay; temp_file_name : STRING := "none"; -- tdevice values: values for internal delays tdevice_TBUF : VitalDelayType := 1.3 us; -- generic control parameters InstancePath : STRING := DefaultInstancePath; TimingChecksOn : BOOLEAN := DefaultTimingChecks; MsgOn : BOOLEAN := DefaultMsgOn; XOn : BOOLEAN := DefaultXon; SeverityMode : SEVERITY_LEVEL := WARNING; -- For FMF SDF technology file usage TimingModel : STRING := DefaultTimingModel ); PORT ( SCL : IN std_logic := 'U'; SDA : INOUT std_logic := 'U'; A0 : IN std_logic := 'U'; A1 : IN std_logic := 'U'; A2 : IN std_logic := 'U'; OS : OUT std_logic := 'U' ); ATTRIBUTE VITAL_LEVEL0 of lm75 : ENTITY IS TRUE; END lm75 ; -------------------------------------------------------------------------------- -- ARCHITECTURE DECLARATION -------------------------------------------------------------------------------- ARCHITECTURE vhdl_behavioral of lm75 IS ATTRIBUTE VITAL_LEVEL0 of vhdl_behavioral : ARCHITECTURE IS TRUE; CONSTANT partID : STRING := "lm75"; SIGNAL SCL_ipd : std_logic := 'U'; SIGNAL SDA_ipd : std_logic := 'U'; SIGNAL A0_ipd : std_logic := 'U'; SIGNAL A1_ipd : std_logic := 'U'; SIGNAL A2_ipd : std_logic := 'U'; SIGNAL buf_in : std_logic := '0'; SIGNAL buf_out : std_logic := '0'; BEGIN ---------------------------------------------------------------------------- -- Internal Delays ---------------------------------------------------------------------------- -- Artificial VITAL primitives to incorporate internal delays TBUF : VitalBuf (buf_out, buf_in, (VitalZeroDelay,tdevice_TBUF)); ---------------------------------------------------------------------------- -- Wire Delays ---------------------------------------------------------------------------- WireDelay : BLOCK BEGIN w_1 : VitalWireDelay (SCL_ipd, SCL, tipd_SCL); w_2 : VitalWireDelay (SDA_ipd, SDA, tipd_SDA); w_3 : VitalWireDelay (A0_ipd, A0, tipd_A0); w_4 : VitalWireDelay (A1_ipd, A1, tipd_A1); w_5 : VitalWireDelay (A2_ipd, A2, tipd_A2); END BLOCK; ---------------------------------------------------------------------------- -- Main Behavior Block ---------------------------------------------------------------------------- Behavior: BLOCK PORT ( SCLIn : IN std_logic := 'U'; SDAIn : IN std_logic := 'U'; SDAOut : OUT std_logic := 'Z'; AddressIn : IN std_logic_vector(2 downto 0) := (others => 'Z'); OSIn : OUT std_logic := 'Z' ); PORT MAP ( SCLIn => SCL_ipd, SDAIn => SDA_ipd, SDAOut => SDA, AddressIn(0) => A0_ipd, AddressIn(1) => A1_ipd, AddressIn(2) => A2_ipd, OSIn => OS ); TYPE RegType IS ARRAY (1 downto 0) OF std_logic_vector(7 downto 0); SIGNAL Temperature : REAL; SIGNAL Conv_time : TIME := 0.15 sec; SIGNAL Start : std_ulogic := 'U'; SIGNAL Conversion : std_ulogic := '1'; SIGNAL READ : std_ulogic := '0'; SIGNAL TemperatureReg : RegType:= ("00000000","00000000"); SIGNAL THYSTReg : RegType := ("01001011","00000000"); SIGNAL TOSReg : RegType := ("01010000","00000000"); SIGNAL ConfigReg : std_logic_vector(7 downto 0) := (others => '0'); SIGNAL power_up : std_logic := '0'; ALIAS RESOLUTION : std_logic_vector(1 downto 0) IS ConfigReg(6 downto 5); ALIAS SHUTDOWN : std_logic IS ConfigReg(0); ALIAS POL : std_logic IS ConfigReg(2); ALIAS TM : std_logic IS ConfigReg(1); ALIAS FAULT : std_logic_vector(1 downto 0) IS ConfigReg(4 downto 3); BEGIN power_up <= '0', '1' AFTER 1 ns; SYSOUT1 : PROCESS BEGIN WAIT FOR Conv_time; Conversion <= not(Conversion); WAIT FOR Conv_time; Conversion <= not(Conversion); END PROCESS SYSOUT1; Temper : PROCESS(RESOLUTION, Conversion, READ) VARIABLE Temp : INTEGER; VARIABLE Measured : INTEGER; VARIABLE THYST : INTEGER; VARIABLE TOS : INTEGER; VARIABLE cntr : INTEGER := 0; VARIABLE Res9 : std_logic_vector(8 downto 0); VARIABLE Res10 : std_logic_vector(9 downto 0); VARIABLE Res11 : std_logic_vector(10 downto 0); VARIABLE Res12 : std_logic_vector(11 downto 0); BEGIN IF SHUTDOWN = '0' THEN CASE RESOLUTION IS WHEN "00" => Conv_time <= 150 ms; WHEN "01" => Conv_time <= 300 ms; WHEN "10" => Conv_time <= 600 ms; WHEN "11" => Conv_time <= 1200 ms; WHEN others => NULL; END CASE; END IF; IF Conversion'EVENT THEN IF SHUTDOWN = '0' THEN Temp := INTEGER(Temperature); CASE RESOLUTION IS WHEN "00" => Temp := Temp * 2; Res9 := int_to_slv(Temp,9); TemperatureReg(1) <= Res9(8 downto 1); TemperatureReg(0) <= Res9(0) & "0000000"; Res9 := THYSTReg(1) & THYSTReg(0)(7); THYST := to_int(Res9); Res9 := TOSReg(1) & TOSReg(0)(7); TOS := to_int(Res9); WHEN "01" => Temp := Temp * 4; Res10 := int_to_slv(Temp,10); TemperatureReg(1) <= Res10(9 downto 2); TemperatureReg(0) <= Res10(1 downto 0) & "000000"; Res10 := THYSTReg(1) & THYSTReg(0)(7 downto 6); THYST := to_int(Res10); Res10 := TOSReg(1) & TOSReg(0)(7 downto 6); TOS := to_int(Res10); WHEN "10" => Temp := Temp * 8; Res11 := int_to_slv(Temp,11); TemperatureReg(1) <= Res11(10 downto 3); TemperatureReg(0) <= Res11(2 downto 0) & "00000"; Res11 := THYSTReg(1) & THYSTReg(0)(7 downto 5); THYST := to_int(Res11); Res11 := TOSReg(1) & TOSReg(0)(7 downto 5); TOS := to_int(Res11); WHEN "11" => Temp := Temp * 16; Res12 := int_to_slv(Temp,12); TemperatureReg(1) <= Res12(11 downto 4); TemperatureReg(0) <= Res12(3 downto 0) & "0000"; Res12 := THYSTReg(1) & THYSTReg(0)(7 downto 4); THYST := to_int(Res12); Res12 := TOSReg(1) & TOSReg(0)(7 downto 4); TOS := to_int(Res12); WHEN others => NULL; END CASE; Measured := Temp; END IF; IF Measured >= TOS THEN cntr := cntr + 1; CASE FAULT IS WHEN "00" => IF cntr = 1 THEN cntr := 0; IF POL = '1' THEN OS <= '1'; ELSE OS <= '0'; END IF; END IF; WHEN "01" => IF cntr = 2 THEN cntr := 0; IF POL = '1' THEN OS <= '1'; ELSE OS <= '0'; END IF; END IF; WHEN "10" => IF cntr = 4 THEN cntr := 0; IF POL = '1' THEN OS <= '1'; ELSE OS <= '0'; END IF; END IF; WHEN "11" => IF cntr = 6 THEN cntr := 0; IF POL = '1' THEN OS <= '1'; ELSE OS <= '0'; END IF; END IF; WHEN others => NULL; END CASE; END IF; IF TM = '0' THEN -- comparator mode IF Measured < THYST THEN -- OS inactive cntr := 0; IF POL = '1' THEN OS <= '0'; ELSE OS <= '1'; END IF; END IF; END IF; END IF; IF TM = '1' THEN -- Interrupt mode IF SHUTDOWN = '1' OR rising_edge(READ) THEN -- OS inactive cntr := 0; IF POL = '1' THEN OS <= '0'; ELSE OS <= '1'; END IF; END IF; END IF; END PROCESS; ---------------------------------------------------------------------------- -- Main Behavior Process ---------------------------------------------------------------------------- Behavior : PROCESS (SCLIn, SDAIn) -- Timing Check Variables VARIABLE Tviol_SDAS_SCL : X01 := '0'; VARIABLE TD_SDAS_SCL : VitalTimingDataType; VARIABLE Tviol_SDAH_SCL : X01 := '0'; VARIABLE TD_SDAH_SCL : VitalTimingDataType; VARIABLE Tviol_SCL_SDAS : X01 := '0'; VARIABLE TD_SCL_SDAS : VitalTimingDataType; VARIABLE Tviol_SCL_SDAP : X01 := '0'; VARIABLE TD_SCL_SDAP : VitalTimingDataType; VARIABLE Pviol_SCL : X01 := '0'; VARIABLE PD_SCL : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE ShiftReg : std_logic_vector(7 downto 0); VARIABLE Pointer : std_logic_vector(7 downto 0) := (others => '0'); VARIABLE TempReg : std_logic_vector(7 downto 0); VARIABLE ShiftReg1 : std_logic_vector(8 downto 0); VARIABLE AddressReg : std_logic_vector(6 downto 0); VARIABLE counter : NATURAL RANGE 0 TO 8; VARIABLE Addreceived : BOOLEAN := false; VARIABLE Pointreceived : BOOLEAN := false; VARIABLE Firstbyte_write : BOOLEAN := false; VARIABLE Firstbyte_read : BOOLEAN := false; VARIABLE Secondbyte_write : BOOLEAN := false; VARIABLE SlaveID : BOOLEAN := false; VARIABLE RW : std_logic; VARIABLE ackslave : BOOLEAN := false; VARIABLE data : std_logic := '0'; VARIABLE Violation : X01 := '0'; BEGIN -------------------------------------------------------------------- -- Timing Check Section -------------------------------------------------------------------- IF (TimingChecksOn) THEN VitalSetupHoldCheck ( TestSignal => SDAIn, TestSignalName => "SDA", RefSignal => SCLIn, RefSignalName => "SCL", SetupHigh => tsetup_SDA_SCL, SetupLow => tsetup_SDA_SCL, CheckEnabled => (Start = '1'), RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_SDAS_SCL, XOn => XOn, MsgOn => MsgOn, Violation => Tviol_SDAS_SCL ); VitalSetupHoldCheck ( TestSignal => SDAIn, TestSignalName => "SDA", RefSignal => SCLIn, RefSignalName => "SCL", HoldHigh => thold_SDA_SCL, HoldLow => thold_SDA_SCL, CheckEnabled => true, RefTransition => '\', HeaderMsg => InstancePath & PartID, TimingData => TD_SDAH_SCL, XOn => XOn, MsgOn => MsgOn, Violation => Tviol_SDAH_SCL ); VitalSetupHoldCheck ( TestSignal => SCLIn, TestSignalName => "SCL", RefSignal => SDAIn, RefSignalName => "SDA", SetupHigh => tsetup_SCL_SDAS, HoldHigh => thold_SCL_SDAS, CheckEnabled => true, RefTransition => '\', HeaderMsg => InstancePath & PartID, TimingData => TD_SCL_SDAS, XOn => XOn, MsgOn => MsgOn, Violation => Tviol_SCL_SDAS ); VitalSetupHoldCheck ( TestSignal => SCLIn, TestSignalName => "SCL", RefSignal => SDAIn, RefSignalName => "SDA", SetupHigh => tsetup_SCL_SDAP, CheckEnabled => true, RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_SCL_SDAP, XOn => XOn, MsgOn => MsgOn, Violation => Tviol_SCL_SDAP ); VitalPeriodPulseCheck ( TestSignal => SCLIn, TestSignalName => "SCL", Period => tperiod_SCL, PulseWidthLow => tpw_SCL_negedge, PulseWidthHigh => tpw_SCL_posedge, PeriodData => PD_SCL, XOn => XOn, MsgOn => MsgOn, Violation => Pviol_SCL, HeaderMsg => InstancePath & PartID, CheckEnabled => true ); Violation := Tviol_SDAS_SCL OR Tviol_SDAH_SCL OR Tviol_SCL_SDAS OR Tviol_SCL_SDAP OR Pviol_SCL; ASSERT Violation = '0' REPORT InstancePath & partID & ": simulation may be" & " inaccurate due to timing violations" SEVERITY SeverityMode; END IF; ---------------------------------------------------------------------------- -- Functional Section ---------------------------------------------------------------------------- IF SCLIn = '1' THEN IF falling_edge(SDAIn) THEN Start <= '1'; counter := 0; Addreceived := false; Pointreceived := false; Firstbyte_write := false; Firstbyte_read := false; Secondbyte_write := false; ackslave := false; data := '0'; SlaveID := false; ASSERT buf_out = '0' REPORT InstancePath & partID & ": Bus free time beetwen STOP" & " and START condition " SEVERITY SeverityMode; ELSIF rising_edge(SDAIn) THEN Start <= '0'; buf_in <= '1', '0' AFTER 1.3 us; END IF; END IF; IF rising_edge(SCLIn) AND Start = '1' THEN IF Addreceived = false THEN IF counter < 7 THEN AddressReg(6 - counter) := SDAIn; counter := counter + 1; ELSIF counter = 7 THEN RW := SDAIn; counter := counter + 1; IF (AddressReg = "1001" & A2 & A1 & A0) THEN SlaveID := true; END IF; ELSIF counter = 8 THEN counter := 0; Addreceived := true; IF RW = '1' THEN READ <= '1', '0' AFTER 10 ns; CASE Pointer IS WHEN "00000000" => --MSB byte first ShiftReg := TemperatureReg(1); WHEN "00000001" => ShiftReg := ConfigReg; WHEN "00000010" => ShiftReg := THYSTReg(1); WHEN "00000011" => ShiftReg := TOSReg(1); WHEN others => ShiftReg := (others => 'X'); END CASE; ShiftReg1 := ShiftReg & '1'; END IF; END IF; ELSIF RW = '1' AND counter < 8 AND SlaveID = true THEN counter := counter + 1; ELSIF RW = '0' AND counter < 8 AND SlaveID = true THEN ShiftReg(counter) := SDAIn; counter := counter + 1; ELSIF counter = 8 AND SlaveID = true THEN data := '0'; counter := 0; IF Pointreceived = false AND RW = '0' THEN Pointreceived := true; FOR I IN 7 DOWNTO 0 LOOP Pointer(i) := ShiftReg(7 - i); END LOOP; ELSIF RW = '0' AND Firstbyte_write = false THEN Firstbyte_write := true; FOR I IN 7 DOWNTO 0 LOOP TempReg(i) := ShiftReg(7 - i); END LOOP; CASE Pointer IS WHEN "00000001" => ConfigReg <= TempReg; WHEN "00000010" => THYSTReg(1) <= TempReg; WHEN "00000011" => TOSReg(1) <= TempReg; WHEN others => null; END CASE; ELSIF RW = '0' AND Firstbyte_write = true AND Secondbyte_write = false THEN Secondbyte_write := true; FOR I IN 7 DOWNTO 0 LOOP TempReg(i) := ShiftReg(7 - i); END LOOP; CASE Pointer IS WHEN "00000010" => THYSTReg(0) <= TempReg; WHEN "00000011" => TOSReg(0) <= TempReg; WHEN others => END CASE; END IF; IF RW = '1' AND Firstbyte_read = false THEN Firstbyte_read := true; READ <= '1', '0' AFTER 10 ns; CASE Pointer IS WHEN "00000000" => ShiftReg := TemperatureReg(0); WHEN "00000010" => ShiftReg := THYSTReg(0); WHEN "00000011" => ShiftReg := TOSReg(0); WHEN others => ShiftReg := (others => 'X'); END CASE; ShiftReg1 := ShiftReg & '1'; ELSIF RW = '1' AND Firstbyte_read = true THEN ShiftReg := (others => 'X'); ShiftReg1 := ShiftReg & '1'; END IF; END IF; ELSIF falling_edge(SCLIn) AND Start = '1' AND SlaveID = true THEN IF RW = '0' THEN IF counter = 8 THEN ackslave := true; ELSIF counter = 0 THEN ackslave := false; END IF; ELSE IF counter = 8 AND Addreceived = false THEN ackslave := true; ELSIF counter = 0 THEN ackslave := false; END IF; IF counter < 8 THEN data := '1'; ELSE data := '0'; END IF; END IF; END IF; IF Start = '1' AND SlaveID = true THEN IF ackslave = true THEN SDAOut <= '0'; ELSIF data = '1' AND falling_edge(SCLIn) THEN SDAOut <= 'Z', ShiftReg1(8 - counter) AFTER 1 us; ELSIF data = '0' THEN SDAOut <= 'Z'; END IF; ELSE SDAOut <= 'Z'; END IF; END PROCESS; Preloadfile: PROCESS(Temperature, power_up) VARIABLE time_temp : time; FILE temp_file : text is temp_file_name; VARIABLE buf : line; BEGIN ------------------------------------------------------------------------------- -----lm75 temperature preload file--------------------------------------------- ------------------------------------------------------------------------------- -- / - comment temperature preload file, NO empty lines !!!!!!!!!!!!!!!! -- / temperature must change value at every line to trigger this process ------------------------------------------------------------------------------- IF (not ENDFILE(temp_file)) THEN READLINE(temp_file, buf); IF buf(1) = '/' THEN null; ELSE time_temp := to_time(to_nat(h(buf(1 to 8)))); Temperature <= REAL(to_nat(h(buf(9 to 10)))) AFTER time_temp; END IF; END IF; END PROCESS Preloadfile; END BLOCK; END vhdl_behavioral;