FPGARelated.com
Forums

RS232 VHDL-core

Started by Preben Holm March 9, 2005
Hi everyone...


I wonder if there is any simple way to send the data from a block-ram to 
the RS232-interface, without the need to write all the RS232 VHDL-code 
myself!



Thanks everyone!
This is a multi-part message in MIME format.
--------------070302010109050402040109
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

> I wonder if there is any simple way to send the data from a block-ram to > the RS232-interface, without the need to write all the RS232 VHDL-code > myself!
There you go. And can we now stop requesting RS232 stuff? ;) Jan --------------070302010109050402040109 Content-Type: text/plain; name="EIA232_TX_bridge.vhd" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="EIA232_TX_bridge.vhd" -- -- ***Author*** -- Jan De Ceuster -- -- *** File *** -- EIA232_TX_bridge.vhd -- -- *** Entity *** -- EIA232_TX_bridge -- -- *** Port list *** -- nrst (in, 1) Active low reset -- clk (in, 1) System Clock -- -- EIA232_TXD (in, 1) EIA232 Receive Serial Data from PC -- EIA232_CTS (out, 1) EIA232 Stop Receiving -- -- ParallelIN_Data (out, 8) ParallelIN sends the data from EIA232 interface. -- ParallelIN_Ack (out, 1) protocol: synchronous Full Handshake, device -- ParallelIN_Req (in, 1) is slave. library ieee; use ieee.std_logic_1164.all, ieee.std_logic_arith.all; library work; use work.shift_registers.all; use work.EIA232.all; entity EIA232_TX_bridge is generic ( DATASIZE : in integer := 8; CLKFREQ : in integer := 33000000; -- clock frequency in Hz BAUDRATE : in integer := 115200 ); port ( nrst : in std_logic; clk : in std_logic; EIA232_TXD : in std_logic; EIA232_CTS : out std_logic; ParallelIN_Data : out std_logic_vector(DATASIZE-1 downto 0); ParallelIN_Req : in std_logic; ParallelIN_Ack : out std_logic ); end EIA232_TX_bridge; architecture RTL of EIA232_TX_bridge is constant BITCOUNTER_SIZE : integer := DATASIZE - 1; constant TIMECOUNTER_SIZE : integer := CLKFREQ/BAUDRATE-1; constant HALF_TIMECOUNTER_SIZE : integer := TIMECOUNTER_SIZE/2 - 1; signal timecounter : integer range 0 to TIMECOUNTER_SIZE; signal bitcounter : integer range 0 to DATASIZE-1; signal ParallelIN_Data_reg : std_logic_vector(1 to DATASIZE); signal EIA232State, nextEIA232State : EIA232State_type; signal timecounter_pulse : std_logic; signal StartReceive : std_logic; signal sync_EIA232_TXD : std_logic_vector(2 downto 1); signal faling_edge_EIA232_TXD : boolean; signal buffer_empty : boolean; begin process (EIA232State, StartReceive, bitcounter) begin nextEIA232State <= EIA232State; case EIA232State is when E_EIA232State_Waiting => if StartReceive = '1' then nextEIA232State <= E_EIA232State_Start; end if; when E_EIA232State_Start => nextEIA232State <= E_EIA232State_Data; when E_EIA232State_Data => if bitcounter = 0 then nextEIA232State <= E_EIA232State_Stop; end if; when E_EIA232State_Stop => nextEIA232State <= E_EIA232State_Waiting; when others => end case; end process; -- sample signal into flipflops process (clk) begin if rising_edge(clk) then ShiftL2H(EIA232_TXD,sync_EIA232_TXD); end if; end process; faling_edge_EIA232_TXD <= sync_EIA232_TXD(sync_EIA232_TXD'high-1) = '0' and sync_EIA232_TXD(sync_EIA232_TXD'high) = '1'; timecounter_pulse <= '1' when timecounter = 0 else '0'; process (clk, nrst) begin if nrst = '0' then timecounter <= TIMECOUNTER_SIZE; StartReceive <= '0'; elsif rising_edge(clk) then -- endless timer with conditional preload (when detecting a startbit) -- StartReceive indicates the detection of the startbit if faling_edge_EIA232_TXD -- faling edge TXD, and nextEIA232State = E_EIA232State_Waiting then -- detect start bit timecounter <= HALF_TIMECOUNTER_SIZE; StartReceive <= '1'; elsif timecounter = 0 then -- counter reset timecounter <= TIMECOUNTER_SIZE; StartReceive <= '0'; else timecounter <= timecounter - 1; -- count down end if; end if; end process; process (clk, nrst) begin if nrst = '0' then EIA232State <= E_EIA232State_Waiting; ParallelIN_Data_reg <= (others => '-'); bitcounter <= BITCOUNTER_SIZE; elsif rising_edge(clk) then if timecounter_pulse = '1' then EIA232State <= nextEIA232State; bitcounter <= BITCOUNTER_SIZE; -- shift register ShiftL2H(sync_EIA232_TXD(sync_EIA232_TXD'high),ParallelIN_Data_reg); if EIA232State = E_EIA232State_Start or EIA232State = E_EIA232State_Data then -- counter for the shiftregister if bitcounter = 0 then bitcounter <= BITCOUNTER_SIZE; else bitcounter <= bitcounter - 1; end if; end if; end if; end if; end process; process (clk, nrst) begin if nrst = '0' then buffer_empty <= TRUE; EIA232_CTS <= '1'; ParallelIN_Ack <= '0'; elsif rising_edge(clk) then if buffer_empty then EIA232_CTS <= '0'; else EIA232_CTS <= '1'; end if; if EIA232State = E_EIA232State_Data then buffer_empty <= FALSE; end if; -- Output the shiftregister directly. if timecounter_pulse = '1' and EIA232State = E_EIA232State_Stop then ParallelIN_Data <= ParallelIN_Data_reg; end if; -- The shiftregister now contains the received byte. -- => give an ack for 1 clock cycle (done with timecounter_pulse) if ParallelIN_REQ = '1' and not buffer_empty and EIA232State = E_EIA232State_Waiting then ParallelIN_Ack <= '1'; buffer_empty <= TRUE; else ParallelIN_Ack <= '0'; end if; end if; end process; end RTL; --------------070302010109050402040109 Content-Type: text/plain; name="EIA232_package.vhd" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="EIA232_package.vhd" -- -- ***Author*** -- Jan De Ceuster -- -- *** File *** -- EIA232_constants.vhd -- -- *** Entity *** -- -- *** Port list *** -- -- *** Description *** -- -- *** History *** -- library ieee; use ieee.std_logic_1164.all; package EIA232 is -- enumerations type EIA232State_type is (E_EIA232State_Waiting, E_EIA232State_Start, E_EIA232State_Data, E_EIA232State_Stop); -- constants -- functions -- procedures -- components component EIA232_TX_bridge -- receive data via a FullHndshk protocol -- bridge is master on EIA232 lines generic ( DATASIZE : in integer := 8; -- size can be anything from 5 to 8 CLKFREQ : in integer := 33000000; -- clock frequency in Hz BAUDRATE : in integer := 115200 ); port ( nrst : in std_logic; clk : in std_logic; EIA232_TXD : in std_logic; EIA232_CTS : out std_logic; ParallelIN_Data : out std_logic_vector(DATASIZE-1 downto 0); ParallelIN_Req : in std_logic; ParallelIN_Ack : out std_logic ); end component; component EIA232_RX_bridge -- send data via a FullHndshk protocol -- bridge is master on EIA232 lines generic ( DATASIZE : in integer := 8; -- size can be anything from 5 to 8 CLKFREQ : in integer := 33000000; -- clock frequency in Hz BAUDRATE : in integer := 115200 ); port ( nrst : in std_logic; clk : in std_logic; EIA232_RXD : out std_logic; EIA232_RTS : in std_logic; ParallelOUT_Data : in std_logic_vector(DATASIZE-1 downto 0); ParallelOUT_Req : in std_logic; ParallelOUT_Ack : out std_logic ); end component; component EIA232_ASCIIfileio -- model using files to send and get ASCII data to/from the system. generic ( DATASIZE : in integer := 8; -- size can be anything from 5 to 8 CLKFREQ : in integer := 33000000; -- clock frequency in Hz BAUDRATE : in integer := 115200; READFILE : string := ""; WRITEFILE : string := "" ); port ( nrst : in std_logic; clk : in std_logic; EIA232_RXD : in std_logic; EIA232_RTS : out std_logic; EIA232_TXD : out std_logic; EIA232_CTS : in std_logic; done : out boolean := false ); end component; end EIA232; package body EIA232 is end EIA232; --------------070302010109050402040109 Content-Type: text/plain; name="EIA232_RX_bridge.vhd" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="EIA232_RX_bridge.vhd" -- -- ***Author*** -- Jan De Ceuster -- -- *** File *** -- EIA232_RX_bridge.vhd -- -- *** Entity *** -- EIA232_RX_bridge -- -- *** Port list *** -- nrst (in, 1) Active low reset -- clk (in, 1) System Clock -- -- EIA232_RXD (out, 1) EIA232 Transmit Serial Data to PC -- EIA232_RTS (in, 1) EIA232 Stop Sending -- -- ParallelOUT_Data (in, 8) ParallelOUT sends the data to EIA232 interface. -- ParallelOUT_Ack (out, 1) protocol: synchronous Full Handshake, device is slave -- ParallelOUT_Req (in, 1) -- -- *** Description *** -- This block will translate the parallel data from a generic interface to -- a serial output according the EIA232 standard with RXD and RTS. -- The size of the parallel data (generic paramter DATASIZE) can be anything -- from 5 to 8. This is also as specified in the EIA232 standard. -- One start and stopbit is provided. -- The generic parameter CLK_DIV is used to set the correct baudrate: -- baudrate = inputfreq/CLK_DIV -- -- *** History *** -- 001 27-06-2003 Initial version -- Fully tested and optimized library ieee; use ieee.std_logic_1164.all, ieee.std_logic_arith.all; library work; use work.shift_registers.all; use work.EIA232.all; entity EIA232_RX_bridge is generic ( DATASIZE : in integer := 8; -- size can be anything from 5 to 8 CLKFREQ : in integer := 33000000; -- clock frequency in Hz BAUDRATE : in integer := 115200 ); port ( nrst : in std_logic; clk : in std_logic; EIA232_RXD : out std_logic; EIA232_RTS : in std_logic; ParallelOUT_Data : in std_logic_vector(DATASIZE-1 downto 0); ParallelOUT_Req : in std_logic; ParallelOUT_Ack : out std_logic ); end EIA232_RX_bridge; architecture RTL of EIA232_RX_bridge is constant TIMECOUNTER_SIZE : integer := integer(real(CLKFREQ/BAUDRATE)-1.0); signal timecounter : integer range 0 to TIMECOUNTER_SIZE; signal bitcounter : integer range 0 to DATASIZE; signal EIA232ShiftRegister : std_logic_vector(1 to DATASIZE); signal EIA232State, nextEIA232State : EIA232State_type; signal StartSending : std_logic; signal timecounter_pulse : std_logic; signal sync_EIA232_RTS : std_logic_vector(3 downto 1); begin -- The EIA232State statemachine controls the correct flow for the start, data -- and stop bit(s). process (EIA232State, StartSending, bitcounter) begin nextEIA232State <= EIA232State; case EIA232State is when E_EIA232State_Waiting => -- Req for sending data received. if StartSending = '1' then nextEIA232State <= E_EIA232State_Start; end if; when E_EIA232State_Start => nextEIA232State <= E_EIA232State_Data; when E_EIA232State_Data => -- Last databit send. if bitcounter = DATASIZE and StartSending = '0' then nextEIA232State <= E_EIA232State_Waiting; end if; when others => end case; end process; -- Generate a pulse when timecounter is 0. timecounter_pulse <= '1' when timecounter = 0 else '0'; -- Sample the inputsignal from physical EIA232 interface into a flipflop. process (clk) begin if rising_edge(clk) then ShiftL2H(EIA232_RTS,sync_EIA232_RTS); end if; end process; process (clk,nrst) begin if nrst = '0' then timecounter <= TIMECOUNTER_SIZE; ParallelOUT_Ack <= '0'; StartSending <= '0'; EIA232ShiftRegister <= (others => '1'); elsif rising_edge(clk) then ParallelOUT_Ack <= '0'; -- Counter to devide the clk input. if timecounter_pulse = '1' then timecounter <= TIMECOUNTER_SIZE; else timecounter <= timecounter - 1; end if; case EIA232State is when E_EIA232State_Waiting => -- Req received and ready to transmit data. if StartSending = '0' and ParallelOUT_Req = '1' and sync_EIA232_RTS(sync_EIA232_RTS'high) = '0' then -- Load the shiftregister EIA232ShiftRegister(1 to DATASIZE) <= ParallelOUT_Data; ParallelOUT_Ack <= '1'; StartSending <= '1'; end if; when E_EIA232State_Start | E_EIA232State_Data => StartSending <= '0'; -- The shiftregister can shift every timecounter_pulse. -- This register runs on clk because it must be possible to load -- external data assynchronous to timecounter_pulse. if timecounter_pulse = '1' then ShiftL2H('1',EIA232ShiftRegister); end if; when others => StartSending <= '0'; end case; end if; end process; process (clk,nrst) begin if nrst = '0' then EIA232_RXD <= '1'; EIA232State <= E_EIA232State_Waiting; bitcounter <= 0; elsif rising_edge(clk) then if timecounter_pulse = '1' then EIA232State <= nextEIA232State; case nextEIA232State is when E_EIA232State_Waiting => EIA232_RXD <= '1'; when E_EIA232State_Start => EIA232_RXD <= '0'; when E_EIA232State_Data => EIA232_RXD <= EIA232ShiftRegister(DATASIZE); if bitcounter = DATASIZE then bitcounter <= 0; else bitcounter <= bitcounter + 1; end if; when others => end case; end if; end if; end process; end RTL; --------------070302010109050402040109 Content-Type: text/plain; name="EIA232_ASCIIfileIO.vhd" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="EIA232_ASCIIfileIO.vhd" -- -- ***Author*** -- -- *** File *** -- EIA232_fileio.vhd -- -- *** Entity *** -- EIA232_fileio -- -- *** Port list *** -- -- *** Description *** -- -- *** History *** -- 001 library std; use std.textio.all; library ieee; use ieee.std_logic_1164.all, ieee.std_logic_arith.all; library nicethings; use nicethings.ASCII.all, nicethings.overloaded_std_logic_arith.all; library communication; use communication.EIA232.all; entity EIA232_ASCIIfileio is generic ( DATASIZE : in integer := 8; -- size can be anything from 5 to 8 CLKFREQ : in integer := 33000000; -- clock frequency in Hz BAUDRATE : in integer := 115200; READFILE : string := ""; WRITEFILE : string := "" ); port ( nrst : in std_logic; clk : in std_logic; EIA232_RXD : in std_logic; EIA232_RTS : out std_logic; EIA232_TXD : out std_logic; EIA232_CTS : in std_logic; done : out boolean := FALSE ); end EIA232_ASCIIfileio; architecture model of EIA232_ASCIIfileio is --signals of the EIA232 side signal in_Data : std_logic_vector(DATASIZE-1 downto 0); signal in_REQ, in_ACK : std_logic; signal out_Data : std_logic_vector(DATASIZE-1 downto 0); signal out_REQ, out_ACK : std_logic; signal RXstate : integer := 0; signal TXstate : integer := 0; begin TX_test : EIA232_TX_bridge generic map (DATASIZE,CLKFREQ,BAUDRATE) port map (nrst=>nrst,clk=>clk, EIA232_TXD=>EIA232_RXD,EIA232_CTS=>EIA232_RTS, ParallelIN_Data=>in_Data,ParallelIN_Req=>in_REQ, ParallelIN_Ack=>in_ACK); RX_test : EIA232_RX_bridge generic map (DATASIZE,CLKFREQ,BAUDRATE) port map (nrst=>nrst,clk=>clk, EIA232_RXD=>EIA232_TXD,EIA232_RTS=>EIA232_CTS, ParallelOUT_Data=>out_Data,ParallelOUT_Req=>out_REQ, ParallelOUT_Ack=>out_ACK); RX_SIDE : if READFILE /= "" generate -- EIA232 RX side process (clk, nrst) file Fread : TEXT open READ_MODE is READFILE; variable L : line; variable char : character; begin if nrst = '0' then out_REQ <= '0'; out_Data <= (others => '0'); RXstate <= 0; done <= FALSE; elsif rising_edge(clk) then case RXstate is when 0 => readline(Fread,L); RXstate <= 1; when 1 => if L'length = 0 then char := LF; else read(L,char); end if; out_REQ <= '1'; out_Data <= conv_std_logic_vector(char,DATASIZE-1); RXstate <= 2; when 2 => if out_ACK = '1' then out_REQ <= '0'; if char = LF then if endfile(Fread) then RXstate <= 3; else readline(Fread,L); RXstate <= 1; end if; else RXstate <= 1; end if; end if; when others => done <= TRUE; end case; end if; end process; end generate; TX_SIDE : if WRITEFILE /= "" generate -- EIA232 TX side process (clk, nrst) file Fwrite : TEXT open WRITE_MODE is WRITEFILE; variable L : line; variable char : character; begin if nrst = '0' then in_REQ <= '0'; TXstate <= 0; elsif rising_edge(clk) then case TXstate is when 0 => in_REQ <= '1'; TXstate <= 1; when 1 => if in_ACK = '1' then in_REQ <= '0'; TXstate <= 0; if in_DATA /= C_ASCII_LF then write(L,conv_character(in_DATA)); else writeline(Fwrite,L); end if; end if; when others => end case; end if; end process; end generate; end model; --------------070302010109050402040109--
Xilinx offers a very nice UART core (+ 16 bytes fifo as an option) for
free - it is includded in the PicoBlaze package. You can download it
and use it - it has full documentation and it is working just fine.
If you do not use Xilinx I'm sure that you can google for a UART core
in the web.
Regards, Moti.

Hi,

I searched the newsgroup but wasn't able to find anything!!
It seems like somebody before me requested it! So thanks anyway!


Thanks,
Preben
Hi Jan

jandc schrieb:
>> I wonder if there is any simple way to send the data from a block-ram >> to the RS232-interface, without the need to write all the RS232 >> VHDL-code myself! > > > There you go. And can we now stop requesting RS232 stuff? ;)
Sorry, but we can't :-) There are still some packages missing to make it work:
> library work; > use work.shift_registers.all;
> library nicethings; > use nicethings.ASCII.all, nicethings.overloaded_std_logic_arith.all;
In another posting on http://www.castalk.com/ftopic211.html you posted a buffer_procedures package. This package had shifting procedures with similar names to those expected in the shift_registers package. Is the shift_registers package a replacement for the buffer_procedures package? There are also two packages that can be compiled to nicethings. (ascii_constants and ascii_functions). Are these former versions of nicethings ascii and nicethings.overloaded_std_logic_arith?? It would be nice if you could post the missing packages as well, so we can test your design. Besides that, your RS232 core looks good and clearly coded, AND is one of the rare examples that supports RTS/CTS handshaking. I made a similar thing years ago with schematic entry. The q&d-VHDL port of that is quite unreadable and not suitable as a vhdl reference design. I would like to compare these two designs, if only I had the missing packages. best regards Eilert Backhus backhus_who hates spam__at__no spam wanted_isms.hs-bremen.de_where spam is deleted anyway_
=D1=81=D1=80=D0=B5=D0=B4=D0=B0, 9 =D0=BC=D0=B0=D1=80=D1=82=D0=B0 2005=C2=A0=
=D0=B3., 16:33:14 UTC+2 =D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=
=82=D0=B5=D0=BB=D1=8C jandc =D0=BD=D0=B0=D0=BF=D0=B8=D1=81=D0=B0=D0=BB:
> > I wonder if there is any simple way to send the data from a block-ram t=
o=20
> > the RS232-interface, without the need to write all the RS232 VHDL-code=
=20
> > myself! >=20 > There you go. And can we now stop requesting RS232 stuff? ;) >=20 > Jan
Hi Jan! I know this might be a little too late to ask, but would you be so kind as = to post here the libraries mentioned by backhus? I mean these:
> library work; > use work.shift_registers.all;
> library nicethings; > use nicethings.ASCII.all, nicethings.overloaded_std_logic_arith.all;
Best regards, Sergiy.
You do realize that this thread is over 8 years old, right?

And frankly, anything that needs a package named "overloaded_std_logic_arith" would raise my suspicions about its worth. 

Andy