Chris_C

USB specifics for the Pro

Recommended Posts

I've been digging round on the site trying to find anything about usb specific to the pro...

 

so code for an echo server would be nice! :)

 

Can I use channel A just like the other papilio's are there pin/timing differences?

 

basically I want to have two way communications between my development machine and the fpga (without needing to swap cables about) so I can for example while "running" designs I can send data to change a state machine for example (instead of using switches) and also recieve messages back by way of feedback...

 

Looks like my Pro has been stuck in the same sorting station for the last three days, but I'm wanting to do all the theoretical research and learning I can so I'm ready for my first breadboard face plant :o) as soon as it lands....

 

I have to say making my own vga controller looks way more interesting than when I used a microcontroller to bit bang a tv signal - and that was fun - so I can't wait

 

Share this post


Link to post
Share on other sites

I don't want to use a soft core, be it picoblaze or similar, I've done microcontrollers to death! and I'm looking at using just HDL

The link (2) you supplied seems to be for the picoblaze, I was hoping it would be possible to create a circuit to drive the usb chip directly, using some of the fpga's internal ram as a buffer if needed. in a similar way that there are a bunch of VGA controllers that don't necessary need a processor...

Share this post


Link to post
Share on other sites

Hi Chris,

 

The short summary is it shifts bits into a 40-bit shift register at a rate 4x that of the serial link. When oldest three are zero (the start bits), then the 5th, 9th, 13th, 17th, 21st, 25th, 29th and 33th bits are taken as the data bits, and the contents of oldest 39 bits are reset to '1' (the idle state of the link).

 

You could also check the 37th bit of the shift register for a stop bit if you want. Far quicker to hack up than a proper UART.

 

Mike

Share this post


Link to post
Share on other sites

there only seems to be TX/RX pins? I see the jtag clk but not channel A clk?, its not clear looking at the schematic or even the constraint file how the FT2232D is wired to the fpga (save the jtag half)

The eprom connected to the FT2232D pasumably provides power on settings but can the settings of the FT2232D be changed given the physical circuit the FT2232D is in... or is it even worth changing anything....

Share this post


Link to post
Share on other sites

Having a look at BPC3010_Papilio_Pro.pdf, there is only 5 connections to the FPGA - TCK,TDI, TMS, USB_TXD & USB_RXD.

 

Possibly this is due to the limited pin count of the FPGA's package - with 48 I/Os, the SDRAM, EPPROM, clocks and LEDs there wasn't many pins left over...

Share this post


Link to post
Share on other sites

okay I'm away from my computer ATM but I think I see where I got confused! channel A is the JTAG channel then?

I'll read up on the classic mode in the data sheet when I get back...

thanks guys!

Share this post


Link to post
Share on other sites

Well as a replacement for physical switches usb is ideal as your programming machine is already connected...

 

any tutorial that can be done soley with a pro without external circuitary has to be onto a winner as it covers ALL pro owners regardless of what wings they have bought, although having said that with a breadboard and 20 mins....

 

Given your great writing style in the last ebook of yours i read I would welcome this for sure!

Share this post


Link to post
Share on other sites

Hamster,

 

That would be really great! If you create an account at learn.gadgetfactory.net I will give you access to write tutorials. I think everything is dialed in to the point where it will be very easy to use now.

 

Jack.

Share this post


Link to post
Share on other sites

Hi Jack - all ready to go - you zap me through an account I'll post this up with more pictures...

 

The quickest way to implement PC-to-FPGA comms on a Papilio FPGA board.
 
The design of the Papilio family has USB interface chip, which presents two 'COM' ports to the PC. The first is usually used as a JTAG interface for programming the FPGA. The second can be used to talk with a design running in the FPGA using the RS232 protocol.
 
RS232 is a very old and simple protocol, and has lots of signals that help co-ordinate the data transfer, however for simple applications only the "TX" (transmit) and "RX" (receive) signals need to be used. The same protocol used over both these wires, the difference is that the data is sent in opposite directions.
 
