--
|
--
|
-- UART receiver
|
-- UART receiver
|
--
|
--
|
-- Author: Sebastian Witt
|
-- Author: Sebastian Witt
|
-- Date: 27.01.2008
|
-- Date: 27.01.2008
|
-- Version: 1.1
|
-- Version: 1.1
|
--
|
--
|
-- This code is free software; you can redistribute it and/or
|
-- This code is free software; you can redistribute it and/or
|
-- modify it under the terms of the GNU Lesser General Public
|
-- modify it under the terms of the GNU Lesser General Public
|
-- License as published by the Free Software Foundation; either
|
-- License as published by the Free Software Foundation; either
|
-- version 2.1 of the License, or (at your option) any later version.
|
-- version 2.1 of the License, or (at your option) any later version.
|
--
|
--
|
-- This code is distributed in the hope that it will be useful,
|
-- This code is distributed in the hope that it will be useful,
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
-- Lesser General Public License for more details.
|
-- Lesser General Public License for more details.
|
--
|
--
|
-- You should have received a copy of the GNU Lesser General Public
|
-- You should have received a copy of the GNU Lesser General Public
|
-- License along with this library; if not, write to the
|
-- License along with this library; if not, write to the
|
-- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
-- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
-- Boston, MA 02111-1307 USA
|
-- Boston, MA 02111-1307 USA
|
--
|
--
|
|
|
LIBRARY IEEE;
|
LIBRARY IEEE;
|
USE IEEE.std_logic_1164.all;
|
USE IEEE.std_logic_1164.all;
|
USE IEEE.numeric_std.all;
|
USE IEEE.numeric_std.all;
|
|
|
-- Serial UART receiver
|
-- Serial UART receiver
|
entity uart_receiver is
|
entity uart_receiver is
|
port (
|
port (
|
CLK : in std_logic; -- Clock
|
CLK : in std_logic; -- Clock
|
RST : in std_logic; -- Reset
|
RST : in std_logic; -- Reset
|
RXCLK : in std_logic; -- Receiver clock (16x baudrate)
|
RXCLK : in std_logic; -- Receiver clock (16x baudrate)
|
RXCLEAR : in std_logic; -- Reset receiver state
|
RXCLEAR : in std_logic; -- Reset receiver state
|
WLS : in std_logic_vector(1 downto 0); -- Word length select
|
WLS : in std_logic_vector(1 downto 0); -- Word length select
|
STB : in std_logic; -- Number of stop bits
|
STB : in std_logic; -- Number of stop bits
|
PEN : in std_logic; -- Parity enable
|
PEN : in std_logic; -- Parity enable
|
EPS : in std_logic; -- Even parity select
|
EPS : in std_logic; -- Even parity select
|
SP : in std_logic; -- Stick parity
|
SP : in std_logic; -- Stick parity
|
SIN : in std_logic; -- Receiver input
|
SIN : in std_logic; -- Receiver input
|
PE : out std_logic; -- Parity error
|
PE : out std_logic; -- Parity error
|
FE : out std_logic; -- Framing error
|
FE : out std_logic; -- Framing error
|
BI : out std_logic; -- Break interrupt
|
BI : out std_logic; -- Break interrupt
|
DOUT : out std_logic_vector(7 downto 0); -- Output data
|
DOUT : out std_logic_vector(7 downto 0); -- Output data
|
RXFINISHED : out std_logic -- Receiver operation finished
|
RXFINISHED : out std_logic -- Receiver operation finished
|
);
|
);
|
end uart_receiver;
|
end uart_receiver;
|
|
|
architecture rtl of uart_receiver is
|
architecture rtl of uart_receiver is
|
-- Majority voting logic
|
-- Majority voting logic
|
component slib_mv_filter is
|
component slib_mv_filter is
|
generic (
|
generic (
|
WIDTH : natural := 4;
|
WIDTH : natural := 4;
|
THRESHOLD : natural := 10
|
THRESHOLD : natural := 10
|
);
|
);
|
port (
|
port (
|
CLK : in std_logic; -- Clock
|
CLK : in std_logic; -- Clock
|
RST : in std_logic; -- Reset
|
RST : in std_logic; -- Reset
|
SAMPLE : in std_logic; -- Clock enable for sample process
|
SAMPLE : in std_logic; -- Clock enable for sample process
|
CLEAR : in std_logic; -- Reset process
|
CLEAR : in std_logic; -- Reset process
|
D : in std_logic; -- Signal input
|
D : in std_logic; -- Signal input
|
Q : out std_logic -- Signal D was at least THRESHOLD samples high
|
Q : out std_logic -- Signal D was at least THRESHOLD samples high
|
);
|
);
|
end component;
|
end component;
|
-- Counter
|
-- Counter
|
component slib_counter is
|
component slib_counter is
|
generic (
|
generic (
|
WIDTH : natural := 4 -- Counter width
|
WIDTH : natural := 4 -- Counter width
|
);
|
);
|
port (
|
port (
|
CLK : in std_logic; -- Clock
|
CLK : in std_logic; -- Clock
|
RST : in std_logic; -- Reset
|
RST : in std_logic; -- Reset
|
CLEAR : in std_logic; -- Clear counter register
|
CLEAR : in std_logic; -- Clear counter register
|
LOAD : in std_logic; -- Load counter register
|
LOAD : in std_logic; -- Load counter register
|
ENABLE : in std_logic; -- Enable count operation
|
ENABLE : in std_logic; -- Enable count operation
|
DOWN : in std_logic; -- Count direction down
|
DOWN : in std_logic; -- Count direction down
|
D : in std_logic_vector(WIDTH-1 downto 0); -- Load counter register input
|
D : in std_logic_vector(WIDTH-1 downto 0); -- Load counter register input
|
Q : out std_logic_vector(WIDTH-1 downto 0); -- Shift register output
|
Q : out std_logic_vector(WIDTH-1 downto 0); -- Shift register output
|
OVERFLOW : out std_logic -- Counter overflow
|
OVERFLOW : out std_logic -- Counter overflow
|
);
|
);
|
end component;
|
end component;
|
|
|
-- FSM
|
-- FSM
|
type state_type is (IDLE, START, DATA, PAR, STOP, MWAIT);
|
type state_type is (IDLE, START, DATA, PAR, STOP, MWAIT);
|
signal CState, NState : state_type;
|
signal CState, NState : state_type;
|
|
|
-- Signals
|
-- Signals
|
signal iBaudCountClear : std_logic; -- Baud counter clear
|
signal iBaudCountClear : std_logic; -- Baud counter clear
|
signal iBaudStep : std_logic; -- Next symbol pulse
|
signal iBaudStep : std_logic; -- Next symbol pulse
|
signal iBaudStepD : std_logic; -- Next symbol pulse delayed by one clock
|
signal iBaudStepD : std_logic; -- Next symbol pulse delayed by one clock
|
signal iFilterClear : std_logic; -- Reset input filter
|
signal iFilterClear : std_logic; -- Reset input filter
|
signal iFSIN : std_logic; -- Filtered SIN
|
signal iFSIN : std_logic; -- Filtered SIN
|
signal iParity : std_logic; -- Data parity
|
signal iParity : std_logic; -- Data parity
|
signal iParityReceived : std_logic; -- Parity received
|
signal iParityReceived : std_logic; -- Parity received
|
signal iDataCount : integer range 0 to 8; -- Data bit counter
|
signal iDataCount : integer range 0 to 8; -- Data bit counter
|
signal iDataCountInit : std_logic; -- Initialize data bit counter to word length
|
signal iDataCountInit : std_logic; -- Initialize data bit counter to word length
|
signal iDataCountFinish : std_logic; -- Data bit counter finished
|
signal iDataCountFinish : std_logic; -- Data bit counter finished
|
signal iRXFinished : std_logic; -- Word received, output data valid
|
signal iRXFinished : std_logic; -- Word received, output data valid
|
signal iFE : std_logic; -- Internal frame error
|
signal iFE : std_logic; -- Internal frame error
|
signal iBI : std_logic; -- Internal break interrupt
|
signal iBI : std_logic; -- Internal break interrupt
|
signal iNoStopReceived : std_logic; -- No valid stop bit received
|
signal iNoStopReceived : std_logic; -- No valid stop bit received
|
signal iDOUT : std_logic_vector(7 downto 0); -- Data output
|
signal iDOUT : std_logic_vector(7 downto 0); -- Data output
|
|
|
begin
|
begin
|
|
|
-- Baudrate counter: RXCLK/16
|
-- Baudrate counter: RXCLK/16
|
RX_BRC: slib_counter generic map (
|
RX_BRC: slib_counter generic map (
|
WIDTH => 4
|
WIDTH => 4
|
) port map (
|
) port map (
|
CLK => CLK,
|
CLK => CLK,
|
RST => RST,
|
RST => RST,
|
CLEAR => iBaudCountClear,
|
CLEAR => iBaudCountClear,
|
LOAD => '0',
|
LOAD => '0',
|
ENABLE => RXCLK,
|
ENABLE => RXCLK,
|
DOWN => '0',
|
DOWN => '0',
|
D => x"0",
|
D => x"0",
|
OVERFLOW => iBaudStep
|
OVERFLOW => iBaudStep
|
);
|
);
|
|
|
-- Input filter
|
-- Input filter
|
RX_MVF: slib_mv_filter generic map (
|
RX_MVF: slib_mv_filter generic map (
|
WIDTH => 4,
|
WIDTH => 4,
|
THRESHOLD => 10
|
THRESHOLD => 10
|
) port map (
|
) port map (
|
CLK => CLK,
|
CLK => CLK,
|
RST => RST,
|
RST => RST,
|
SAMPLE => RXCLK,
|
SAMPLE => RXCLK,
|
CLEAR => iFilterClear,
|
CLEAR => iFilterClear,
|
D => SIN,
|
D => SIN,
|
Q => iFSIN
|
Q => iFSIN
|
);
|
);
|
|
|
-- iBaudStepD
|
-- iBaudStepD
|
RX_IFC: process (CLK, RST)
|
RX_IFC: process (CLK, RST)
|
begin
|
begin
|
if (RST = '1') then
|
if (RST = '1') then
|
iBaudStepD <= '0';
|
iBaudStepD <= '0';
|
elsif (CLK'event and CLK = '1') then
|
elsif (CLK'event and CLK = '1') then
|
iBaudStepD <= iBaudStep;
|
iBaudStepD <= iBaudStep;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
iFilterClear <= iBaudStepD or iBaudCountClear;
|
iFilterClear <= iBaudStepD or iBaudCountClear;
|
|
|
-- Parity generation
|
-- Parity generation
|
RX_PAR: process (iDOUT, EPS)
|
RX_PAR: process (iDOUT, EPS)
|
begin
|
begin
|
iParity <= iDOUT(7) xor iDOUT(6) xor iDOUT(5) xor iDOUT(4) xor iDOUT(3) xor iDOUT(2) xor iDOUT(1) xor iDOUT(0) xor not EPS;
|
iParity <= iDOUT(7) xor iDOUT(6) xor iDOUT(5) xor iDOUT(4) xor iDOUT(3) xor iDOUT(2) xor iDOUT(1) xor iDOUT(0) xor not EPS;
|
end process;
|
end process;
|
|
|
-- Data bit capture
|
-- Data bit capture
|
RX_DATACOUNT: process (CLK, RST)
|
RX_DATACOUNT: process (CLK, RST)
|
begin
|
begin
|
if (RST = '1') then
|
if (RST = '1') then
|
iDataCount <= 0;
|
iDataCount <= 0;
|
iDOUT <= (others => '0');
|
iDOUT <= (others => '0');
|
elsif (CLK'event and CLK = '1') then
|
elsif (CLK'event and CLK = '1') then
|
if (iDataCountInit = '1') then
|
if (iDataCountInit = '1') then
|
iDataCount <= 0;
|
iDataCount <= 0;
|
iDOUT <= (others => '0');
|
iDOUT <= (others => '0');
|
else
|
else
|
if (iBaudStep = '1' and iDataCountFinish = '0') then
|
if (iBaudStep = '1' and iDataCountFinish = '0') then
|
iDOUT(iDataCount) <= iFSIN;
|
iDOUT(iDataCount) <= iFSIN;
|
iDataCount <= iDataCount + 1;
|
iDataCount <= iDataCount + 1;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
iDataCountFinish <= '1' when (WLS = "00" and iDataCount = 5) or
|
iDataCountFinish <= '1' when (WLS = "00" and iDataCount = 5) or
|
(WLS = "01" and iDataCount = 6) or
|
(WLS = "01" and iDataCount = 6) or
|
(WLS = "10" and iDataCount = 7) or
|
(WLS = "10" and iDataCount = 7) or
|
(WLS = "11" and iDataCount = 8) else '0';
|
(WLS = "11" and iDataCount = 8) else '0';
|
|
|
-- FSM update process
|
-- FSM update process
|
RX_FSMUPDATE: process (CLK, RST)
|
RX_FSMUPDATE: process (CLK, RST)
|
begin
|
begin
|
if (RST = '1') then
|
if (RST = '1') then
|
CState <= IDLE;
|
CState <= IDLE;
|
elsif (CLK'event and CLK = '1') then
|
elsif (CLK'event and CLK = '1') then
|
CState <= NState;
|
CState <= NState;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
-- RX FSM
|
-- RX FSM
|
RX_FSM: process (CState, SIN, iFSIN, iBaudStep, iDataCountFinish, PEN, WLS, STB)
|
RX_FSM: process (CState, SIN, iFSIN, iBaudStep, iDataCountFinish, PEN, WLS, STB)
|
begin
|
begin
|
-- Defaults
|
-- Defaults
|
NState <= IDLE;
|
NState <= IDLE;
|
iBaudCountClear <= '0';
|
iBaudCountClear <= '0';
|
iDataCountInit <= '0';
|
iDataCountInit <= '0';
|
iRXFinished <= '0';
|
iRXFinished <= '0';
|
|
|
case CState is
|
case CState is
|
when IDLE => if (SIN = '0') then -- Start detected
|
when IDLE => if (SIN = '0') then -- Start detected
|
NState <= START;
|
NState <= START;
|
end if;
|
end if;
|
iBaudCountClear <= '1';
|
iBaudCountClear <= '1';
|
iDataCountInit <= '1';
|
iDataCountInit <= '1';
|
when START => iDataCountInit <= '1';
|
when START => iDataCountInit <= '1';
|
if (iBaudStep = '1') then -- Wait for start bit end
|
if (iBaudStep = '1') then -- Wait for start bit end
|
if (iFSIN = '0') then
|
if (iFSIN = '0') then
|
NState <= DATA;
|
NState <= DATA;
|
end if;
|
end if;
|
else
|
else
|
NState <= START;
|
NState <= START;
|
end if;
|
end if;
|
when DATA => if (iDataCountFinish = '1') then -- Received all data bits
|
when DATA => if (iDataCountFinish = '1') then -- Received all data bits
|
if (PEN = '1') then
|
if (PEN = '1') then
|
NState <= PAR; -- Parity enabled
|
NState <= PAR; -- Parity enabled
|
else
|
else
|
NState <= STOP; -- No parity
|
NState <= STOP; -- No parity
|
end if;
|
end if;
|
else
|
else
|
NState <= DATA;
|
NState <= DATA;
|
end if;
|
end if;
|
when PAR => if (iBaudStep = '1') then -- Wait for parity bit
|
when PAR => if (iBaudStep = '1') then -- Wait for parity bit
|
NState <= STOP;
|
NState <= STOP;
|
else
|
else
|
NState <= PAR;
|
NState <= PAR;
|
end if;
|
end if;
|
when STOP => if (iBaudStep = '1') then -- Wait for stop bit
|
when STOP => if (iBaudStep = '1') then -- Wait for stop bit
|
if (iFSIN = '0') then -- No stop bit received
|
if (iFSIN = '0') then -- No stop bit received
|
iRXFinished <= '1';
|
iRXFinished <= '1';
|
NState <= MWAIT;
|
NState <= MWAIT;
|
else
|
else
|
iRXFinished <= '1';
|
iRXFinished <= '1';
|
NState <= IDLE; -- Stop bit end
|
NState <= IDLE; -- Stop bit end
|
end if;
|
end if;
|
else
|
else
|
NState <= STOP;
|
NState <= STOP;
|
end if;
|
end if;
|
when MWAIT => if (SIN = '0') then -- Wait for mark
|
when MWAIT => if (SIN = '0') then -- Wait for mark
|
NState <= MWAIT;
|
NState <= MWAIT;
|
end if;
|
end if;
|
when others => null;
|
when others => null;
|
end case;
|
end case;
|
end process;
|
end process;
|
|
|
-- Check parity
|
-- Check parity
|
RX_PARCHECK: process (CLK, RST)
|
RX_PARCHECK: process (CLK, RST)
|
begin
|
begin
|
if (RST = '1') then
|
if (RST = '1') then
|
PE <= '0';
|
PE <= '0';
|
iParityReceived <= '0';
|
iParityReceived <= '0';
|
elsif (CLK'event and CLK = '1') then
|
elsif (CLK'event and CLK = '1') then
|
if (CState = PAR and iBaudStep = '1') then
|
if (CState = PAR and iBaudStep = '1') then
|
iParityReceived <= iFSIN; -- Received parity bit
|
iParityReceived <= iFSIN; -- Received parity bit
|
end if;
|
end if;
|
|
|
-- Check parity
|
-- Check parity
|
if (PEN = '1') then -- Parity enabled
|
if (PEN = '1') then -- Parity enabled
|
PE <= '0';
|
PE <= '0';
|
if (SP = '1') then -- Sticky parity
|
if (SP = '1') then -- Sticky parity
|
if ((EPS xor iParityReceived) = '0') then
|
if ((EPS xor iParityReceived) = '0') then
|
PE <= '1'; -- Parity error
|
PE <= '1'; -- Parity error
|
end if;
|
end if;
|
else
|
else
|
if (iParity /= iParityReceived) then
|
if (iParity /= iParityReceived) then
|
PE <= '1'; -- Parity error
|
PE <= '1'; -- Parity error
|
end if;
|
end if;
|
end if;
|
end if;
|
else
|
else
|
PE <= '0'; -- Parity disabled
|
PE <= '0'; -- Parity disabled
|
iParityReceived <= '0';
|
iParityReceived <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
-- Framing error and break interrupt
|
-- Framing error and break interrupt
|
iNoStopReceived <= '1' when iFSIN = '0' and (CState = STOP) else '0';
|
iNoStopReceived <= '1' when iFSIN = '0' and (CState = STOP) else '0';
|
iBI <= '1' when iDOUT = "00000000" and
|
iBI <= '1' when iDOUT = "00000000" and
|
iParityReceived = '0' and
|
iParityReceived = '0' and
|
iNoStopReceived = '1' else '0';
|
iNoStopReceived = '1' else '0';
|
iFE <= '1' when iNoStopReceived = '1' else '0';
|
iFE <= '1' when iNoStopReceived = '1' else '0';
|
|
|
-- Output signals
|
-- Output signals
|
DOUT <= iDOUT;
|
DOUT <= iDOUT;
|
BI <= iBI;
|
BI <= iBI;
|
FE <= iFE;
|
FE <= iFE;
|
RXFINISHED <= iRXFinished;
|
RXFINISHED <= iRXFinished;
|
|
|
end rtl;
|
end rtl;
|
|
|
|
|