Оболочка VHDL для одножильного провода для датчика температуры DS18B20

В настоящее время я пытаюсь написать оболочку VHDL для этого модуля Opencore Verilog (однопроводный мастер), чтобы я мог отправлять / получать от этого датчика температуры (DS18B20).

Однако я изо всех сил пытаюсь понять использование. А именно, разрешение чтения / записи в сравнении с битом цикла в регистре управления / состояния 1-проводного мастер-модуля.

Код, который у меня есть, устанавливает бит цикла равным 1 и активирует чтение / запись одновременно, но не циклически повторяет их во время каждого бита. Это правильно или я неправильно понимаю? Я новичок в VHDL/ читаю таблицу данных, поэтому я боролся за это в течение нескольких дней. Любая помощь будет оценена.

Я нашел этот сайт, который я использовал в качестве ссылки, но он не имеет отношения к модулю 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;

Заранее спасибо. Лучший Том

2 ответа

Решение

Я также ищу советы по моему стилю кода и советы по VHDL в целом.

ХОРОШО.

Во-первых, не делайте линии так долго. Так что не ставьте комментарии в конце строки. Поставь им строчку раньше.


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. Это специальный краевой элемент ПЛИС, который разделяет вход и выход на отдельные сигналы. Вы можете выбрать выходное значение, установив порт управления.

В качестве альтернативы вы можете просто сделать это так, как вы делаете в своем коде (это также объясняется, например, в руководстве пользователя по синтезу Xilinx). Что приводит меня к другому вопросу в вашем коде.

io_temp_probe <= owr_e_s? "0": "Z"; - Мне также нужна помощь в преобразовании этой строки в 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 мА длится 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 и даже с элементами схемы. В приведенной ниже ссылке я использую драйвер Verilog для того же чипа (DS18B20).

Подробнее см. здесь:https://physnoct.wordpress.com/2016/12/14/altera-quartus-combining-verilog-and-vhdl/

Другие вопросы по тегам