Setting up a serial transmission on the Papilio One

So here is the first thing I did when I received my Papilio One board.

rs232_tx_putty

I thought about writing this post after having read a tutorial by Jack Garrett, the man behind the Papilio: HighSpeedUART. He basically shows you how to do the same thing, but he makes use of a UART module part of the picoblaze proprietary soft processor from Xilinx. Even tho its source code is available, it is not Free, you wouldn’t be able to use it in your Open Source Hardware designs.

You can see here the content of a byte being updated inside the component. The amazing thing about this is that it can be done in less than 15 minutes! To achieve this rather simple thing I used an already existent VHDL module from opencores, but RS232 being fairly straight forward it would be quite easy to do it yourself.

You can clone my samples repository using git:

$ git clone git://git.tuxfamily.org/gitroot/toastertech/samples.git

If you’re not familiar with git you can browse the repository here.

Using the core

So as I just said, before even looking at how to implement a serial communication for an FPGA, I went to opencores‘s website and scrolled through the numerous projects available. I finally chose this one: Uart block

Then all I had to do was chose the files I needed form the project and embed them in my design. I wanted a serial transmission, aka TX, and I took it.

The corresponding file being serial_transmitter.vhd.

Here is the component instantiation: `

use work.pkgDefinitions.all;

-- (..)

component serial_transmitter is
    port( 
        RST: in  std_logic;
        BAUDCLK: in  std_logic; 
        DATA_BYTE: in  std_logic_vector(nbits - 1 downto 0); 
        DATA_SENT: out std_logic; 
        SERIAL_OUT: out  std_logic
    );
end component;

It is quite self-explanatory, you need to connect up the SERIAL_OUT to the papilio‘s TX pin and the data you wish to send corresponds to DATA_SENT, a nbits length vector.

One of the reasons why I chose this project from opencores‘s numerous UART implementations was that it contained test benches for each VHDL module. So here is how the serial transmitter works:

rs232_tx_testbench

The module is being resetted in between each transmission, or so says that test bench. I’ve followed this guideline for the next part.

So we have a serial transmission ready to send characters to a computer or other peripherals in just 15 minutes! Now I’m going to go through what I did to display an internal byte on the terminal, that took a bit longer I’m afraid, but it’s still quite straight forward.

Displaying a byte

So what I initialy wanted to do was to use this as a simple debugging tool.

So here is a module that transmits a character 0 or 1 according to the given byte: BYTE_TRANSMITTER

entity BYTE_TRANSMITTER is
    port( 
        TX : out  std_logic;
        DATA_SEND: in std_logic;
        DATA_IN: in std_logic_vector(7 downto 0);
        DATA_OUT: out std_logic_vector(7 downto 0);
        CLK : in std_logic
    );
end BYTE_TRANSMITTER;

DATA_SEND serves as an enable input.

It then sends each character thanks to a state machine controlling the transmission core. This is were things get a little tricky.

I hope I’ve done things right, but I strongly suspect that it is needlessly complicated. I am still a VHDL newbie so if anybody reading this thinks what I’ve done could be improved then feel free to shout at me ;-).

Triggering the transmission

A start signal is used synchronously to trigger a transmission on its rising edge.

process(CLK)
begin
    if rising_edge(CLK)
    then
        data_send_buf <= DATA_SEND;                    -- the enable signal 
    end if;                                            -- is used synchronously
end process;

process(data_send_buf, CLK)
begin
    if start = '1' and transmitter_state = preparing   -- once the transmission
    then                                               -- has started, 
        start <= '0';                                  -- "start" goes back to 0
    elsif rising_edge(data_send_buf)
    then
        start <= '1';                                  -- triggering a transmission
        data_in_buf <= DATA_IN;
    end if;
end process;

Transmission state machine

Here are the different states used:

type state is (waiting, preparing, transmitting);
signal transmitter_state: state := waiting;

It goes as follows:

  • waiting for an enable signal (DATA_SEND).
  • preparing, holds the reset high for a few clock cycles
  • transmitting, then back to preparing untill all characters are sent.

rs232_tx_statemachine

process(CLK)
begin
    if rising_edge(CLK)
    then
        case transmitter_state is
            when waiting =>                                  
                tx_rst <= '1';                           -- holding reset state
                if start = '1'                           -- to 1
                then
                    transmitter_state <= preparing;      -- moving to preparing
                end if;                                  -- when start = 1
            when preparing =>
                tx_rst <= '1';
                count_preparing <= count_preparing + 1;  -- simple counter
                if count_preparing = 4                   -- that holds the machine
                then                                     -- in its preparing state
                    transmitter_state <= transmitting;   -- for a few clock cycles
                    count_preparing <= 0;
                end if;
            when transmitting =>                         -- actual transmission
                tx_rst <= '0';
                if count_char = 9                        -- at the end of the 
                then                                     -- counting we're
                    char <= X"0A";                       -- sending 2 bytes ending
                elsif count_char = 8                     -- the line and moving
                then                                     -- on to the next one
                    char <= X"0D";
                else
                    if data_in_buf(7 - count_char) = '0' -- we're counting
                    then                                 -- up the byte "data_in"
                        char <= X"30";
                    else
                        char <= X"31";
                    end if;
                end if;
                if data_sent = '1'                      -- counting is only
                then                                    -- done when the character
                    if count_char = 9                   -- has been sent
                    then
                        count_char <= 0;                -- end of characters
                        transmitter_state <= waiting;   -- transmissions
                    else
                        count_char <= count_char + 1;   -- we're moving on to
                        transmitter_state <= preparing; -- preparing in between
                    end if;                             -- each character
                end if;
        end case;
    end if;
end process;

And there we go! We have a VHDL module that sends characters according to an internal byte!

Now let’s get this working in real life and make it show is an FPGA can count.

Adapting the baud rate

The Papilio One ships with a 32MHz oscillator on board, so to set up a specific band rate all we have to do is divide the main clock with a counter. One bit will be transmitted on each rising edge of the BAUDCLK signal of the transmistter, so whatever frequency we set this to, the baud rate will be half of it.

In the TOP_LEVEL module in the samples we can simply divide the main clock by 8 for example, connecting the fourth least significant bit of our main counter.
baudclock=\frac{32 \times 10^6}{8}=4 \times 10^6 Hz

baudrate=\frac{baudclock}{2}=2\times 10^6 bits\ per\ second

Doesn’t it just look lovely with \LaTeX :-), I know I was just looking for an excuse to use this…

So here we have a baud rate of 2Mbit per second.

All we need to do is set up putty and we’re set!

Here are the configuration of the transmission:

  • Speed (baud) : 2000000
  • Data bits: 8
  • Stop bits: 1
  • Parity: None
  • Flow control: None

If you don’t know which device node ( in a Linux system ), is assigned to the Papilio One on your system, as in /dev/ttyUSBX, here’s a useful way to find out:

$ ls /sys/bus/usb-serial/drivers/ftdi_sio
bind  module  new_id  ttyUSB8  uevent  unbind

Thanks

I hope somebody out there could find this useful, source code is available on the git repository, and if you’re lazy I’ve even uploaded a bitstream here to test it.

I’ve recently been doing work with interfacing the RaspberryPi micro-computer with the Papilio using SPI, and again using a project form opencores. I shall write a post about that later, but maybe more oriented towards my attempt at writing a device driver for Linux.

One thought on “Setting up a serial transmission on the Papilio One

  1. Thanks a lot man! I just begun the same journey and got stuck at serial communication, not only does this article answer most of my unvoiced questions but it also pointed me in the right direction! Cheers! :-)

Leave a comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>