To send an 8-bit byte it is changed to a 10-bit frame, but adding 'start bit' of '0' before the least significant bit, and adding a 'stop bit' of '1' after the most significant bit.  These values are chosen as when the line is idle it is held at logical '1', so on an idle line the first 1->0 transition can be used to indicate when a frame starts. The frame is is then transmitted down the wire, start bit first, stop bit last at the desired baud (bits per second) rate
 
The actual wiring is where it starts getting tricky. RS232 was originally used for dumb terminals and printers to talk with mainframe computes using analog modems, and in the context of a terminal it is pretty easy to understand the wiring. The 'TX' connection on a terminal sends data to the 'TX' connection on the modem, and the modem then sends it off down the phone line as a series of beeps. Data being received from the analogue line appears on the 'RX' signal on the modem, which is connected to the 'RX' connection on the terminal. The names used in the different configurations (the one used on a terminal and the one used on a modem) are called DTE ("Data Terminal Equipment") and DCE ("Data Communication Equipment").
 
So what happens when there are no modems in the link between two DTEs? Like when a printer is plugged directly into a serial port? The short answer is it gets really confusing. The TX on one device needs to be wired to the RX on the other. This model gives two points of view for labeling signals. On the Papilio boards the signals are labelled from the perspective of the USB interface - data from the interface is received on the TX line, and sent on the RX line. 
 
An easier way of thinking about the Papilio board is this: "It is wired as you would expect it to be if it was a modem". Incoming data form the host is presented to the FPGA on the "TX" line (in this context "please transmit this"), and the FPGA can send data to the host on the the RX line (in this context, "I've received this for you").
 
So the aim for this project is to receive data off of the TX line (yeah, it sucks) and display it on a LogicStart's LEDs. The easiest place to start is the constraints required for the ten pins that will be used -  8 LEDs, the TX signal and the clock:
 
These are the constraints for the Papilio Pro:
 
  CONFIG PROHIBIT=P144;
  CONFIG PROHIBIT=P69;
  CONFIG PROHIBIT=P60;
 
  NET CLK            LOC="P94"  | IOSTANDARD=LVTTL | PERIOD=31.25ns;               # CLK
  NET TX             LOC="P105" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST | PULLUP; # TX
  NET LED(7)         LOC="P114" | IOSTANDARD=LVTTL;                                # C0
  NET LED(6)         LOC="P115" | IOSTANDARD=LVTTL;                                # C1
  NET LED(5)         LOC="P116" | IOSTANDARD=LVTTL;                                # C2
  NET LED(4)         LOC="P117" | IOSTANDARD=LVTTL;                                # C3
  NET LED(3)         LOC="P118" | IOSTANDARD=LVTTL;                                # C4
  NET LED(2)         LOC="P119" | IOSTANDARD=LVTTL;                                # C5
  NET LED(1)         LOC="P120" | IOSTANDARD=LVTTL;                                # C6
  NET LED(0)         LOC="P121" | IOSTANDARD=LVTTL;                                # C7
 
These are the constraints for the Papilio One:
 
########## Papilio One #########
CONFIG PROHIBIT=P99;
CONFIG PROHIBIT=P43;
CONFIG PROHIBIT=P42;
CONFIG PROHIBIT=P39;
CONFIG PROHIBIT=P49;
CONFIG PROHIBIT=P48;
CONFIG PROHIBIT=P47;
CONFIG PART=XC3S250E-VQ100-4;
 
NET CLK          LOC="P89"  | IOSTANDARD=LVTTL | PERIOD=31.25ns;               # CLK
NET TX           LOC="P88"  | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST | PULLUP; # TX
NET LED(7)       LOC="P17"  | IOSTANDARD=LVTTL;                                # C0
NET LED(6)       LOC="P16"  | IOSTANDARD=LVTTL;                                # C1
NET LED(5)       LOC="P15"  | IOSTANDARD=LVTTL;                                # C2
NET LED(4)       LOC="P12"  | IOSTANDARD=LVTTL;                                # C3
NET LED(3)       LOC="P11"  | IOSTANDARD=LVTTL;                                # C4
NET LED(2)       LOC="P10"  | IOSTANDARD=LVTTL;                                # C5
NET LED(1)       LOC="P9"   | IOSTANDARD=LVTTL;                                # C6
NET LED(0)       LOC="P5"   | IOSTANDARD=LVTTL;                                # C7
 
Great, with that done we can move on to what the high-level receiving component will look like. Working from what signals it needs to source and sink, and what it needs to be correctly configured. I ended up with the following design ('frequency' is the clock frequency, 'baud' is the bits per second rate of the RS232 connection - 9600 is pretty much the de facto standard for human-speed transfers).
 
   COMPONENT rs232_rx
   GENERIC ( frequency   : natural;
             baud        : natural);
   PORT    ( clk         : IN std_logic;
             rx          : IN std_logic;          
             data        : OUT std_logic_vector(7 downto 0);
             data_strobe : OUT std_logic);
   END COMPONENT;
 
This component can be added into a top level design. In the top level design we don't have to to much, just map the external connections of the FPGA through to the rs232_rx module (Note how "rx" is mapped to the "tx" pin - you can understand why this is now that you are a pro at serial comms):
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
entity rs232_rx_demo is
    Port ( clk : in  STD_LOGIC;
           tx  : in  STD_LOGIC;
           led : out  STD_LOGIC_VECTOR (7 downto 0));
end rs232_rx_demo;
 
architecture Behavioral of rs232_rx_demo is
   COMPONENT rs232_rx
   GENERIC ( frequency   : natural;
             baud        : natural);
   PORT    ( clk         : IN std_logic;
             rx          : IN std_logic;          
             data        : OUT std_logic_vector(7 downto 0);
             data_strobe : OUT std_logic);
   END COMPONENT;
begin
Inst_rs232_rx: rs232_rx 
   GENERIC MAP (frequency => 32000000, baud => 9600)
   PORT MAP(clk => clk,   rx => tx, data => led, data_strobe => open);
 
end Behavioral;
 
So now we come down to the tricky bit. How do you receive the bits coming in at a given rate, then present them on the 'data' signals? There are plenty of ways to do this, but I'm using a nieve approach based on oversampling. If we sample the signal four times quicker than needed, and remember the last 40 quater-bits (for a full 10 bit frame). To control when the samples are taken I use a counter ("baud_x4") which rolls over after the correct number of clock ticks.
 
When the oldest three bits are zeros then I assume they are the start bit and grab every forth bit (bits 34, 30, 26, 22, 18, 14, 10, 6) to present as the received data. I don't bother presenting the start bit or stop bit - they are just used for framing the data on the wire - however If you are at all worried about data integrity you should test that bit 2 is a valid stop bit (value of '1').
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity rs232_rx is
   GENERIC (
      frequency   : natural;
      baud        : natural
      );
    Port ( clk : in  STD_LOGIC;
           rx : in  STD_LOGIC;
           data : out  STD_LOGIC_VECTOR (7 downto 0);
           data_strobe : out  STD_LOGIC);
end rs232_rx;
 
architecture Behavioral of rs232_rx is
   signal oversampled_bits : std_logic_vector(39 downto 0);
   signal baud_x4 : unsigned(11 downto 0) := (others => '0');
begin
 
process(clk)
   begin
      if rising_edge(clk) then
         data_strobe <= '0';
      
         if baud_x4 = 0 then
            -- If a start bit is seen then capture the data and reset the shift registers
            if oversampled_bits(39 downto 37) = "000" then
               data_strobe <= '1';
               data <= oversampled_bits(34) & oversampled_bits(30) 
                     & oversampled_bits(26) & oversampled_bits(22) 
                     & oversampled_bits(18) & oversampled_bits(14) 
                     & oversampled_bits(10) & oversampled_bits( 6); 
               oversampled_bits(39 downto 1) <= (others => '1');
               oversampled_bits(0) <= rx;
            else
               -- Just capture another bit in the shift register.
               oversampled_bits <= oversampled_bits(38 downto 0) & rx;
             end if;
         end if;
 
         -- process the interval counter
         if baud_x4 = frequency  / (baud*4) - 1 then
            baud_x4 <= (others => '0');
         else
            baud_x4 <= baud_x4+1;
         end if;
      end if;
   end process;
end Behavioral;
 
And that is it! Just build the project, download the project to the FPGA, open a terminal program (I recommend "Putty"), connect to the higher number COM port on the Papilio with the following parameters:
  • 9600 baud 
  • No parity
  • 1 stop bit
 
Then press some keys to light some LEDs.

Share this post


Link to post
Share on other sites

amazing, thanks so much, it's so clear! yes the over sampling one way coms could be accused (by the mean spirited) of being a quick hack, but it's exactly the clear quick hack that can be easily understood / explained and its a great place to start from.... (far far better than scratch!)

 

and I'm sure not only will I be using it, but I bet a whole raft of "newbies" like me will find it immensely useful

 

really looking forward to playing with this and developing it further

 

One point of confusion still mind!!!

Channel A is just used to program the FPGA and channel B just has the tx and rx pins connected. You need to use the classic UART mode.

http://papilio.cc/index.php?n=Papilio.PapilioPro says A is fast coms, and B is jtag

 

looking at the circuit diagram, channel B (bus D ???) seems to have only TX/RX connected so I assumed that was the fast async coms, where as channel A (bus C ???) has a bunch of extra signals connected so I assumed that was the jtag channel (with the others signals is syncronous?) - I have to look at the datasheet again after some sleep!

 

I couldn't seem to find the labels that these lead to so couldn't sync it up with the constraint file so easily

 

so bit confused there...!

 

also is it possible to solder some fly leads to the FTDI chips unconnected pins so they could be plugged into pins on an unused wing? or do the chips eeprom settings preclude this?

 

.... and finally if I was shooting data at it at say 115200 baud would the FTDI need some change of settings or would it see the faster incoming connection and automagically configure it at spit out 115200baud over the RX pin

right that’s it! all out of dumb questions and need my bed!

again thanks for that really clear tutorial, even given the oddities of VHDL (for a new comer) I still understood what was going on!

Share this post


Link to post
Share on other sites

I'll have to defer the FTDI & port questions to Jack - all I know is that COM5 is JTAG and COM6 is the serial port on my Papilio One... however, once you get your hardware it should just work - Even if you guess at random you have a 50/50 chance of it working first time!

 

I'm sure it is possible to patch some wires onto he FTDI chip, but I would be tempted to break one of these (https://www.sparkfun.com/products/9873) instead of my Papilio Pro, saving a few $s if  you make a stuff up. There is lots of other fun stuff to do before you start board modding :)

 

Jack has been able to get 2Mb/s over the serial port before the USB interface or host starts dropping bytes, or the timing gets too tricky for it to work. At higher speeds you might need to use some clocking resources to run at a better frequency that 32MHz (eg. 72MHz) to minimise rounding errors in the bit timing at very high speed.

Share this post


Link to post
Share on other sites

I'd kinda assumed to get (really) decent speeds you'd need a serial clock signal...

of course like you suggest there are a whole 48 signal lines to play with so really I could just keep the onboard usb purely for programming and implement a different coms route depending on application...

heck there's SPI and in any case a lot of SoC's use I2C internally between blocks as well as externally (ie cpu <> watchdog)

thanks again for the run through on getting started with usb input...

Share this post


Link to post
Share on other sites

For the baud question the answer is that the FTDI chip actually acts as a USB serial port for the PC and the PC configures the baud rate, so you have to set this to the same thing that you are using on the papilio, there is no magic here and you WILL get wrong results if you set it wrong.

Share this post


Link to post
Share on other sites

from for example Linux, is it possible to configure the FTDI driver on the fly?

can I set an arbitrary baud rate for the driver and have my fpga circuit use that bit rate?

Share this post


Link to post
Share on other sites

