OpenCores
URL https://opencores.org/ocsvn/manchesteruart/manchesteruart/trunk

Subversion Repositories manchesteruart

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 1 to Rev 2
    Reverse comparison

Rev 1 → Rev 2

/manchesteruart/trunk/bench/vhdl/manchester_tb.vhd
0,0 → 1,209
--*************************************************************************
--* *
--* Copyright (C) 2014 William B Hunter - LGPL *
--* *
--* This source file may be used and distributed without *
--* restriction provided that this copyright statement is not *
--* removed from the file and that any derivative work contains *
--* the original copyright notice and the associated disclaimer. *
--* *
--* This source file is free software; you can redistribute it *
--* and/or modify it under the terms of the GNU Lesser General *
--* Public License as published by the Free Software Foundation; *
--* either version 2.1 of the License, or (at your option) any *
--* later version. *
--* *
--* This source is distributed in the hope that it will be *
--* useful, but WITHout ANY WARRANTY; without even the implied *
--* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR *
--* PURPOSE. See the GNU Lesser General Public License for more *
--* details. *
--* *
--* You should have received a copy of the GNU Lesser General *
--* Public License along with this source; if not, download it *
--* from http://www.opencores.org/lgpl.shtml *
--* *
--*************************************************************************
--
-- Engineer: William B Hunter
-- Create Date: 08/08/2014
-- Project: Manchester Uart
-- File: Manchester_tb.vhd
-- Description: This is a testbench for the Manchester UART. It consists of two instances of
-- the UART, both run on independant clocks. The clocks start off at the same frequency (
-- 16x 9600 baud), and one is slowly decreaased to check the robustness of the uart to
-- differences in clock frequencies. Currently it fails when the clocks are about 18% different.
-- The test bench consists of the two UARTs, each has a feeder process and a capture process.
-- The feeder sends data to the transmitters, and the capture process is simply to make viewing
-- the output more convenient.
 
----------------------------------------------------------------------------------
 
 
entity manchester_tb is
 
end manchester_tb;
 
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
architecture Behavioral of manchester_tb is
signal sdat_1to2 : std_logic := '1';
signal sdat_2to1 : std_logic := '1';
signal clk1 : std_logic := '1';
signal clk2 : std_logic := '1';
signal xrst : std_logic := '1';
signal txerr1 : std_logic := '0';
signal txidle1 : std_logic := '0';
signal rxerr1 : std_logic := '0';
signal rxidle1 : std_logic := '0';
signal txdata1 : std_logic_vector(15 downto 0) := x"0000";
signal txstb1 : std_logic := '0';
signal rxdata1 : std_logic_vector(15 downto 0) := x"0000";
signal rxstb1 : std_logic := '0';
signal txerr2 : std_logic := '0';
signal txidle2 : std_logic := '0';
signal rxerr2 : std_logic := '0';
signal rxidle2 : std_logic := '0';
signal txdata2 : std_logic_vector(15 downto 0) := x"0000";
signal txstb2 : std_logic := '0';
signal rxdata2 : std_logic_vector(15 downto 0) := x"0000";
signal rxstb2 : std_logic := '0';
signal clk2_time : time := 3.255 ns;
signal cap1 : std_logic_vector(15 downto 0) := x"0000";
signal cap2 : std_logic_vector(15 downto 0) := x"0000";
 
begin
 
xrst <= '1', '0' after 1000 ns;
--clk1 is a fixed 16x 9600 clock
p_clk1 :process
begin
clk1 <= '0';
wait for 3.255 us;
clk1 <= '1';
wait for 3.255 us;
end process;
 
--this process slowly decreases the clk2 by 100 ns every 10 ms
p_clkmod :process
begin
clk2_time <= 3.255 us;
while true loop
wait for 10 ms;
clk2_time <= clk2_time - 100 ns;
end loop;
end process;
--this is the slowly decreasing clock 2
p_clk2 :process
begin
clk2 <= '0';
wait for clk2_time;
clk2 <= '1';
wait for clk2_time;
end process;
 
