VHDL model of a RS 232 transmitter

F

fpgawizz

I am working on a project where I send serial data from my PC to an FPGA
which samples it, captures it and puts it in an external memory.
In order to test this using a test bench, I need a model for the RS 232
transmitter - a model that mimics sending 8 bits of RS 232 data at 9600
Hz. I got the model of the memory from the vendor.Where can I get a model
of the RS 232 to use for my test bench?

thanks
 
J

Jonathan Bromley

I am working on a project where I send serial data from my PC to an FPGA
which samples it, captures it and puts it in an external memory.
In order to test this using a test bench, I need a model for the RS 232
transmitter - a model that mimics sending 8 bits of RS 232 data at 9600
Hz. I got the model of the memory from the vendor.Where can I get a model
of the RS 232 to use for my test bench?


Bert has given you a link to a synthesisable UART IP block, but for
a test bench it is really very simple. Just write a procedure, and
put the procedure in a package. Code below. It's left as a trivial
exercise for the student to add parity, variable numbers of stop
bits, and suchlike extra goodies. Make sure you know what you're
doing about the line signal levels - I've assumed the line marks
at '1' and spaces at '0', which is usually correct in the core
logic, but the RS-232 line discipline uses negative voltage for
marking and positive for spacing. The line transceiver chips
do the necessary level shifting and inversion for you, so you
don't normally need to worry about it in the FPGA.

It is somewhat trickier to write a behavioural model of a
UART receiver, but even that isn't too mind-bending.

Enjoy writing and using behavioural models!

Take my package here and use it as you see fit - I've
checked that it works, but as usual on Usenet you get
no commercial guarantee of reliability or fitness for
purpose. The little entity/architecture at the end is
a very quick demonstration of how to use the package.

------------------------------------------------------ package ---

library IEEE;
use IEEE.std_logic_1164.all;

package UART_behavioural_model is

procedure UART_tx (

-- The signal that is to be driven by this model...
signal tx_line: out std_logic;

-- Inputs to control how to send one character:
data: in std_logic_vector; -- usually 8 bits
baud_rate:in integer -- e.g. 9600
);

end package UART_behavioural_model;

--------------------------------------------------- package body ---

package body UART_behavioural_model is

procedure UART_tx (

-- The signal that is to be driven by this model...
signal tx_line: out std_logic;

-- Inputs to control how to send one character:
data: in std_logic_vector; -- usually 8 bits
baud_rate:in integer -- e.g. 9600
) is

constant bit_time: time := 1 sec / baud_rate;

begin

-- Send the start bit
tx_line <= '0';
wait for bit_time;

-- Send the data bits, least significant first
for i in data'reverse_range loop
tx_line <= data(i);
wait for bit_time;
end loop;

-- Send the stop bit
tx_line <= '1';
wait for bit_time;

end; -- procedure UART_tx

end package body UART_behavioural_model;

---------------------------------------------- a simple test ---

library IEEE;
use IEEE.std_logic_1164.all;

-- Import our UART tester package
use work.UART_behavioural_model.all;

entity try_the_UART is end;

architecture A of try_the_UART is

-- A signal for the tester to drive, initialised to "marking"
signal serial_line: std_logic := '1';

begin

Testing: process

constant My_Baud_Rate: integer := 9600;
-- Make a jacket procedure around UART_tx, for convenience
procedure send (data: in std_logic_vector) is
begin
UART_tx(
tx_line => serial_line,
data => data,
baud_rate => My_Baud_Rate
);
end;

variable D: std_logic_vector(7 downto 0);

begin

-- Idle awhile
wait for 1 ms;

-- Send an 8-bit character as a test
send("10001110");

-- Idle some more
wait for 1 ms;

-- Some more characters - use a walking-ones pattern:
for i in D'range loop
D := (others => '0');
D(i) := '1';
send(D);
end loop;

-- And finally, just for fun, send a 10-bit character:
send("1111100000");

wait; -- That's All Folks
end process;

end;


--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL, Verilog, SystemC, Perl, Tcl/Tk, Verification, Project Services

