Commit 2c67ec27 authored by Tristan Gingold's avatar Tristan Gingold

Move gc_ds182x_readout.vhd to a subdirectory.

parent 9027e98a
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: gc_ds182x_readout
--
-- description: one wire temperature & unique id interface for
-- DS1822 and DS1820.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2013-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
--=================================================================================================
-- Libraries & Packages
--=================================================================================================
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.NUMERIC_STD.all;
--=================================================================================================
-- Entity declaration for fmc_masterFIP_core
--=================================================================================================
entity gc_ds182x_readout is
generic (
g_CLOCK_FREQ_KHZ : integer := 40000; -- clk_i frequency in KHz
g_USE_INTERNAL_PPS : boolean := false);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
pps_p_i : in std_logic; -- pulse per second (for temperature read)
onewire_b : inout std_logic; -- IO to be connected to the chip(DS1820/DS1822)
id_o : out std_logic_vector(63 downto 0); -- id_o value
temper_o : out std_logic_vector(15 downto 0); -- temperature value (refreshed every second)
id_read_o : out std_logic; -- id_o value is valid_o
id_ok_o : out std_logic); -- Same as id_read_o, but not reset with rst_n_i
end gc_ds182x_readout;
--=================================================================================================
-- architecture declaration
--=================================================================================================
architecture arch of gc_ds182x_readout is
-- time slot constants according to specs https://www.maximintegrated.com/en/app-notes/index.mvp/id/162
constant SLOT_CNT_START : unsigned(15 downto 0) := to_unsigned(0*g_CLOCK_FREQ_KHZ/40000, 16);
constant SLOT_CNT_START_PLUSONE : unsigned(15 downto 0) := SLOT_CNT_START + 1;
constant SLOT_CNT_SET : unsigned(15 downto 0) := to_unsigned(60*g_CLOCK_FREQ_KHZ/40000, 16);
constant SLOT_CNT_RD : unsigned(15 downto 0) := to_unsigned(600*g_CLOCK_FREQ_KHZ/40000, 16);
constant SLOT_CNT_STOP : unsigned(15 downto 0) := to_unsigned(3600*g_CLOCK_FREQ_KHZ/40000, 16);
constant SLOT_CNT_PRESTOP : unsigned(15 downto 0) := to_unsigned((3600-60)*g_CLOCK_FREQ_KHZ/40000, 16);
constant READ_ID_HEADER : std_logic_vector(7 downto 0) := X"33";
constant CONVERT_HEADER : std_logic_vector(7 downto 0) := X"44";
constant READ_TEMPER_HEADER : std_logic_vector(7 downto 0) := X"BE";
constant SKIPHEADER : std_logic_vector(7 downto 0) := X"CC";
constant ID_LEFT : integer := 71;
constant ID_RIGHT : integer := 8;
constant TEMPER_LEFT : integer := 15;
constant TEMPER_RIGHT : integer := 0;
constant TEMPER_DONE_BIT : std_logic := '0'; -- The serial line is asserted to this value by the
-- DS1820/DS1822 when the temperature conversion is ready
constant TEMPER_LGTH : unsigned(7 downto 0) := to_unsigned(72, 8);
constant ID_LGTH : unsigned(7 downto 0) := to_unsigned(64, 8);
type op_fsm_t is (READ_ID_OP, SKIP_ROM_OP1, CONV_OP1, CONV_OP2, SKIP_ROM_OP2, READ_TEMP_OP);
type cm_fsm_t is (RST_CM, PREP_WR_CM, WR_CM, PREP_RD_CM, RD_CM, IDLE_CM);
signal bit_top, bit_cnt : unsigned(7 downto 0);
signal slot_cnt : unsigned(15 downto 0);
signal start_p, end_p, set_value, read_value, init_pulse : std_logic;
signal state_op, nxt_state_op : op_fsm_t;
signal state_cm, nxt_state_cm : cm_fsm_t;
signal crc_vec, header : std_logic_vector(7 downto 0);
signal crc_ok, init, pre_read_p, i_id_read : std_logic;
signal load_temper, load_id, cm_only, pps_p_d : std_logic;
signal serial_id_out, nx_serial_id_out, nx_serial_id_oe : std_logic;
signal i_serial_id_oe, serial_idr : std_logic;
signal end_wr_cm, end_rd_cm, inc_bit_cnt, rst_bit_cnt : std_logic;
signal shift_header, id_cm_reg : std_logic;
signal cm_reg : std_logic_vector(71 downto 0);
signal shifted_header : std_logic_vector(7 downto 0);
signal pre_init_p : std_logic;
signal pps_counter : unsigned(31 downto 0);
signal pps : std_logic;
--=================================================================================================
-- architecture begin
--=================================================================================================
begin
gen_external_pps : if not g_USE_INTERNAL_PPS generate
pps <= pps_p_i;
end generate gen_external_pps;
gen_internal_pps : if g_USE_INTERNAL_PPS generate
p_pps_gen : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
pps <= '0';
pps_counter <= (others => '0');
else
if pps_counter = g_CLOCK_FREQ_KHZ*1000-1 then
pps <= '1';
pps_counter <= (others => '0');
else
pps <= '0';
pps_counter <= pps_counter + 1;
end if;
end if;
end if;
end process;
end generate gen_internal_pps;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- Serial data line in tri-state, when not writing data out
onewire_b <= serial_id_out when i_serial_id_oe = '1' else 'Z';
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- pps_p_i 1 clock tick delay
pps_p_iDelay : process (clk_i)
begin
if rising_edge(clk_i) then
pps_p_d <= pps;
end if;
end process;
---------------------------------------------------------------------------------------------------
-- operations FSM --
---------------------------------------------------------------------------------------------------
op_fsm_transitions : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
state_op <= READ_ID_OP;
else
state_op <= nxt_state_op;
end if;
end if;
end process;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
op_fsm_states : process(state_op, pps, crc_ok)
begin
nxt_state_op <= READ_ID_OP;
case state_op is
when READ_ID_OP =>
if pps = '1' and crc_ok = '1' then
nxt_state_op <= CONV_OP1;
else
nxt_state_op <= state_op;
end if;
when CONV_OP1 =>
if pps = '1' then
nxt_state_op <= SKIP_ROM_OP1;
else
nxt_state_op <= state_op;
end if;
when SKIP_ROM_OP1 =>
if pps = '1' then
nxt_state_op <= READ_TEMP_OP;
else
nxt_state_op <= state_op;
end if;
when READ_TEMP_OP =>
if pps = '1' then
nxt_state_op <= SKIP_ROM_OP2;
else
nxt_state_op <= state_op;
end if;
when SKIP_ROM_OP2 =>
if pps = '1' then
nxt_state_op <= CONV_OP2;
else
nxt_state_op <= state_op;
end if;
when CONV_OP2 =>
if pps = '1' then
nxt_state_op <= SKIP_ROM_OP1;
else
nxt_state_op <= state_op;
end if;
end case;
end process;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
op_fsm_outputs : process(state_op, state_cm, crc_ok, pps, cm_only)
begin
header <= READ_ID_HEADER;
bit_top <= ID_LGTH;
load_temper <= '0';
load_id <= '0';
cm_only <= '0';
case state_op is
when READ_ID_OP =>
header <= READ_ID_HEADER;
bit_top <= ID_LGTH;
if state_cm = IDLE_CM then
load_id <= crc_ok;
end if;
when CONV_OP1 =>
header <= CONVERT_HEADER;
cm_only <= '1';
when SKIP_ROM_OP1 =>
header <= SKIPHEADER;
cm_only <= '1';
when READ_TEMP_OP =>
header <= READ_TEMPER_HEADER;
bit_top <= TEMPER_LGTH;
if state_cm = IDLE_CM then
load_temper <= crc_ok and pps;
end if;
when SKIP_ROM_OP2 =>
header <= SKIPHEADER;
cm_only <= '1';
when CONV_OP2 =>
header <= CONVERT_HEADER;
cm_only <= '1';
when others => null;
end case;
end process;
---------------------------------------------------------------------------------------------------
-- commands FSM --
---------------------------------------------------------------------------------------------------
cm_fsm_transitions : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
state_cm <= RST_CM;
else
state_cm <= nxt_state_cm;
end if;
end if;
end process;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
cm_fsm_states : process(state_cm, start_p, end_wr_cm, end_rd_cm, crc_ok, state_op, cm_only, pps_p_d)
begin
nxt_state_cm <= RST_CM;
case state_cm is
when RST_CM =>
if start_p = '1' then
nxt_state_cm <= PREP_WR_CM;
else
nxt_state_cm <= state_cm;
end if;
when PREP_WR_CM =>
if start_p = '1' then
nxt_state_cm <= WR_CM;
else
nxt_state_cm <= state_cm;
end if;
when WR_CM =>
if end_wr_cm = '1' then
if cm_only = '0' then
nxt_state_cm <= PREP_RD_CM;
else
nxt_state_cm <= IDLE_CM;
end if;
else
nxt_state_cm <= state_cm;
end if;
when PREP_RD_CM =>
if start_p = '1' then
nxt_state_cm <= RD_CM;
else
nxt_state_cm <= state_cm;
end if;
when RD_CM =>
if end_rd_cm = '1' then
nxt_state_cm <= IDLE_CM;
else
nxt_state_cm <= state_cm;
end if;
when IDLE_CM =>
if state_op = READ_ID_OP then
if crc_ok = '0' then
nxt_state_cm <= RST_CM;
else
nxt_state_cm <= state_cm;
end if;
elsif state_op = READ_TEMP_OP then -- At this moment I will send a Conv temper_o command
if pps_p_d = '1' then
nxt_state_cm <= PREP_WR_CM;
else
nxt_state_cm <= state_cm;
end if;
elsif (state_op = CONV_OP1) or (state_op = CONV_OP2) then -- At this moment I will restart a temper_o read
if pps_p_d = '1' then
nxt_state_cm <= PREP_WR_CM;
else
nxt_state_cm <= state_cm;
end if;
elsif (state_op = SKIP_ROM_OP1) or (state_op = SKIP_ROM_OP2) then -- At this moment I will restart
if pps_p_d = '1' then
nxt_state_cm <= RST_CM;
else
nxt_state_cm <= state_cm;
end if;
else
nxt_state_cm <= state_cm;
end if;
end case;
end process;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
cm_fsm_outputs : process(state_cm, bit_cnt, pre_read_p, crc_vec, start_p,
shifted_header, init_pulse, read_value, pre_init_p)
begin
inc_bit_cnt <= '0';
nx_serial_id_out <= '0';
shift_header <= '0';
id_cm_reg <= '0';
nx_serial_id_oe <= '0';
rst_bit_cnt <= '0';
init <= '0';
crc_ok <= '0';
case state_cm is
when RST_CM =>
rst_bit_cnt <= '1';
nx_serial_id_out <= '0';
nx_serial_id_oe <= '1';
init <= start_p;
when PREP_WR_CM =>
rst_bit_cnt <= start_p;
nx_serial_id_oe <= '0';
nx_serial_id_out <= '0';
when WR_CM =>
shift_header <= start_p;
inc_bit_cnt <= start_p;
rst_bit_cnt <= '0';
nx_serial_id_out <= shifted_header(0) and (not init_pulse);
if bit_cnt < to_unsigned(7, bit_cnt'length) then
nx_serial_id_oe <= not pre_init_p;
else
nx_serial_id_oe <= not pre_read_p;
end if;
when PREP_RD_CM =>
rst_bit_cnt <= start_p;
nx_serial_id_oe <= '0';
nx_serial_id_out <= '0';
when RD_CM =>
inc_bit_cnt <= start_p;
rst_bit_cnt <= '0';
nx_serial_id_out <= not init_pulse;
id_cm_reg <= read_value;
nx_serial_id_oe <= init_pulse;
when IDLE_CM =>
if crc_vec = x"00" then
crc_ok <= '1';
else
crc_ok <= '0';
end if;
init <= '1';
end case;
end process;
---------------------------------------------------------------------------------------------------
-- time slots --
---------------------------------------------------------------------------------------------------
-- Generates time slots
-- Reset pulse
-- Read time slot
-- Write time slots
process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
slot_cnt(slot_cnt'left) <= '1';
slot_cnt(slot_cnt'left -1 downto 0) <= (others => '0');
start_p <= '0';
end_p <= '0';
set_value <= '0';
read_value <= '0';
init_pulse <= '0';
pre_init_p <= '0';
pre_read_p <= '0';
else
-- Slot counter
if init = '1' then
slot_cnt(slot_cnt'left) <= '1';
slot_cnt(slot_cnt'left - 1 downto 0) <= (others => '0');
elsif slot_cnt = SLOT_CNT_STOP then
slot_cnt <= (others => '0');
else
slot_cnt <= slot_cnt + 1;
end if;
-- Time slot start pulse
if slot_cnt = SLOT_CNT_START then
start_p <= '1';
else
start_p <= '0';
end if;
if ((slot_cnt > SLOT_CNT_START) and (slot_cnt < SLOT_CNT_SET)) then
init_pulse <= '1';
else
init_pulse <= '0';
end if;
if ((slot_cnt > SLOT_CNT_PRESTOP) and (slot_cnt < SLOT_CNT_STOP)) then
pre_init_p <= '1';
else
pre_init_p <= '0';
end if;
if (((slot_cnt > SLOT_CNT_PRESTOP) and (slot_cnt <= SLOT_CNT_STOP)) or
(slot_cnt <= SLOT_CNT_START_PLUSONE)) then
pre_read_p <= '1';
else
pre_read_p <= '0';
end if;
-- End of time slot pulse
if slot_cnt = SLOT_CNT_START then
end_p <= '1';
else
end_p <= '0';
end if;
-- Pulse to write value on serial link
if slot_cnt = SLOT_CNT_SET then
set_value <= '1';
else
set_value <= '0';
end if;
-- Pulse to read value on serial link
if slot_cnt = SLOT_CNT_RD then
read_value <= '1';
else
read_value <= '0';
end if;
end if;
end if;
end process;
---------------------------------------------------------------------------------------------------
-- serdes --
---------------------------------------------------------------------------------------------------
-- Data serializer bit counter
BitCnt_p : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
bit_cnt <= (others => '0');
else
if rst_bit_cnt = '1' then
bit_cnt <= (others => '0');
elsif inc_bit_cnt = '1' then
bit_cnt <= bit_cnt + 1;
end if;
end if;
end if;
end process;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- Data serializer shift register
ShiftReg_p : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
shifted_header <= READ_ID_HEADER;
cm_reg <= (others => '0');
serial_idr <= '0';
serial_id_out <= '0';
i_serial_id_oe <= '0';
id_o <= (others => '0');
i_id_read <= '0';
id_read_o <= '0';
crc_vec <= (others => '0');
temper_o <= (others => '0');
else
-- Samples serial input
serial_idr <= onewire_b;
-- Shifts command out
if init = '1' then
shifted_header <= header;
elsif shift_header = '1' then
shifted_header(shifted_header'left-1 downto 0) <= shifted_header(shifted_header'left downto 1);
shifted_header(shifted_header'left) <= '0';
end if;
-- Computes CRC on read data (include the received CRC itself, if no errror crc_vec = X"00")
if init = '1' then
crc_vec <= (others => '0');
elsif id_cm_reg = '1' then
crc_vec(0) <= serial_idr xor crc_vec(7);
crc_vec(3 downto 1) <= crc_vec(2 downto 0);
crc_vec(4) <= (serial_idr xor crc_vec(7)) xor crc_vec(3);
crc_vec(5) <= (serial_idr xor crc_vec(7)) xor crc_vec(4);
crc_vec(7 downto 6) <= crc_vec(6 downto 5);
end if;
-- Stores incoming data
if (id_cm_reg = '1') then
cm_reg(cm_reg'left - 1 downto 0) <= cm_reg(cm_reg'left downto 1);
cm_reg(cm_reg'left) <= serial_idr;
end if;
-- Updates serial output data
serial_id_out <= nx_serial_id_out;
-- Updates serial output enable
i_serial_id_oe <= nx_serial_id_oe;
-- Stores id_o in register
if (load_id = '1')then
i_id_read <= '1';
id_o <= cm_reg(ID_LEFT downto ID_RIGHT);
end if;
-- Stores temperature in register
if (load_temper = '1')then
temper_o <= cm_reg(TEMPER_LEFT downto TEMPER_RIGHT);
end if;
-- Delays id_o read
id_read_o <= i_id_read;
end if;
end if;
end process;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- Value on id_o port is valid_o
process(clk_i)
begin
if rising_edge(clk_i) then
if state_cm = IDLE_CM then
id_ok_o <= crc_ok;
end if;
end if;
end process;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- Detects end of read or end of write command
end_wr_cm <= '1' when (bit_cnt = to_unsigned(7, bit_cnt'length)) and (inc_bit_cnt = '1') else '0';
end_rd_cm <= '1' when (bit_cnt = bit_top) else '0';
end arch;
--=================================================================================================
-- architecture end
--=================================================================================================
---------------------------------------------------------------------------------------------------
-- E N D O F F I L E
---------------------------------------------------------------------------------------------------
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment