用于 DS18B20 温度传感器的 1 线芯的 VHDL 包装器
VHDL wrapper for 1-wire core for DS18B20 temperature sensor
目前我正在尝试为 this Opencore Verilog module (1-wire master) so that I can send/receive from this 温度传感器 (DS18B20) 编写 VHDL 包装器。
但是我很难理解它的用法。即 read/write 启用与 1-wire 主模块的 control/status 寄存器中的 cyc 位。
我目前的代码将 cyc 位设置为 1,同时将 read/write 启用为 1,但不会在每一位期间循环它们。这是正确的还是我误解了?我是 VHDL 的新手/正在阅读数据表,所以我已经为此苦苦挣扎了几天。任何帮助将不胜感激。
我发现 this site 我一直在使用它作为参考,但它不涉及我正在使用的 Verilog 模块。
我也在寻找关于我的代码风格的提示,以及一般的 VHDL 提示。
我当前的代码:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL; --may need to remove if signed not used
ENTITY one_wire_temp_probe_control IS
GENERIC (
one_us_divider_g : integer range 0 to 50 := 50 -- clock divider for one micro second
);
PORT (
i_clk_50mhz : IN STD_LOGIC;
i_read_enable : IN std_logic;
io_temp_probe : INOUT STD_LOGIC; --how do i register an inout
o_temperature : OUT signed(6 DOWNTO 0);
o_temp_ready : OUT std_logic
);
END one_wire_temp_probe_control;
ARCHITECTURE rtl of one_wire_temp_probe_control IS
----temp commands----
CONSTANT skip_rom_c : std_logic_vector(7 DOWNTO 0) := x"CC"; --command to skip ROM identity of temperature sensor
CONSTANT convert_temp_c : std_logic_vector(7 DOWNTO 0) := x"44"; --command to start temperature conversion
CONSTANT read_scratchpad_c : std_logic_vector(7 DOWNTO 0) := x"BE"; --command to read the scratchpad i.e. get temperature data
CONSTANT command_bits_c : integer RANGE 0 TO 8 := 8; --number of bits in the above commands (note: range used to limit number of bits to minimum needed)
CONSTANT data_bits_c : integer RANGE 0 to 12 := 12; --number of bits in received data
----1-wire commands----
CONSTANT send_reset_pulse : std_logic_vector(7 DOWNTO 0) := "00001010"; --command to send reset pulse
CONSTANT write_command_structure_c : std_logic_vector(6 DOWNTO 0) := "0000000"; --structure of the command that must be passed to the 1-wire controller (----EDIT----)
----timing constants----
CONSTANT delay_65us_c : integer := one_us_divider_g * 65; --65 micro-second delay
CONSTANT delay_960us_c : integer := one_us_divider_g * 960; --960 micro-second delay
CONSTANT delay_750ms : integer := one_us_divider_g * 1000 * 750; --760 milli-second delay
----state machine----
TYPE state_type IS (idle, presence_pulse, wait_presence_pulse, skip_rom, temp_conversion, wait_for_conversion,
read_scratchpad, data_read, convert_data, wait_65us);
SIGNAL state : state_type := idle;
SIGNAL previous_state : state_type := idle;
----1-wire----
SIGNAL read_enable_s, write_enable_s, reset_s, owr_e_s : std_logic := '0';
SIGNAL write_data_s, read_data_s : std_logic_vector(7 DOWNTO 0):= (OTHERS => '0'); --8 bit mode chosen in sockit_owm
SIGNAL address_s : std_logic_vector(1 DOWNTO 0) := "00";
SIGNAL timer_s : integer := 0;
----commands---
SIGNAL bit_counter_command_s : integer RANGE 0 TO command_bits_c := 0; --counter for bits in commands (note: not -1 due to using 9th bit as state change)
SIGNAL bit_counter_data_s : integer RANGE 0 TO data_bits_c := 0; --counter for bits in data recieved
----temperature----
SIGNAL temperature_raw_data : std_logic_vector(11 DOWNTO 0) := (OTHERS => '0');
----one wire control----
COMPONENT sockit_owm IS
PORT (
----control interface----
clk : IN std_logic;
rst : IN std_logic;
bus_ren : IN std_logic;
bus_wen : IN std_logic;
bus_adr : IN std_logic_vector(7 DOWNTO 0);
bus_wdt : IN std_logic_vector(7 DOWNTO 0);
bus_rdt : OUT std_logic_vector(7 DOWNTO 0);
bus_irq : OUT std_logic;
----1-wire interface----
owr_p : OUT std_logic; --verilog code is a one bit wide vector
owr_e : OUT std_logic;
owr_i : IN std_logic
);
END COMPONENT;
BEGIN
address_s <= "00"; --for the temp probe control we're not interested in other address spaces
PROCESS(i_clk_50mhz) BEGIN --state change
IF rising_edge(i_clk_50mhz) THEN
CASE state is
WHEN idle =>
o_temp_ready <= '0';
IF (i_read_enable = '1') THEN
state <= presence_pulse;
ELSE
state <= idle;
END IF;
WHEN presence_pulse =>
----send reset/presence pulse----
write_enable_s <= '1';
write_data_s <= send_reset_pulse;
timer_s <= delay_960us_c;
state <= wait_presence_pulse;
WHEN wait_presence_pulse =>
----wait for 960 micro seconds----
read_enable_s <= '1';
IF (timer_s = 0) THEN
IF (read_data_s(0) = '0') THEN
state <= skip_rom;
ELSIF (read_data_s(0) = '1') THEN
--precence not detected
ELSE
state <= wait_presence_pulse;
END IF;
ELSE
timer_s <= timer_s - 1;
state <= wait_presence_pulse;
END IF;
WHEN skip_rom =>
----send skip rom command----
previous_state <= skip_rom;
write_enable_s <= '1';
IF (bit_counter_command_s = command_bits_c) THEN
bit_counter_command_s <= 0;
state <= temp_conversion;
ELSE
write_data_s <= write_command_structure_c & skip_rom_c(bit_counter_command_s); ---command structure concatonated with 1 bit from command
bit_counter_command_s <= bit_counter_command_s + 1;
timer_s <= delay_65us_c;
state <= wait_65us;
END IF;
WHEN temp_conversion =>
----send temp conversion command to probe----
previous_state <= temp_conversion;
IF (bit_counter_command_s = bit_counter_command_s) THEN
bit_counter_command_s <= 0;
timer_s <= delay_750ms;
state <= wait_for_conversion;
ELSE
write_data_s <= write_command_structure_c & convert_temp_c(bit_counter_command_s); ---command structure concatonated with 1 bit from command
bit_counter_command_s <= bit_counter_command_s + 1;
timer_s <= delay_65us_c;
state <= wait_65us;
END IF;
WHEN wait_for_conversion =>
----wait for temperature conversion to finish----
IF (timer_s = 0) then
state <= read_scratchpad;
ELSE
timer_s <= timer_s - 1;
END IF;
WHEN read_scratchpad =>
----send read scratchpad command----
previous_state <= read_scratchpad;
IF (bit_counter_command_s = command_bits_c) THEN
state <= data_read;
bit_counter_command_s <= 0;
ELSE
write_data_s <= write_command_structure_c & read_scratchpad_c(bit_counter_command_s); ---command structure concatonated with 1 bit from command
bit_counter_command_s <= bit_counter_command_s + 1;
timer_s <= delay_65us_c;
state <= wait_65us;
END IF;
WHEN data_read =>
----read incoming data----
previous_state <= data_read;
read_enable_s <= '1';
IF (bit_counter_data_s = data_bits_c) THEN
bit_counter_data_s <= 0; --may need to invert this
state <= convert_data;
ELSE
temperature_raw_data(bit_counter_data_s) <= read_data_s(0);
bit_counter_data_s <= bit_counter_data_s + 1;
timer_s <= delay_65us_c;
state <= wait_65us;
END IF;
WHEN convert_data =>
----convert raw data into temperature----
o_temp_ready <= '1';
WHEN wait_65us =>
----wait for read/write cycle to finish----
IF (timer_s = 0) THEN
state <= previous_state;
ELSE
timer_s <= timer_s - 1;
state <= wait_65us;
END IF;
END CASE;
END IF;
END PROCESS;
----one wire component instantiation----
one_wire_control : sockit_owm
PORT MAP(
----control interface----
clk => i_clk_50mhz,
rst => reset_s,
bus_ren => read_enable_s,
bus_wen => write_enable_s,
bus_adr => address_s,
bus_wdt => write_data_s,
bus_rdt => read_data_s,
bus_irq => OPEN,
----1-wire interface----
owr_p => OPEN,
owr_e => owr_e_s,
owr_i => io_temp_probe
);
io_temp_probe <= owr_e_s ? '0' : 'Z'; --I also need help converting this line to VHDL
END rtl;
提前谢谢你。
最好
汤姆
I am also looking for tips on my code style, and VHDL tips in general.
好的。
第一件事:不要排那么长的队。所以不要把注释放在行尾。把他们放在前面。
use IEEE.NUMERIC_STD.ALL; --may need to remove if signed not used
然后删除,因为我没有看到任何 signed
one_us_divider_g : integer range 0 to 50 := 50 -- clock divider for one micro second
所以... one_us_divider_g
设置为 0 会发生什么?似乎是非法值。用它来模拟?
io_temp_probe : INOUT STD_LOGIC; --how do i register an inout
一种选择是使用三态 IOBUFFER。这是一个特殊的 FPGA 边缘元件,它将输入和输出拆分为单独的信号。您可以通过设置控制端口来三态输出。
或者,您也可以按照您在代码中的方式进行操作(例如,赛灵思综合用户指南中也对此进行了解释)。这让我想到了你代码中的另一个问题。
io_temp_probe <= owr_e_s ? '0' : 'Z'; --I also need help converting this line to VHDL
io_temp_probe <= '0' when owr_e_s = '1' else 'Z';
CONSTANT command_bits_c : integer RANGE 0 TO 8 := 8;
如果是常数,则不需要整数范围。
CONSTANT send_reset_pulse : ...
CONSTANT delay_750ms : ...
缺少您放在所有常量后面的“_c”。但无论如何我都不会添加这个“s”、“_c”或“_g”。多劳多得。
COMPONENT sockit_owm IS
PORT (
[...]
);
END COMPONENT;
一段时间以来不再需要组件声明。您可以删除它并更改您的实例化:
one_wire_control : entity work.sockit_owm
PORT MAP(
[...]
WHEN idle =>
[...]
ELSE
state <= idle;
END IF;
不需要。如果您不更改 state
,它将停留在 idle
。
WHEN wait_presence_pulse =>
IF (timer_s = 0) THEN
IF (read_data_s(0) = '0') THEN
[...]
ELSIF (read_data_s(0) = '1') THEN
[...]
ELSE
state <= wait_presence_pulse;
END IF;
read_data_s(0)
'0' 和 '1' 被覆盖。你期望任何其他价值吗?这只能在模拟中发生,而不能在实施中发生。所以最后一个 else 语句中的代码是不可访问的。
[...]
timer_s <= delay_65us_c;
state <= wait_65us;
[...]
WHEN wait_65us =>
IF (timer_s = 0) THEN
[...]
ELSE
timer_s <= timer_s - 1;
END IF;
假设延迟为 65 us,持续 10 个时钟周期。将分频器设置为 1,delay_65us_c
=10。所以在 t=0 时,timer_s
设置为 10。在 t=1 时 -state
现在是 wait_65us
- timer_s
设置为 9。依此类推:在 t =10,timer_s
设置为 0... 但 state
仍然是 wait_65us
。所以在t=11时,检测到timer_s
为0,state
改成之前的。它将在 t=12 时进入。
因此,您得到的不是 10 个时钟周期的延迟,而是 12 个时钟周期的延迟。
这是个问题吗?如果是,您应该重新考虑您的代码。
SIGNAL read_enable_s, write_enable_s, reset_s, owr_e_s : std_logic := '0';
[... not used anywhere else... ]
one_wire_control : sockit_owm
PORT MAP(
[...]
rst => reset_s,
你确定这是正确的吗?很多组件需要正确重置才能正常运行。
如果您使用的是 Quartus,则可以将 VHDL 代码与 Verilog 甚至原理图元素混合使用。在下面的 link 中,我为同一芯片 (DS18B20) 使用了 verilog 驱动程序。
详情请看这里:
https://physnoct.wordpress.com/2016/12/14/altera-quartus-combining-verilog-and-vhdl/
目前我正在尝试为 this Opencore Verilog module (1-wire master) so that I can send/receive from this 温度传感器 (DS18B20) 编写 VHDL 包装器。
但是我很难理解它的用法。即 read/write 启用与 1-wire 主模块的 control/status 寄存器中的 cyc 位。
我目前的代码将 cyc 位设置为 1,同时将 read/write 启用为 1,但不会在每一位期间循环它们。这是正确的还是我误解了?我是 VHDL 的新手/正在阅读数据表,所以我已经为此苦苦挣扎了几天。任何帮助将不胜感激。
我发现 this site 我一直在使用它作为参考,但它不涉及我正在使用的 Verilog 模块。
我也在寻找关于我的代码风格的提示,以及一般的 VHDL 提示。
我当前的代码:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL; --may need to remove if signed not used
ENTITY one_wire_temp_probe_control IS
GENERIC (
one_us_divider_g : integer range 0 to 50 := 50 -- clock divider for one micro second
);
PORT (
i_clk_50mhz : IN STD_LOGIC;
i_read_enable : IN std_logic;
io_temp_probe : INOUT STD_LOGIC; --how do i register an inout
o_temperature : OUT signed(6 DOWNTO 0);
o_temp_ready : OUT std_logic
);
END one_wire_temp_probe_control;
ARCHITECTURE rtl of one_wire_temp_probe_control IS
----temp commands----
CONSTANT skip_rom_c : std_logic_vector(7 DOWNTO 0) := x"CC"; --command to skip ROM identity of temperature sensor
CONSTANT convert_temp_c : std_logic_vector(7 DOWNTO 0) := x"44"; --command to start temperature conversion
CONSTANT read_scratchpad_c : std_logic_vector(7 DOWNTO 0) := x"BE"; --command to read the scratchpad i.e. get temperature data
CONSTANT command_bits_c : integer RANGE 0 TO 8 := 8; --number of bits in the above commands (note: range used to limit number of bits to minimum needed)
CONSTANT data_bits_c : integer RANGE 0 to 12 := 12; --number of bits in received data
----1-wire commands----
CONSTANT send_reset_pulse : std_logic_vector(7 DOWNTO 0) := "00001010"; --command to send reset pulse
CONSTANT write_command_structure_c : std_logic_vector(6 DOWNTO 0) := "0000000"; --structure of the command that must be passed to the 1-wire controller (----EDIT----)
----timing constants----
CONSTANT delay_65us_c : integer := one_us_divider_g * 65; --65 micro-second delay
CONSTANT delay_960us_c : integer := one_us_divider_g * 960; --960 micro-second delay
CONSTANT delay_750ms : integer := one_us_divider_g * 1000 * 750; --760 milli-second delay
----state machine----
TYPE state_type IS (idle, presence_pulse, wait_presence_pulse, skip_rom, temp_conversion, wait_for_conversion,
read_scratchpad, data_read, convert_data, wait_65us);
SIGNAL state : state_type := idle;
SIGNAL previous_state : state_type := idle;
----1-wire----
SIGNAL read_enable_s, write_enable_s, reset_s, owr_e_s : std_logic := '0';
SIGNAL write_data_s, read_data_s : std_logic_vector(7 DOWNTO 0):= (OTHERS => '0'); --8 bit mode chosen in sockit_owm
SIGNAL address_s : std_logic_vector(1 DOWNTO 0) := "00";
SIGNAL timer_s : integer := 0;
----commands---
SIGNAL bit_counter_command_s : integer RANGE 0 TO command_bits_c := 0; --counter for bits in commands (note: not -1 due to using 9th bit as state change)
SIGNAL bit_counter_data_s : integer RANGE 0 TO data_bits_c := 0; --counter for bits in data recieved
----temperature----
SIGNAL temperature_raw_data : std_logic_vector(11 DOWNTO 0) := (OTHERS => '0');
----one wire control----
COMPONENT sockit_owm IS
PORT (
----control interface----
clk : IN std_logic;
rst : IN std_logic;
bus_ren : IN std_logic;
bus_wen : IN std_logic;
bus_adr : IN std_logic_vector(7 DOWNTO 0);
bus_wdt : IN std_logic_vector(7 DOWNTO 0);
bus_rdt : OUT std_logic_vector(7 DOWNTO 0);
bus_irq : OUT std_logic;
----1-wire interface----
owr_p : OUT std_logic; --verilog code is a one bit wide vector
owr_e : OUT std_logic;
owr_i : IN std_logic
);
END COMPONENT;
BEGIN
address_s <= "00"; --for the temp probe control we're not interested in other address spaces
PROCESS(i_clk_50mhz) BEGIN --state change
IF rising_edge(i_clk_50mhz) THEN
CASE state is
WHEN idle =>
o_temp_ready <= '0';
IF (i_read_enable = '1') THEN
state <= presence_pulse;
ELSE
state <= idle;
END IF;
WHEN presence_pulse =>
----send reset/presence pulse----
write_enable_s <= '1';
write_data_s <= send_reset_pulse;
timer_s <= delay_960us_c;
state <= wait_presence_pulse;
WHEN wait_presence_pulse =>
----wait for 960 micro seconds----
read_enable_s <= '1';
IF (timer_s = 0) THEN
IF (read_data_s(0) = '0') THEN
state <= skip_rom;
ELSIF (read_data_s(0) = '1') THEN
--precence not detected
ELSE
state <= wait_presence_pulse;
END IF;
ELSE
timer_s <= timer_s - 1;
state <= wait_presence_pulse;
END IF;
WHEN skip_rom =>
----send skip rom command----
previous_state <= skip_rom;
write_enable_s <= '1';
IF (bit_counter_command_s = command_bits_c) THEN
bit_counter_command_s <= 0;
state <= temp_conversion;
ELSE
write_data_s <= write_command_structure_c & skip_rom_c(bit_counter_command_s); ---command structure concatonated with 1 bit from command
bit_counter_command_s <= bit_counter_command_s + 1;
timer_s <= delay_65us_c;
state <= wait_65us;
END IF;
WHEN temp_conversion =>
----send temp conversion command to probe----
previous_state <= temp_conversion;
IF (bit_counter_command_s = bit_counter_command_s) THEN
bit_counter_command_s <= 0;
timer_s <= delay_750ms;
state <= wait_for_conversion;
ELSE
write_data_s <= write_command_structure_c & convert_temp_c(bit_counter_command_s); ---command structure concatonated with 1 bit from command
bit_counter_command_s <= bit_counter_command_s + 1;
timer_s <= delay_65us_c;
state <= wait_65us;
END IF;
WHEN wait_for_conversion =>
----wait for temperature conversion to finish----
IF (timer_s = 0) then
state <= read_scratchpad;
ELSE
timer_s <= timer_s - 1;
END IF;
WHEN read_scratchpad =>
----send read scratchpad command----
previous_state <= read_scratchpad;
IF (bit_counter_command_s = command_bits_c) THEN
state <= data_read;
bit_counter_command_s <= 0;
ELSE
write_data_s <= write_command_structure_c & read_scratchpad_c(bit_counter_command_s); ---command structure concatonated with 1 bit from command
bit_counter_command_s <= bit_counter_command_s + 1;
timer_s <= delay_65us_c;
state <= wait_65us;
END IF;
WHEN data_read =>
----read incoming data----
previous_state <= data_read;
read_enable_s <= '1';
IF (bit_counter_data_s = data_bits_c) THEN
bit_counter_data_s <= 0; --may need to invert this
state <= convert_data;
ELSE
temperature_raw_data(bit_counter_data_s) <= read_data_s(0);
bit_counter_data_s <= bit_counter_data_s + 1;
timer_s <= delay_65us_c;
state <= wait_65us;
END IF;
WHEN convert_data =>
----convert raw data into temperature----
o_temp_ready <= '1';
WHEN wait_65us =>
----wait for read/write cycle to finish----
IF (timer_s = 0) THEN
state <= previous_state;
ELSE
timer_s <= timer_s - 1;
state <= wait_65us;
END IF;
END CASE;
END IF;
END PROCESS;
----one wire component instantiation----
one_wire_control : sockit_owm
PORT MAP(
----control interface----
clk => i_clk_50mhz,
rst => reset_s,
bus_ren => read_enable_s,
bus_wen => write_enable_s,
bus_adr => address_s,
bus_wdt => write_data_s,
bus_rdt => read_data_s,
bus_irq => OPEN,
----1-wire interface----
owr_p => OPEN,
owr_e => owr_e_s,
owr_i => io_temp_probe
);
io_temp_probe <= owr_e_s ? '0' : 'Z'; --I also need help converting this line to VHDL
END rtl;
提前谢谢你。 最好 汤姆
I am also looking for tips on my code style, and VHDL tips in general.
好的。
第一件事:不要排那么长的队。所以不要把注释放在行尾。把他们放在前面。
use IEEE.NUMERIC_STD.ALL; --may need to remove if signed not used
然后删除,因为我没有看到任何 signed
one_us_divider_g : integer range 0 to 50 := 50 -- clock divider for one micro second
所以... one_us_divider_g
设置为 0 会发生什么?似乎是非法值。用它来模拟?
io_temp_probe : INOUT STD_LOGIC; --how do i register an inout
一种选择是使用三态 IOBUFFER。这是一个特殊的 FPGA 边缘元件,它将输入和输出拆分为单独的信号。您可以通过设置控制端口来三态输出。
或者,您也可以按照您在代码中的方式进行操作(例如,赛灵思综合用户指南中也对此进行了解释)。这让我想到了你代码中的另一个问题。
io_temp_probe <= owr_e_s ? '0' : 'Z'; --I also need help converting this line to VHDL
io_temp_probe <= '0' when owr_e_s = '1' else 'Z';
CONSTANT command_bits_c : integer RANGE 0 TO 8 := 8;
如果是常数,则不需要整数范围。
CONSTANT send_reset_pulse : ...
CONSTANT delay_750ms : ...
缺少您放在所有常量后面的“_c”。但无论如何我都不会添加这个“s”、“_c”或“_g”。多劳多得。
COMPONENT sockit_owm IS
PORT (
[...]
);
END COMPONENT;
一段时间以来不再需要组件声明。您可以删除它并更改您的实例化:
one_wire_control : entity work.sockit_owm
PORT MAP(
[...]
WHEN idle =>
[...]
ELSE
state <= idle;
END IF;
不需要。如果您不更改 state
,它将停留在 idle
。
WHEN wait_presence_pulse =>
IF (timer_s = 0) THEN
IF (read_data_s(0) = '0') THEN
[...]
ELSIF (read_data_s(0) = '1') THEN
[...]
ELSE
state <= wait_presence_pulse;
END IF;
read_data_s(0)
'0' 和 '1' 被覆盖。你期望任何其他价值吗?这只能在模拟中发生,而不能在实施中发生。所以最后一个 else 语句中的代码是不可访问的。
[...]
timer_s <= delay_65us_c;
state <= wait_65us;
[...]
WHEN wait_65us =>
IF (timer_s = 0) THEN
[...]
ELSE
timer_s <= timer_s - 1;
END IF;
假设延迟为 65 us,持续 10 个时钟周期。将分频器设置为 1,delay_65us_c
=10。所以在 t=0 时,timer_s
设置为 10。在 t=1 时 -state
现在是 wait_65us
- timer_s
设置为 9。依此类推:在 t =10,timer_s
设置为 0... 但 state
仍然是 wait_65us
。所以在t=11时,检测到timer_s
为0,state
改成之前的。它将在 t=12 时进入。
因此,您得到的不是 10 个时钟周期的延迟,而是 12 个时钟周期的延迟。
这是个问题吗?如果是,您应该重新考虑您的代码。
SIGNAL read_enable_s, write_enable_s, reset_s, owr_e_s : std_logic := '0';
[... not used anywhere else... ]
one_wire_control : sockit_owm
PORT MAP(
[...]
rst => reset_s,
你确定这是正确的吗?很多组件需要正确重置才能正常运行。
如果您使用的是 Quartus,则可以将 VHDL 代码与 Verilog 甚至原理图元素混合使用。在下面的 link 中,我为同一芯片 (DS18B20) 使用了 verilog 驱动程序。
详情请看这里: https://physnoct.wordpress.com/2016/12/14/altera-quartus-combining-verilog-and-vhdl/