Doulos Ltd. Church Hatch, 22 Market Place, Ringwood, BH24 1AW, UK
Tel: +44 (0)1425 471223 mail:[email protected]
Fax: +44 (0)1425 471573 Web: http://www.doulos.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
I

info_

The behavioral receiver (and transmitter) were on the conference page 16
even with a few comments in that smell croissant and baguette... ;-)

Our UART IP also includes behavioral models, as well as a console model which reads &
writes data from/to text files and interprets special commands including a "pause".
This helps emulate the behavior of a console.

Here comes the receiver. You can strip the parity if you don't need it,
and remove the debug printing after everything works.
And the variable for the received word still smells baguette.

I think some call this code a no-brainer ?


-- -----------------------------
-- Serial Receive (behavioral)
-- -----------------------------
process
variable L : line;
variable MOT : std_logic_vector (7 downto 0);
variable ParityBit : std_logic;
begin
-- nothing to initialize
loop
ParityBit := '0';

wait until TX = '0'; -- get falling edge

wait for (0.5 * BITperiod); -- move to Middle of Start bit
assert TX = '0'
report "Error during Start Bit ???" severity warning;

wait for BITperiod; -- move to First Data Bit
for i in 0 to 7 loop -- Get word in a loop
MOT(i) := TX;
ParityBit := ParityBit xor TX;
wait for BITperiod;
end loop;

if Parity then
if not Even then
ParityBit := not ParityBit;
end if;
if ParityBit /= TX then
report "Error during Parity Bit" severity warning;
end if;
wait for BITperiod;
end if;

wait for BITperiod; -- Stop bit
assert TX = '1'
report "Error during Stop bit ???" severity warning;

-- debug printing
write (L,string'("Character received (hex) = "));
hwrite (L,MOT); -- trace
write (L,string'(" - '" & character'val(to_integer(unsigned(MOT))) & "'" ));
writeline (output,L); -- write to simulation transcript
end loop;
end process;
 
J

Jonathan Bromley

The behavioral receiver (and transmitter) were on the conference page 16
even with a few comments in that smell croissant and baguette... ;-)

Sorry Bert. I missed them there, until I took a closer look some
time later.

Anyhow, it's nice to see that we agree about how to do it - and
it's very important that you should know that there is a truly
excellent patisserie only 400m from my home, where the French
proprietor makes viennoiserie as good as all but the very
best in France :)
 
F

fpgawizz

Jonathan
I tried using the package procedure as you advised. I had some
problems..firstly the tool complains that i cannot have "Wait for" state
ments in a package. How do i fix this?
thanks
 
J

Jonathan Bromley

Jonathan
I tried using the package procedure as you advised. I had some
problems..firstly the tool complains that i cannot have "Wait for" state
ments in a package. How do i fix this?

(1) If, as I suspect, you are trying to put my code through a
synthesis tool such as XST, then DON'T. It's for simulation only.

(2) If it's a simulator giving the error, throw it away and
get one that works.
 
F

fpgawizz

Jonathan:
I used ur procedure..I have an entity with input ports "Din" ( serial in)
and a clock that i generate. I am generating a 6 us clock which is approx.
16 times faster than 9600 Hz. And i am connecting the serial_line signal
to my Din input as i need my serial data on that line.But all my signals
except the serial_line signal are undefined "UUUUUUUU".
Any idea why even my clock signal is not coming through?

thanks


my testbench code is as follows.

LIBRARY ieee,toplevelib;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
use toplevelib.uart_model.all;

ENTITY datacomm_tb1_vhd_tb IS
END datacomm_tb1_vhd_tb;

ARCHITECTURE behavior OF datacomm_tb1_vhd_tb IS

COMPONENT datacomm
PORT(
clk : IN std_logic;
Din : IN std_logic;
DATABUS : INOUT std_logic_vector(7 downto 0);
LD : OUT std_logic_vector(7 downto 0);
SRAMADDRUpper : OUT std_logic_vector(9 downto 0);
SRAMADDR : OUT std_logic_vector(7 downto 0);
OE : OUT std_logic;
WE : OUT std_logic;
LB : OUT std_logic;
UB : OUT std_logic;
CE1 : OUT std_logic;
CE2 : OUT std_logic;
data_out : OUT std_logic_vector(7 downto 0);
AN : OUT std_logic_vector(3 downto 0);
Seven_seg : OUT std_logic_vector(6 downto 0)
);
END COMPONENT;

SIGNAL clk : std_logic;
SIGNAL Din : std_logic;
SIGNAL LD : std_logic_vector(7 downto 0);
SIGNAL SRAMADDRUpper : std_logic_vector(9 downto 0);
SIGNAL SRAMADDR : std_logic_vector(7 downto 0);
SIGNAL DATABUS : std_logic_vector(7 downto 0);
SIGNAL OE : std_logic;
SIGNAL WE : std_logic;
SIGNAL LB : std_logic;
SIGNAL UB : std_logic;
SIGNAL CE1 : std_logic;
SIGNAL CE2 : std_logic;
SIGNAL data_out : std_logic_vector(7 downto 0);
SIGNAL AN : std_logic_vector(3 downto 0);
SIGNAL Seven_seg : std_logic_vector(6 downto 0);

-- A signal for the tester to drive, initialised to "marking"
signal serial_line: std_logic := '1';
BEGIN

uut: datacomm PORT MAP(
clk => clk,
Din => serial_line,
LD => LD,
SRAMADDRUpper => SRAMADDRUpper,
SRAMADDR => SRAMADDR,
DATABUS => DATABUS,
OE => OE,
WE => WE,
LB => LB,
UB => UB,
CE1 => CE1,
CE2 => CE2,
data_out => data_out,
AN => AN,
Seven_seg => Seven_seg
);


-- *** Test Bench - User Defined Section ***

clk <= not clk after 6 us;

tb : PROCESS
constant My_Baud_Rate: integer := 9600;

-- Make a jacket procedure around UART_tx, for convenience
procedure send (data: in std_logic_vector) is
begin
UART_tx(
tx_line => serial_line,
data => data,
baud_rate => My_Baud_Rate
);
end;

variable D: std_logic_vector(7 downto 0);
BEGIN

-- Idle awhile
wait for 1 ms;

-- Send an 8-bit character as a test
send("10001110");

-- Idle some more
wait for 1 ms;

wait; -- will wait forever
END PROCESS;
-- *** End Test Bench - User Defined Section ***

END;
 
F

fpgawizz

Jonathan:
I used ur procedure..I have an entity with input ports "Din" ( serial in)
and a clock that i generate. I am generating a 6 us clock which is approx.
16 times faster than 9600 Hz. And i am connecting the serial_line signal
to my Din input as i need my serial data on that line.But all my signals
except the serial_line signal are undefined "UUUUUUUU".
Any idea why even my clock signal is not coming through?

thanks


my testbench code is as follows.

LIBRARY ieee,toplevelib;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
use toplevelib.uart_model.all;

ENTITY datacomm_tb1_vhd_tb IS
END datacomm_tb1_vhd_tb;

ARCHITECTURE behavior OF datacomm_tb1_vhd_tb IS

COMPONENT datacomm
PORT(
clk : IN std_logic;
Din : IN std_logic;
DATABUS : INOUT std_logic_vector(7 downto 0);
LD : OUT std_logic_vector(7 downto 0);
SRAMADDRUpper : OUT std_logic_vector(9 downto 0);
SRAMADDR : OUT std_logic_vector(7 downto 0);
OE : OUT std_logic;
WE : OUT std_logic;
LB : OUT std_logic;
UB : OUT std_logic;
CE1 : OUT std_logic;
CE2 : OUT std_logic;
data_out : OUT std_logic_vector(7 downto 0);
AN : OUT std_logic_vector(3 downto 0);
Seven_seg : OUT std_logic_vector(6 downto 0)
);
END COMPONENT;