--first UART
u_manch1 : entity work.Manchester(rtl)
port map(
clk16x => clk1,
srst => xrst,
rxd => sdat_2to1,
rx_data => rxdata1,
rx_stb => rxstb1,
rx_idle => rxidle1,
fm_err => rxerr1,
txd => sdat_1to2,
tx_data => txdata1,
tx_stb => txstb1,
tx_idle => txidle1,
or_err => txerr1
);
--second UART
u_manch2 : entity work.Manchester(rtl)
port map(
clk16x => clk2,
srst => xrst,
rxd => sdat_1to2,
rx_data => rxdata2,
rx_stb => rxstb2,
rx_idle => rxidle2,
fm_err => rxerr2,
txd => sdat_2to1,
tx_data => txdata2,
tx_stb => txstb2,
tx_idle => txidle2,
or_err => txerr2
);
 
--feeder 1 - feeds data into UART1's transmitter
p_feeder1 : process
begin
txdata1 <= x"aaaa";
txstb1 <= '0';
wait until xrst = '0';
for i in 1 to 100 loop
wait until clk1 = '1';
end loop;
while unsigned(txdata1) < x"abaa" loop
wait until clk1 = '1';
if txidle1 = '1' then
wait for 400 us;
wait until clk1 = '0';
txdata1 <= std_logic_vector(unsigned(txdata1) + x"0001");
txstb1 <= '1';
wait until clk1 = '0';
txstb1 <= '0';
wait until clk1 = '0';
end if;
end loop;
end process;
 
 
--feeder 2 - feeds data into UART2's tranmitter
p_feeder2 : process
begin
txdata2 <= x"5555";
txstb2 <= '0';
wait until xrst = '0';
for i in 1 to 100 loop
wait until clk2 = '1';
end loop;
while unsigned(txdata2) > x"5455" loop
wait until clk2 = '1';
if txidle2 = '1' then
wait for 400 us;
wait until clk2 = '0';
txdata2 <= std_logic_vector(unsigned(txdata2) - x"0001");
txstb2 <= '1';
wait until clk2 = '0';
txstb2 <= '0';
wait until clk2 = '0';
end if;
end loop;
end process;
--cap1 - captures rx data from UART1's reciever for easy viewing
p_cap1 : process
begin
wait until rxstb1 = '1';
wait until clk1 = '0';
cap1 <= rxdata1;
end process;
--cap2 - captures rx data from UART2's reciver for easy viewing
p_cap2 : process
begin
wait until rxstb2 = '1';
wait until clk2 = '0';
cap2 <= rxdata2;
end process;
 
end Behavioral;
/manchesteruart/trunk/rtl/vhdl/decode.vhd
0,0 → 1,239
--*************************************************************************
--* *
--* Copyright (C) 2014 William B Hunter - LGPL *
--* *
--* This source file may be used and distributed without *
--* restriction provided that this copyright statement is not *
--* removed from the file and that any derivative work contains *
--* the original copyright notice and the associated disclaimer. *
--* *
--* This source file is free software; you can redistribute it *
--* and/or modify it under the terms of the GNU Lesser General *
--* Public License as published by the Free Software Foundation; *
--* either version 2.1 of the License, or (at your option) any *
--* later version. *
--* *
--* This source is distributed in the hope that it will be *
--* useful, but WITHout ANY WARRANTY; without even the implied *
--* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR *
--* PURPOSE. See the GNU Lesser General Public License for more *
--* details. *
--* *
--* You should have received a copy of the GNU Lesser General *
--* Public License along with this source; if not, download it *
--* from http://www.opencores.org/lgpl.shtml *
--* *
--*************************************************************************
--
-- Engineer: William B Hunter
-- Create Date: 08/08/2014
-- Project: Manchester Uart
-- File: decode.vhd
-- Description: This decoder recieves short bursts of 16 bit data words encoded with as manchester data.
-- Because this is not a stream decoder, it has no sync pattern or packet alignment typical of manchester decoders.
-- It therefore uses start and stop bits much like a UART. Both the start and stop bits are always ones. The idle
-- state is always high, and the ones are a low to high transition in the middle of the bit period, and a zero is a
-- high to low transition in the middle of the bit period. A high for 3 bit periods is a reset/resync.
----------------------------------------------------------------------------------
 
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity decode is
Port(
clk16x : in STD_LOGIC;
srst : in STD_LOGIC;
rxd : in STD_LOGIC;
rx_data : out STD_LOGIC_VECTOR (15 downto 0);
rx_stb : out STD_LOGIC;
fm_err : out STD_LOGIC;
rx_idle : out STD_LOGIC
);
end decode;
 
