-
Notifications
You must be signed in to change notification settings - Fork 66
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adicionar implementação do protocolo onewire usando VHDL (#66)
* Create README.md * Adicionar arquivos do protocolo onewire * Adicionar figuras com diagrama de intervalo de escrita e leitura * Atualizar documentação do projeto * Corrigir data em docstring de tb.do
- Loading branch information
1 parent
bbe7e9c
commit 284ea12
Showing
10 changed files
with
414 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# Protocolo One-wire | ||
|
||
Este projeto visa a implementação do protocolo de comunicação one-wire utilizando VHDL. | ||
|
||
O protocolo one-wire é um padrão de comunicação serial utilizado para conectar dispositivos eletrônicos de forma que possam ser controlados e alimentados por um único fio de dados, além de possuírem identificação única. Ele é comumente usado em sensores de temperatura, memórias EEPROM e outros dispositivos eletrônicos de baixo custo e baixo consumo de energia. O protocolo permite que múltiplos dispositivos sejam conectados ao mesmo barramento de comunicação. | ||
|
||
A temporação utilizada neste projeto foi baseada na documentação do sensor DS18B20, um sensor de temperatura de baixo custo que utiliza o protocolo one-wire para comunicação | ||
|
||
Para implementarmos esse protocolo foi criada a seguinte máquina de estados, representada na figura abaixo. | ||
|
||
 | ||
|
||
O protocolo one-wire segue temporizações rigorosas para que os dados possam ser transmitidos de forma correta. Abaixo iremos descrever o funcionamento do protocolo em paralelo com a máquina de estados criada. | ||
|
||
### Procedimento de inicialização | ||
|
||
No protocolo OneWire, a inicialização começa quando o mestre (o dispositivo controlador) envia um pulso de reset para a linha de dados. Durante a inicialização, o mestre envia um pulso de reset por um determinado periodo de tempo e espera a resposta de algum dispositivo no barramento de dados, esse processo ocorre entre os estados __RESET, SAMPLE DEVICE RESPONSE e DEVICE RECOVERY RESPONSE__. Caso dentro de uma janela específica de tempo algum dispositivo não puxe o barramento de dados para o GND sinalizando sua presença, a máquina de estados volta para o estado IDLE e reinicia o processo de inicialização buscando novamente por um dispositivo. Caso obtenha a resposta de algum dispositivo, a máquina prossegue para a fase de escrita no barramento. A figura a seguir demonstra a temporização e como funciona esse procedimento. | ||
|
||
 | ||
|
||
### WRITE | ||
Durante a escrita, desejamos enviar algum comando para que o dispositivo nos responda com os dados requisitados. Esse envio é feito seguindo um protocolo restrito de temporização para o envio de cada bit do comando. Abaixo segue as especificações de temporização utilizadas para o envio de um bit. | ||
|
||
 | ||
|
||
O envio dos bits é feito entre os estados __MASTER WRITE, MASTER WRITE SLOT E MASTER WRITE RECOVERY__, onde será iterado em cada um dos bits do comando de escrita e serão enviados para o dispositivo. Após o envio do comando entramos num estado __MASTER POST WRITE DELAY__ antes de iniciarmos o processo de leitura. | ||
|
||
### READ | ||
Da mesma forma que a escrita, a leitura da resposta do dispositivo segue temporização rigorosa. Abaixo seguem dois diagramas detalhando melhor as especificações utilizadas durante o processo de leitura. | ||
|
||
 | ||
|
||
 | ||
|
||
Durante o processo de escrita iremos ciclar entre os estados __MASTER READ, MASTER AWAIT READ SAMPLE E MASTER READ RECOVERY__, atuando de forma cíclica extremamente similar a como fazemos o processo de escrita, porém trabalhando com temporizações diferentes. Após a leitura de todos os bits de resposta do dispositivo finalmente vamos para um estado de recuperação __MASTER POST READ DELAY__ e finalmente chegamos no fim da implementação do protocolo no estado __DONE__. | ||
|
||
### ToDo | ||
Atualmente foi implementado o envio e leitura de dados utilizando a temporização adequada do protocolo, porém demonstrando a leitura e escrita utilizando valores **hardcoded**. A adequação do projeto para que ele possa enviar qualquer tipo de comando e também tratar os dados adequadamente seria o próximo passo importante neste projeto | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,272 @@ | ||
------------------------------------------------------- | ||
--! file: onewire.vhd | ||
--! author: Eric Monteiro dos Reis | ||
--! Description: OneWire Protocol implementation following the timing specifications for the DS18B20 sensor available at: | ||
--! https://www.analog.com/media/en/technical-documentation/data-sheets/ds18b20.pdf | ||
--! For more details about how the onewire protocol was implemented here, access: https://github.com/ericreis27/vhdl_onewire | ||
------------------------------------------------------- | ||
|
||
library ieee; | ||
use ieee.std_logic_1164.all; | ||
use ieee.numeric_std.all; | ||
|
||
|
||
entity onewire is | ||
-- all generic values below represent a micro-seconds time value. | ||
generic ( | ||
RESET_PULSE_TIME : positive := 500; | ||
SAMPLE_RESPONSE_TIME : positive := 100; | ||
DEVICE_RESPONSE_RECOVERY_TIME : positive := 400; | ||
SEND_DATA_WAIT_TIME: positive := 500; | ||
MASTER_WRITE_TIME : positive := 10; | ||
MASTER_WRITE_SLOT_TIME : positive := 50; | ||
MASTER_WRITE_RECOVERY_TIME : positive := 5; | ||
MASTER_POST_WRITE_DELAY_TIME : positive := 480; | ||
MASTER_AWAIT_READ_SAMPLE_TIME : positive := 10; | ||
MASTER_READ_RECOVERY_TIME: positive := 55; | ||
MASTER_POST_READ_DELAY_TIME : positive := 480 | ||
); | ||
|
||
port ( | ||
clk : in std_logic; | ||
rst : in std_logic; | ||
data_bus : inout std_logic | ||
); | ||
end entity onewire; | ||
|
||
architecture rtl of onewire is | ||
type state_type is ( | ||
IDLE, | ||
RESET, | ||
SAMPLE_DEVICE_RESPONSE, | ||
DEVICE_RECOVERY_RESPONSE, | ||
MASTER_WRITE_DELAY, | ||
MASTER_WRITE, | ||
MASTER_WRITE_SLOT, | ||
MASTER_WRITE_RECOVERY, | ||
MASTER_POST_WRITE_DELAY, | ||
MASTER_READ, | ||
MASTER_AWAIT_READ_SAMPLE, | ||
MASTER_READ_RECOVERY, | ||
MASTER_POST_READ_DELAY, | ||
DONE | ||
); | ||
signal all_zeros : unsigned(31 downto 0) := (others => '0'); | ||
signal state : state_type; | ||
signal tristate : std_logic; -- this is used to control the inout data_bus | ||
signal iterator : unsigned(2 downto 0) := "000"; | ||
signal counter_clk : std_logic; | ||
signal time_slot : unsigned(31 downto 0); | ||
begin | ||
data_bus <= '0' when tristate = '0' else 'Z'; | ||
state_transition : process (counter_clk, rst) is | ||
variable device_response_flag : std_logic := '1'; | ||
begin | ||
if rst = '1' then | ||
state <= IDLE; | ||
|
||
elsif rising_edge(counter_clk) then | ||
case state is | ||
when IDLE => | ||
state <= RESET; | ||
when RESET => | ||
state <= SAMPLE_DEVICE_RESPONSE; | ||
when SAMPLE_DEVICE_RESPONSE => | ||
if (data_bus = '0') then | ||
device_response_flag := data_bus; | ||
else | ||
device_response_flag := '1'; --this is done so the device_response_flag doesn't have a tristate value due to the data_bus. | ||
end if; | ||
|
||
state <= DEVICE_RECOVERY_RESPONSE; | ||
when DEVICE_RECOVERY_RESPONSE => | ||
if (device_response_flag = '0') then | ||
state <= MASTER_WRITE_DELAY; | ||
else | ||
state <= IDLE; | ||
end if; | ||
when MASTER_WRITE_DELAY => | ||
state <= MASTER_WRITE; | ||
when MASTER_WRITE => | ||
state <= MASTER_WRITE_SLOT; | ||
when MASTER_WRITE_SLOT => | ||
state <= MASTER_WRITE_RECOVERY; | ||
|
||
when MASTER_WRITE_RECOVERY => | ||
if (iterator = 7) then | ||
state <= MASTER_POST_WRITE_DELAY; | ||
iterator <= (others => '0'); | ||
else | ||
iterator <= iterator + 1; | ||
state <= MASTER_WRITE; | ||
end if; | ||
when MASTER_POST_WRITE_DELAY => | ||
state <= MASTER_READ; | ||
when MASTER_READ => | ||
state <= MASTER_AWAIT_READ_SAMPLE; | ||
when MASTER_AWAIT_READ_SAMPLE => | ||
state <= MASTER_READ_RECOVERY; | ||
when MASTER_READ_RECOVERY => | ||
if (iterator = 7) then | ||
state <= MASTER_POST_READ_DELAY; | ||
iterator <= (others => '0'); | ||
else | ||
iterator <= iterator + 1; | ||
state <= MASTER_READ; | ||
end if; | ||
when MASTER_POST_READ_DELAY => | ||
state <= DONE; | ||
when DONE => | ||
null; | ||
end case; | ||
end if; | ||
end process state_transition; | ||
|
||
state_machine_control : process (state, iterator) is | ||
variable write_command : std_logic_vector(7 downto 0) := "00110011"; -- command value to be sent for test purposes | ||
variable data_buffer : std_logic_vector(7 downto 0) := "00000000"; -- buffer to be used to save the incoming values while reading from the device | ||
begin | ||
tristate <= '1'; | ||
case state is | ||
when IDLE => | ||
null; | ||
when RESET => | ||
tristate <= '0'; | ||
when SAMPLE_DEVICE_RESPONSE => | ||
null; | ||
when DEVICE_RECOVERY_RESPONSE => | ||
null; | ||
when MASTER_WRITE_DELAY => | ||
null; | ||
when MASTER_WRITE => | ||
tristate <= '0'; | ||
when MASTER_WRITE_SLOT => | ||
if (write_command(to_integer(iterator)) = '1') then | ||
tristate <= '1'; | ||
else | ||
tristate <= '0'; | ||
end if; | ||
when MASTER_WRITE_RECOVERY => | ||
tristate <= '1'; | ||
when MASTER_POST_WRITE_DELAY => | ||
null; | ||
when MASTER_READ => | ||
tristate <= '0'; | ||
when MASTER_AWAIT_READ_SAMPLE => | ||
tristate <= '1'; | ||
when MASTER_READ_RECOVERY => | ||
if (data_bus = '0') then | ||
data_buffer(to_integer(iterator)) := '0'; | ||
else | ||
data_buffer(to_integer(iterator)) := '1'; | ||
end if; | ||
when MASTER_POST_READ_DELAY => | ||
null; | ||
when DONE => | ||
null; | ||
end case; | ||
end process state_machine_control; | ||
|
||
counter : process (clk, rst) is | ||
begin | ||
if rst = '1' then | ||
time_slot <= to_unsigned(1, time_slot'length); | ||
elsif rising_edge(clk) then | ||
case state is | ||
when IDLE => | ||
if (time_slot > 0) then | ||
time_slot <= (others => '0'); | ||
else | ||
time_slot <= time_slot + 1; | ||
end if; | ||
when RESET => | ||
if (time_slot >= RESET_PULSE_TIME - 1) then | ||
time_slot <= (others => '0'); | ||
else | ||
time_slot <= time_slot + 1; | ||
end if; | ||
when SAMPLE_DEVICE_RESPONSE => | ||
if (time_slot >= SAMPLE_RESPONSE_TIME - 1) then | ||
time_slot <= (others => '0'); | ||
else | ||
time_slot <= time_slot + 1; | ||
end if; | ||
when DEVICE_RECOVERY_RESPONSE => | ||
if (time_slot >= DEVICE_RESPONSE_RECOVERY_TIME - 1) then | ||
time_slot <= (others => '0'); | ||
else | ||
time_slot <= time_slot + 1; | ||
end if; | ||
when MASTER_WRITE_DELAY => | ||
if (time_slot >= SEND_DATA_WAIT_TIME - 1) then | ||
time_slot <= (others => '0'); | ||
else | ||
time_slot <= time_slot + 1; | ||
end if; | ||
|
||
when MASTER_WRITE => | ||
if (time_slot >= MASTER_WRITE_TIME - 1) then | ||
time_slot <= (others => '0'); | ||
else | ||
time_slot <= time_slot + 1; | ||
end if; | ||
when MASTER_WRITE_SLOT => | ||
if (time_slot >= MASTER_WRITE_SLOT_TIME - 1) then | ||
time_slot <= (others => '0'); | ||
else | ||
time_slot <= time_slot + 1; | ||
end if; | ||
when MASTER_WRITE_RECOVERY => | ||
if (time_slot >= MASTER_WRITE_RECOVERY_TIME - 1) then | ||
time_slot <= (others => '0'); | ||
else | ||
time_slot <= time_slot + 1; | ||
end if; | ||
when MASTER_POST_WRITE_DELAY => | ||
if (time_slot >= MASTER_POST_WRITE_DELAY_TIME - 1) then | ||
time_slot <= (others => '0'); | ||
else | ||
time_slot <= time_slot + 1; | ||
end if; | ||
when MASTER_READ => | ||
if (time_slot > 0) then | ||
time_slot <= (others => '0'); | ||
else | ||
time_slot <= time_slot + 1; | ||
end if; | ||
when MASTER_AWAIT_READ_SAMPLE => | ||
if (time_slot >= MASTER_AWAIT_READ_SAMPLE_TIME - 1) then | ||
time_slot <= (others => '0'); | ||
else | ||
time_slot <= time_slot + 1; | ||
end if; | ||
when MASTER_READ_RECOVERY => | ||
if (time_slot >= MASTER_READ_RECOVERY_TIME - 1) then | ||
time_slot <= (others => '0'); | ||
else | ||
time_slot <= time_slot + 1; | ||
end if; | ||
when MASTER_POST_READ_DELAY => | ||
if (time_slot >= MASTER_POST_READ_DELAY_TIME - 1) then | ||
time_slot <= (others => '0'); | ||
else | ||
time_slot <= time_slot + 1; | ||
end if; | ||
when DONE => | ||
null; | ||
end case; | ||
end if; | ||
end process counter; | ||
|
||
-- process responsible to make the state machine sensible to time_slot reaching a specific time value depending on the current state | ||
counter_clk_cycle : process (time_slot) | ||
begin | ||
if time_slot = all_zeros then | ||
counter_clk <= '1'; | ||
else | ||
counter_clk <= '0'; | ||
end if; | ||
end process; | ||
|
||
end architecture rtl; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#------------------------------------------------------------------- | ||
#-- File: tb.do | ||
#-- Author : Eric M. dos Reis | ||
#-- Date : 15 de dez. de 2023 | ||
#------------------------------------------------------------------- | ||
|
||
#Cria biblioteca do projeto | ||
vlib work | ||
|
||
#compila projeto: todos os arquivos. Ordem é importante | ||
vcom -93 onewire.vhd testbench.vhd | ||
|
||
#Simula (work é o diretorio, testbench é o nome da entity) | ||
vsim -voptargs="+acc" -t ns work.testbench | ||
|
||
#Mosta forma de onda | ||
view wave | ||
|
||
#Adiciona ondas específicas | ||
# -radix: binary, hex, dec | ||
# -label: nome da forma de onda | ||
add wave -label "clk" -radix binary /clk | ||
add wave -label "Clock" -radix binary /dut/counter_clk | ||
add wave -label "Reset" -radix binary /rst | ||
add wave -label "Data" -radix binary /data_bus | ||
add wave -label "State" -radix symbolic /dut/state | ||
add wave -label "recovery_flag" -radix binary /dut/state_transition/device_response_flag | ||
add wave -label "data_buffer" -radix binary /dut/state_machine_control/data_buffer | ||
add wave -label "iterator" -radix binary /dut/iterator | ||
|
||
#Simula até 6000us | ||
run 6000us | ||
|
||
wave zoomfull | ||
write wave wave.ps |
Oops, something went wrong.