From the FPGA end "auto-bauding" would be possible, but error prone. The RS232 protocol isn't very well designed for recovering the send's clock. As an example, If the receiver sees "0000011111" is the a complete frame for 0x0F, or is the first two bits of something being transmitted at 1/5th the speed?

 

Protocols like S/PDIF have fixed length symbols that are either one, two or three bit-times in length,and that all occur in each frame. This allows the receiver to observe the longest and shortest time between transitions, and then deduce the raw data rate very quickly and accurately.

 

The gold standard serial encoding is 8b/10b coding (used in lots of stuff - like FibreChannel). It is truly awesome - and has an intrinsic beauty to it. 8b/10b makes RS232 look like the ugliest kid in town  (if I can use such and un P.C. comparison).

Share this post


Link to post
Share on other sites

from for example Linux, is it possible to configure the FTDI driver on the fly?

can I set an arbitrary baud rate for the driver and have my fpga circuit use that bit rate?

 

Yes you can change the baud rate on linux whenever, its a standard serial port operation, I don't know if you can use arbitrary rates though, you can definitely pick any of the usual ones like 115200 though.

Share this post


Link to post
Share on other sites

Chris, seriously, all of your questions should be answered in the high speed UART example. That example is not a picoblaze implementation, the UART is a standalone VHDL or Verilog example. It's just a part of the picoblaze code base, but it is not implementing a picoblaze soft processor. So even though it will probably be better to use Hamster's code, you will get a lot of Papilio specific answers by watching the tutorial I put together...

 

For channel B only rx and tx are connected in the 232 UART Interface mode described in the datasheet on page 31. This mode is capable of speeds up to 3Mbaud according to the first page of the datasheet and as tested out in the high speed UART example.

post-29509-0-62090200-1386004634_thumb.p

 

In order to achieve this speed you need to set the transfer rate of the UART you are implementing in the FPGA to run at 3Mbaud and you need your PC client to be set at the same speed. For the high speed UART example the speed was set by controlling the oversample clock speed from what I remember...

Share this post


Link to post
Share on other sites

Hamster, thank you so much for putting this together. I created an account for you on learn.gadgetfactory.net, its good to know I can do that. You should be getting an email with the username/password.

 

Writing an article on the learn site is super easy, all you need to know is that you create a new section in the table of contents by using the H1 header. When you preview or publish the article the stylesheet will applied and you will see the table of contents and the section boxes applied to your article. You can also use the "Snippet Vault" on the right to add callout boxes such as tip, information, post it notes. The stylesheets are applied to the editor too so you should get a WYSIWYG experience with those.

 

Let me know if there are any problems or issues.

 

Thanks!

Jack.

 

 

Hi Jack - all ready to go - you zap me through an account I'll post this up with more pictures...

 

The quickest way to implement PC-to-FPGA comms on a Papilio FPGA board.
 
The design of the Papilio family has USB interface chip, which presents two 'COM' ports to the PC. The first is usually used as a JTAG interface for programming the FPGA. The second can be used to talk with a design running in the FPGA using the RS232 protocol.
 
RS232 is a very old and simple protocol, and has lots of signals that help co-ordinate the data transfer, however for simple applications only the "TX" (transmit) and "RX" (receive) signals need to be used. The same protocol used over both these wires, the difference is that the data is sent in opposite directions.
 
To send an 8-bit byte it is changed to a 10-bit frame, but adding 'start bit' of '0' before the least significant bit, and adding a 'stop bit' of '1' after the most significant bit.  These values are chosen as when the line is idle it is held at logical '1', so on an idle line the first 1->0 transition can be used to indicate when a frame starts. The frame is is then transmitted down the wire, start bit first, stop bit last at the desired baud (bits per second) rate
 