architecture rtl of decode is
signal shifter : std_logic_vector(15 downto 0);
signal tick_cnt : integer range 0 to 31 := 0;
signal bit_cnt : integer range 0 to 15 := 0;
signal rcv_stb : std_logic := '0';
signal debounce : std_logic_vector(3 downto 0) := (others=>'1');
signal filt : std_logic := '1';
signal filt_old : std_logic := '1';
signal fall_det : std_logic := '0';
signal rst_det : std_logic := '0';
signal rst_cnt :integer range 0 to 15 := 0;
signal rise_det : std_logic := '0';
type rcv_state_type is (SM_SEEK, SM_START, SM_RCV, SM_END, SM_ERR);
signal rcv_state : rcv_state_type := SM_SEEK;
begin
--this process debounces the input signal to remove noise. It also detects rising
-- and falling edges and reset conditions.
p_debounce: process(clk16x)
begin
if rising_edge(clk16x) then
if srst = '1' then
debounce <= "1111";
rise_det <= '0';
fall_det <= '0';
rst_cnt <= 0;
rst_det <= '0';
filt_old <= '1';
else
if filt_old = '0' and filt = '1' then
rise_det <= '1';
fall_det <= '0';
elsif filt_old = '1' and filt = '0' then
rise_det <= '0';
fall_det <= '1';
else
rise_det <= '0';
fall_det <= '0';
end if;
if filt = '0' then
rst_cnt <= 0;
rst_det <= '0';
elsif rst_cnt = 47 then
rst_det <= '1';
else
rst_det <= '0';
rst_cnt <= rst_cnt +1;
end if;
debounce <= debounce(2 downto 0) & rxd;
filt_old <= filt;
end if;
end if;
end process;
--this is the actual debounce logic. It is a basic 2 out of three majority vote
with debounce(3 downto 1) select filt <=
'1' when "111",
'1' when "110",
'1' when "101",
'1' when "011",
'0' when others;
--This process is the main reciever. It detects the start bit, 16 data bits and the stop bit.
-- it does this by having a window for which it looks for the midbit transistions. When a transition is found,
-- it syncs on the new transition so that it can look for the next. This allows the wide variation in clock rates
-- between the transmitter and reciever.
p_reciever: process(clk16x)
begin
if rising_edge(clk16x) then
if srst = '1' then
rcv_state <= SM_SEEK;
rcv_stb <= '0';
tick_cnt <= 0;
bit_cnt <= 0;
else
case rcv_state is
--The idle state is high, so look for the leading edge of the start bit which is a falling edge
when SM_SEEK =>
rcv_stb <= '0';
tick_cnt <= 0;
bit_cnt <= 0;
if fall_det = '1' then
rcv_state <= SM_START;
end if;
--After the falling edge, there should be the mid bit rising edge of the start bit, Make sure
-- this appears in the right window
when SM_START =>
--skip the first 4 clock periods
if tick_cnt < 4 then
tick_cnt <= tick_cnt + 1;
--The active window is ticks 4 to 10, look for the rising edge in this window
elsif tick_cnt < 11 then
--a rising edge in the window allows us to start recieveing data
if rise_det = '1' then
tick_cnt <= 0;
rcv_state <= SM_RCV;
--two falling edges in a row is an error
elsif fall_det = '1' then
rcv_state <= SM_ERR;
tick_cnt <= 0;
bit_cnt <= 0;
else
tick_cnt <= tick_cnt + 1;
end if;
--if there was no rising edge in the window, than error out
else
rcv_state <= SM_ERR;
tick_cnt <= 0;
bit_cnt <= 0;
end if;
when SM_RCV =>
--During recieve, we only look for the mid bit transisions in the window of
-- 12 to 18 ticks from the previous mid bit transition
if tick_cnt < 12 then
tick_cnt <= tick_cnt + 1;
elsif tick_cnt < 19 then
if rise_det = '1' or fall_det = '1' then
tick_cnt <= 0;
shifter <= shifter(14 downto 0) & rise_det;
if bit_cnt = 15 then
rcv_state <= SM_END;
tick_cnt <= 0;
else
bit_cnt <= bit_cnt + 1;
end if;
else
tick_cnt <= tick_cnt + 1;
end if;
else
rcv_state <= SM_ERR;
tick_cnt <= 0;
bit_cnt <= 0;
end if;
when SM_END =>
--after all 16 data bits, we should see a stop bit which is always 1 (rising edge)
if tick_cnt < 12 then
tick_cnt <= tick_cnt + 1;
elsif tick_cnt < 19 then
if rise_det = '1' then
tick_cnt <= 0;
bit_cnt <= 0;
rcv_stb <= '1';
rcv_state <= SM_SEEK;
elsif fall_det = '1' then
rcv_state <= SM_ERR;
tick_cnt <= 0;
bit_cnt <= 0;
else
tick_cnt <= tick_cnt + 1;
end if;
else
rcv_state <= SM_ERR;
tick_cnt <= 0;
bit_cnt <= 0;
end if;
--this state handles the error conditions. The error persists until a reset condition
--It is up to external logic to latch errors if nessesary
when SM_ERR =>
rcv_stb <= '0';
tick_cnt <= 4;
bit_cnt <= 0;
if rst_det = '1' then
rcv_state <= SM_SEEK;
end if;
--we should never get here
when others =>
rcv_stb <= '0';
tick_cnt <= 4;
bit_cnt <= 0;
rcv_state <= SM_SEEK;
end case;
end if; --srst
end if; --clk16x
end process;
rx_idle <= '1' when rcv_state = SM_SEEK else '0';
fm_err <= '1' when rcv_state = SM_ERR else '0';
rx_data <= shifter;
rx_stb <= rcv_stb;
 