SIGNAL clk : std_logic;
SIGNAL Din : std_logic;
SIGNAL LD : std_logic_vector(7 downto 0);
SIGNAL SRAMADDRUpper : std_logic_vector(9 downto 0);
SIGNAL SRAMADDR : std_logic_vector(7 downto 0);
SIGNAL DATABUS : std_logic_vector(7 downto 0);
SIGNAL OE : std_logic;
SIGNAL WE : std_logic;
SIGNAL LB : std_logic;
SIGNAL UB : std_logic;
SIGNAL CE1 : std_logic;
SIGNAL CE2 : std_logic;
SIGNAL data_out : std_logic_vector(7 downto 0);
SIGNAL AN : std_logic_vector(3 downto 0);
SIGNAL Seven_seg : std_logic_vector(6 downto 0);

-- A signal for the tester to drive, initialised to "marking"
signal serial_line: std_logic := '1';
BEGIN

uut: datacomm PORT MAP(
clk => clk,
Din => serial_line,
LD => LD,
SRAMADDRUpper => SRAMADDRUpper,
SRAMADDR => SRAMADDR,
DATABUS => DATABUS,
OE => OE,
WE => WE,
LB => LB,
UB => UB,
CE1 => CE1,
CE2 => CE2,
data_out => data_out,
AN => AN,
Seven_seg => Seven_seg
);


-- *** Test Bench - User Defined Section ***

clk <= not clk after 6 us;

tb : PROCESS
constant My_Baud_Rate: integer := 9600;

-- Make a jacket procedure around UART_tx, for convenience
procedure send (data: in std_logic_vector) is
begin
UART_tx(
tx_line => serial_line,
data => data,
baud_rate => My_Baud_Rate
);
end;

variable D: std_logic_vector(7 downto 0);
BEGIN

-- Idle awhile
wait for 1 ms;

-- Send an 8-bit character as a test
send("10001110");

-- Idle some more
wait for 1 ms;

wait; -- will wait forever
END PROCESS;
-- *** End Test Bench - User Defined Section ***

END;
 
I

info_

initialize your clock signal one way or another !

signal clk : std_logic := '0';
should improve your simulation.

BTW : you can use constants :
const BitPeriod : time := 1 sec / 9600;
will do the math for you, accurately (at your current simulator's resolution).

And I still don't think it's agood idea to have your clock domain set
to 16x the baudrate... but it's a design issue.


Bert Cuzeau
 
F

fpgawizz

Bert
Why is having a 16X clock not a good idea? What would you have the clock
rate set to if you were designing it? Just trying to learn some thing
here..your thoughts would be appreciated.
 
F

fpgawizz

Bert
Why is having a 16X clock not a good idea? What would you have the clock
rate set to if you were designing it? Just trying to learn some thing
here..your thoughts would be appreciated.
 
I

info_

fpgawizz said:
Bert
Why is having a 16X clock not a good idea? What would you have the clock
rate set to if you were designing it? Just trying to learn some thing
here..your thoughts would be appreciated.


My guess is that you didn't get this idea of 16x clock by yourself : you were
influenced by what has been done by others with different constraints or agenda.
But that's my opinion, you're free not to share it.

The other more concrete reasons I don't like that are :
- this scheme wont work well if you want to do 921k bauds transmission with
a 25 MHz (or any other "standard" value) oscillator.
(A user of our UART IP used it at this baud rate wihtout any problem.)
- You would need a special frequency oscillator or sacrify a PLL for this.
- Your description tends to make me believe you will end up with
several clock domains ! A uart is not a good enough reason to go
into the problems you will very likely meet if you're not
used to edaling with clock domains crossings.

The "good" clock, to me, is your board's oscilator one and only clock
unless you have reasons to do otherwise (SDram controller, camera
or video interface, etc... are usually valid reasons for extra clock domains)

Bert Cuzeau
 
Joined
Jun 3, 2010
Messages
1
Reaction score
0
help me please

hello,
Please help me!!!!!!!!!!
Could you help me. I am a student, write a diploma "Simulation and Design of microcontroller based on the processor dp 32" and for the protection I need a code Ewart (full + test) to work with the PC processor 232.
Do you have desired me to code? It is very important and very urgent)))
Thank
Lena
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,021
Latest member
AkilahJaim

Latest Threads

Top