The actual wiring is where it starts getting tricky. RS232 was originally used for dumb terminals and printers to talk with mainframe computes using analog modems, and in the context of a terminal it is pretty easy to understand the wiring. The 'TX' connection on a terminal sends data to the 'TX' connection on the modem, and the modem then sends it off down the phone line as a series of beeps. Data being received from the analogue line appears on the 'RX' signal on the modem, which is connected to the 'RX' connection on the terminal. The names used in the different configurations (the one used on a terminal and the one used on a modem) are called DTE ("Data Terminal Equipment") and DCE ("Data Communication Equipment").
 
So what happens when there are no modems in the link between two DTEs? Like when a printer is plugged directly into a serial port? The short answer is it gets really confusing. The TX on one device needs to be wired to the RX on the other. This model gives two points of view for labeling signals. On the Papilio boards the signals are labelled from the perspective of the USB interface - data from the interface is received on the TX line, and sent on the RX line. 
 
An easier way of thinking about the Papilio board is this: "It is wired as you would expect it to be if it was a modem". Incoming data form the host is presented to the FPGA on the "TX" line (in this context "please transmit this"), and the FPGA can send data to the host on the the RX line (in this context, "I've received this for you").
 
So the aim for this project is to receive data off of the TX line (yeah, it sucks) and display it on a LogicStart's LEDs. The easiest place to start is the constraints required for the ten pins that will be used -  8 LEDs, the TX signal and the clock:
 
These are the constraints for the Papilio Pro:
 
  CONFIG PROHIBIT=P144;
  CONFIG PROHIBIT=P69;
  CONFIG PROHIBIT=P60;
 
  NET CLK            LOC="P94"  | IOSTANDARD=LVTTL | PERIOD=31.25ns;               # CLK
  NET TX             LOC="P105" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST | PULLUP; # TX
  NET LED(7)         LOC="P114" | IOSTANDARD=LVTTL;                                # C0
  NET LED(6)         LOC="P115" | IOSTANDARD=LVTTL;                                # C1
  NET LED(5)         LOC="P116" | IOSTANDARD=LVTTL;                                # C2
  NET LED(4)         LOC="P117" | IOSTANDARD=LVTTL;                                # C3
  NET LED(3)         LOC="P118" | IOSTANDARD=LVTTL;                                # C4
  NET LED(2)         LOC="P119" | IOSTANDARD=LVTTL;                                # C5
  NET LED(1)         LOC="P120" | IOSTANDARD=LVTTL;                                # C6
  NET LED(0)         LOC="P121" | IOSTANDARD=LVTTL;                                # C7
 
These are the constraints for the Papilio One:
 
########## Papilio One #########
CONFIG PROHIBIT=P99;
CONFIG PROHIBIT=P43;
CONFIG PROHIBIT=P42;
CONFIG PROHIBIT=P39;
CONFIG PROHIBIT=P49;
CONFIG PROHIBIT=P48;
CONFIG PROHIBIT=P47;
CONFIG PART=XC3S250E-VQ100-4;
 
NET CLK          LOC="P89"  | IOSTANDARD=LVTTL | PERIOD=31.25ns;               # CLK
NET TX           LOC="P88"  | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST | PULLUP; # TX
NET LED(7)       LOC="P17"  | IOSTANDARD=LVTTL;                                # C0
NET LED(6)       LOC="P16"  | IOSTANDARD=LVTTL;                                # C1
NET LED(5)       LOC="P15"  | IOSTANDARD=LVTTL;                                # C2
NET LED(4)       LOC="P12"  | IOSTANDARD=LVTTL;                                # C3
NET LED(3)       LOC="P11"  | IOSTANDARD=LVTTL;                                # C4
NET LED(2)       LOC="P10"  | IOSTANDARD=LVTTL;                                # C5
NET LED(1)       LOC="P9"   | IOSTANDARD=LVTTL;                                # C6
NET LED(0)       LOC="P5"   | IOSTANDARD=LVTTL;                                # C7
 