end rtl;
/manchesteruart/trunk/rtl/vhdl/Manchester.vhd
0,0 → 1,108
--*************************************************************************
--* *
--* Copyright (C) 2014 William B Hunter - LGPL *
--* *
--* This source file may be used and distributed without *
--* restriction provided that this copyright statement is not *
--* removed from the file and that any derivative work contains *
--* the original copyright notice and the associated disclaimer. *
--* *
--* This source file is free software; you can redistribute it *
--* and/or modify it under the terms of the GNU Lesser General *
--* Public License as published by the Free Software Foundation; *
--* either version 2.1 of the License, or (at your option) any *
--* later version. *
--* *
--* This source is distributed in the hope that it will be *
--* useful, but WITHout ANY WARRANTY; without even the implied *
--* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR *
--* PURPOSE. See the GNU Lesser General Public License for more *
--* details. *
--* *
--* You should have received a copy of the GNU Lesser General *
--* Public License along with this source; if not, download it *
--* from http://www.opencores.org/lgpl.shtml *
--* *
--*************************************************************************
--
-- Engineer: William B Hunter
-- Create Date: 08/08/2014
-- Project: Manchester Uart
-- File: manchester.vhd - a Manchester encoded UART
-- Description: This is a wrapper for teh encoder and decoder.
--
-- Justification: The use of the Manchester UART has some advantages of a standard UART.
-- 1. The Manchester UART can tolerate about 18% difference in timing between the transmitter and reciever.
-- This is very useful if one or both of the systems don't have an accurate clock. RC oscillators can be used
-- instead of crystals. No PLL is required for recovery of the data signal.
-- 2. The Manchester UART is better when powering low power (devices off of the serial lines (parasitic power).
-- A typical UART can have a continuous low output for 9 bit times, whereas the Manchester UART has a max
-- low time of 1 bit time.
-- There is also a disadvantage of the Manchester UART. It can have twice the transitions per bit compared to
-- a normal UART.This requires twice the bandwidth in the UART dirvers for a given data rate.
--
-- Operational Description: This is a Manchester encoded UART - It encodes 16 bit data grams using Manchester encoding.
-- This unit is designed for short data bursts rather than stream encoding typical of Manchester systesm.
-- Since this is a burst encoder, it relys on start and stop bits for synchronization instead of sync patterns.
-- The Manchester UART goes to an idle state when no data is being transmitted. The idle state is a logic high.
-- Bits are encoded by a high to low (zero) or low to high(one) transition in the middle of the bit period. Start
-- and stop bits are always ones (low to high transitions).
----------------------------------------------------------------------------------
 
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
 
-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
 
entity Manchester is
Port (
clk16x : in STD_LOGIC;
srst : in STD_LOGIC;
rxd : in STD_LOGIC;
rx_data : out STD_LOGIC_VECTOR (15 downto 0);
rx_stb : out STD_LOGIC;
rx_idle : out STD_LOGIC;
fm_err : out STD_LOGIC;
txd : out STD_LOGIC;
tx_data : in STD_LOGIC_VECTOR (15 downto 0);
tx_stb : in STD_LOGIC;
tx_idle : out STD_LOGIC;
or_err : out STD_LOGIC
);
end Manchester;
 
architecture rtl of Manchester is
 
begin
 
u_decode : entity work.decode(rtl)
port map(
clk16x => clk16x,
srst => srst,
rxd => rxd,
rx_data => rx_data,
rx_stb => rx_stb,
fm_err => fm_err,
rx_idle => rx_idle
);
 
u_encode : entity work.encode(rtl)
port map(
clk16x => clk16x,
srst => srst,
txd => txd,
tx_data => tx_data,
tx_stb => tx_stb,
or_err => or_err,
tx_idle => tx_idle
);
 
end rtl;
/manchesteruart/trunk/rtl/vhdl/encode.vhd
0,0 → 1,162
--*************************************************************************
--* *
--* Copyright (C) 2014 William B Hunter - LGPL *
--* *
--* This source file may be used and distributed without *
--* restriction provided that this copyright statement is not *
--* removed from the file and that any derivative work contains *
--* the original copyright notice and the associated disclaimer. *
--* *
--* This source file is free software; you can redistribute it *
--* and/or modify it under the terms of the GNU Lesser General *
--* Public License as published by the Free Software Foundation; *
--* either version 2.1 of the License, or (at your option) any *
--* later version. *
--* *
--* This source is distributed in the hope that it will be *
--* useful, but WITHout ANY WARRANTY; without even the implied *
--* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR *
--* PURPOSE. See the GNU Lesser General Public License for more *
--* details. *
--* *
--* You should have received a copy of the GNU Lesser General *
--* Public License along with this source; if not, download it *
--* from http://www.opencores.org/lgpl.shtml *
--* *
--*************************************************************************
--
-- Engineer: William B Hunter
-- Create Date: 08/08/2014
-- Project: Manchester Uart
-- File: encode.vhd
-- Description: This encoder sends out short bursts of 16 bit data words encoded with as manchester data.
-- Because this is not a stream encoder, it has no sync pattern or packet alignment typical of manchester encoders.
-- It therefor uses start and stop bits much like a UART. Both the start and stop bits are always ones. The idle
-- state is always high, and the ones are a low to high transition in the middle of the bit period, and a zero is a
-- high to low transition in the middle of the bit period. A high for 3 bit periods is a reset/resync.
----------------------------------------------------------------------------------
 
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity encode is
Port (
clk16x : in STD_LOGIC;
srst : in STD_LOGIC;
tx_data : in STD_LOGIC_VECTOR (15 downto 0);
tx_stb : in STD_LOGIC;
txd : out STD_LOGIC;
or_err : out STD_LOGIC;
tx_idle : out STD_LOGIC
);
end encode;
 
architecture rtl of encode is
signal shifter : std_logic_vector(15 downto 0);
signal tick_cnt : integer range 0 to 15 := 0;
signal bit_cnt : integer range 0 to 15 := 0;
signal txd_int : std_logic := '1';
signal err_int : std_logic := '0';
 
type txr_state_type is (SM_IDLE, SM_START, SM_SEND, SM_STOP);
signal txr_state : txr_state_type := SM_IDLE;
 
begin
 
p_transmitter: process(clk16x)
begin
if rising_edge(clk16x) then
if srst = '1' then
txr_state <= SM_IDLE;
tick_cnt <= 0;
bit_cnt <= 0;
else
case txr_state is
--wait for a tx strobe to start a transmission
when SM_IDLE =>
tick_cnt <= 0;
bit_cnt <= 0;
if tx_stb = '1' then
txr_state <= SM_START;
shifter <= tx_data;
end if;
--the start is a one, which is 8 ticks low followed by 8 ticks high
when SM_START =>
if tick_cnt < 8 then
txd_int <= '0';
tick_cnt <= tick_cnt + 1;
elsif tick_cnt < 15 then
txd_int <= '1';
tick_cnt <= tick_cnt + 1;
else
txd_int <= '1';
tick_cnt <= 0;
bit_cnt <= 0;
txr_state <= SM_SEND;
end if;
when SM_SEND =>
--for each bit, a one is 8 ticks low followed by 8 ticks high, and a zero is 8 ticks high followed by 8 ticks low
if tick_cnt < 8 then
txd_int <= not shifter(15);
tick_cnt <= tick_cnt + 1;
elsif tick_cnt < 15 then
txd_int <= shifter(15);
tick_cnt <= tick_cnt + 1;
else
txd_int <= shifter(15);
tick_cnt <= 0;
shifter <= shifter(14 downto 0) & '1';
--at end of this bit check to see if we have more bits or if it's time for the stop bit
if bit_cnt < 15 then
bit_cnt <= bit_cnt + 1;
else
bit_cnt <=0;
txr_state <= SM_STOP;
end if;
end if;
when SM_STOP =>
--stop bits are always ones, which are 8 ticks low followed by 8 ticks high
if tick_cnt < 8 then
txd_int <= '0';
tick_cnt <= tick_cnt + 1;
elsif tick_cnt < 15 then
txd_int <= '1';
tick_cnt <= tick_cnt + 1;
else
txd_int <= '1';
tick_cnt <= 0;
txr_state <= SM_IDLE;
end if;
--we should never get to the iothers state.
when others =>
tick_cnt <= 4;
bit_cnt <= 0;
txr_state <= SM_IDLE;
end case;
end if; --srst
end if; --clk16x
end process;
 
 
--An overrun error occurs when the transmit strobe is triggered and we are not finished with the previous state.
-- The error is cleared when the transmitter goes back to idle
p_or_err: process(clk16x)
begin
if rising_edge(clk16x) then
if srst = '1' then
err_int <='0';
elsif tx_stb = '1' and txr_state /= SM_IDLE then
err_int <= '1';
elsif txr_state = SM_IDLE then
err_int <= '0';
end if;
end if;
end process;
 
txd <= txd_int;
or_err <= err_int;
tx_idle <= '1' when txr_state = SM_IDLE else '0';
end rtl;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.