Great, with that done we can move on to what the high-level receiving component will look like. Working from what signals it needs to source and sink, and what it needs to be correctly configured. I ended up with the following design ('frequency' is the clock frequency, 'baud' is the bits per second rate of the RS232 connection - 9600 is pretty much the de facto standard for human-speed transfers).
 
   COMPONENT rs232_rx
   GENERIC ( frequency   : natural;
             baud        : natural);
   PORT    ( clk         : IN std_logic;
             rx          : IN std_logic;          
             data        : OUT std_logic_vector(7 downto 0);
             data_strobe : OUT std_logic);
   END COMPONENT;
 
This component can be added into a top level design. In the top level design we don't have to to much, just map the external connections of the FPGA through to the rs232_rx module (Note how "rx" is mapped to the "tx" pin - you can understand why this is now that you are a pro at serial comms):
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
entity rs232_rx_demo is
    Port ( clk : in  STD_LOGIC;
           tx  : in  STD_LOGIC;
           led : out  STD_LOGIC_VECTOR (7 downto 0));
end rs232_rx_demo;
 
architecture Behavioral of rs232_rx_demo is
   COMPONENT rs232_rx
   GENERIC ( frequency   : natural;
             baud        : natural);
   PORT    ( clk         : IN std_logic;
             rx          : IN std_logic;          
             data        : OUT std_logic_vector(7 downto 0);
             data_strobe : OUT std_logic);
   END COMPONENT;
begin
Inst_rs232_rx: rs232_rx 
   GENERIC MAP (frequency => 32000000, baud => 9600)
   PORT MAP(clk => clk,   rx => tx, data => led, data_strobe => open);
 
end Behavioral;
 
So now we come down to the tricky bit. How do you receive the bits coming in at a given rate, then present them on the 'data' signals? There are plenty of ways to do this, but I'm using a nieve approach based on oversampling. If we sample the signal four times quicker than needed, and remember the last 40 quater-bits (for a full 10 bit frame). To control when the samples are taken I use a counter ("baud_x4") which rolls over after the correct number of clock ticks.
 
When the oldest three bits are zeros then I assume they are the start bit and grab every forth bit (bits 34, 30, 26, 22, 18, 14, 10, 6) to present as the received data. I don't bother presenting the start bit or stop bit - they are just used for framing the data on the wire - however If you are at all worried about data integrity you should test that bit 2 is a valid stop bit (value of '1').
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity rs232_rx is
   GENERIC (
      frequency   : natural;
      baud        : natural
      );
    Port ( clk : in  STD_LOGIC;
           rx : in  STD_LOGIC;
           data : out  STD_LOGIC_VECTOR (7 downto 0);
           data_strobe : out  STD_LOGIC);
end rs232_rx;
 
architecture Behavioral of rs232_rx is
   signal oversampled_bits : std_logic_vector(39 downto 0);
   signal baud_x4 : unsigned(11 downto 0) := (others => '0');
begin
 
process(clk)
   begin
      if rising_edge(clk) then
         data_strobe <= '0';
      
         if baud_x4 = 0 then
            -- If a start bit is seen then capture the data and reset the shift registers
            if oversampled_bits(39 downto 37) = "000" then
               data_strobe <= '1';
               data <= oversampled_bits(34) & oversampled_bits(30) 
                     & oversampled_bits(26) & oversampled_bits(22) 
                     & oversampled_bits(18) & oversampled_bits(14) 
                     & oversampled_bits(10) & oversampled_bits( 6); 
               oversampled_bits(39 downto 1) <= (others => '1');
               oversampled_bits(0) <= rx;
            else
               -- Just capture another bit in the shift register.
               oversampled_bits <= oversampled_bits(38 downto 0) & rx;
             end if;
         end if;
 
         -- process the interval counter
         if baud_x4 = frequency  / (baud*4) - 1 then
            baud_x4 <= (others => '0');
         else
            baud_x4 <= baud_x4+1;
         end if;
      end if;
   end process;
end Behavioral;
 
And that is it! Just build the project, download the project to the FPGA, open a terminal program (I recommend "Putty"), connect to the higher number COM port on the Papilio with the following parameters:
  • 9600 baud 
  • No parity
  • 1 stop bit
 
Then press some keys to light some LEDs.

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now