Jump to content

Arty A7 100 UART echo example


Recommended Posts

I am looking to learn more about peripherals on my board and UART appears to be the best option to start experimenting. Can someone suggest how I could create an echo UART design?

I would like to communicate to the board as so

echo "1" > /dev/ttyUSB1

And would like to read it back, perhaps via

screen /dev/ttyUSB1 9600



Link to comment
Share on other sites

Hi Ed,

You have chosen well -- implementing a simple UART is a great learning experience. I'd recommend trying to make a blinking LED even before that, though.

As to the UART:

As a first step, to verify that your connection is working and that you can talk to the /dev/ttyUSB device, create the simplest loopback of all: just hook up the TX and RX at the FPGA side, and presto! With about 10 lines of Verilog of VHDL, that's an actual working loopback.

Getting that to work in Vivado is a good way to make sure you have a basic grasp of the tools. In particular, you will need a constraints file that tells Vivado which physical pin location corresponds to your SERIAL_TX and SERIAL_RX pins (or whatever you decide to call them).

If you now press a key on the PC side in a terminal program (screen, or something like minicom), it should echo back to you -- and this will work at any COM setting.

Implementing the functional UART is the next step. For starters, it is useful to consider the FPGA's "TX" and "RX" sides as two different, quite independent devices; and to implement them one by one. The TX side (FPGA to PC) is easiest.

Make sure you understand the serial protocol, and stick to 8N1 to get started, at some reasonable baudrate; 9600 is fine.

As an in-between step, send out a block wave on the TX pin of the appropriate frequency (each 1 and 0 should be f_clk/baudrate cycles long).

This corresponds to sending a lot of 0x55 bytes, which you should receive on the PC side as "U" characters. If that work, you're getting close.

Note that, to get this to work, you will need to add a clock to your constraints file.


Next step is to implement a proper state machine to handle any byte and shift it out over the TX pin, including START and STOP bits. This is where you need to flex your VHDL or Verilog muscle. There are many styles to build a UART transmitter, but first thing is to make something that works, and that can, for example, emit 0x41 (showing an 'A' on the receiving end).

To a large extent, programming FPGAs is a matter of implementing small state-machines that do a single task, and hooking them up together. As your understanding of FPGAs grows you will start to develop a feel for good and bad ideas for designing VHDL (or Verilog) state machines.

For example, one Good Idea is to interface between two state machines by having the sender manage a VALID flag ("DATA_OUT is valid") and the receiver manage a READY flag ("I am willing and able to handle incoming data on DATA_IN). At each clock cycle, the sending state machine and the receiving state machine inspect the current value of both signals (as set on the previous clock cycle) to decide whether data is transferred from DATA_IN to DATA_OUT. Using such a convention consistently will save you many headaches.

Another Good Idea is, for each state machine, to only use registered outputs, and to be quite consistent about that. This prevents combinatorial chains and the headaches (and lower performance due to lower achievable clock frequencies) that comes with that.

Another Good Idea is to make sure any external input (such as a BUTTON, or a serial input) is put into a register (flip-flop) at one location, on each clock cycle. For the rest of your design, only use the registered version of the signal. Not doing this will lead to strange behaviors where the device exhibits behavior that seemingly "cannot happen" -- because the external value is not synchronized to your clock, and if you use it multiple times, it may be seen by different parts of your design as having a different value, when it is transitioning for 0 to 1 or vice versa. Mull on that for a bit, because it will be crucial to understand this as your designs become more complex, and you will be doing more interfacing with external devices or even with multiple independent clock domains inside your own design.

Of course the "design rules" above have exceptions, but they are a very useful baseline.

Another deeply central idea is to understand the difference between "variables" and "signals", and specifically the difference between what an assignment to a variable means, vs what assignment to a signal means. At least in VHDL this can be super confusing at first! I don't know Verilog but I presume the same is true there.

The RX side of the UART will be a bit more complex than the TX side. You will detect the falling edge of the START bit, then wait 1.5 baud periods, and start sampling the RX line at 1 baud period intervals for data bits.

I suggest you develop the RX-side in isolation from the TX-side, and show successful reception of a data byte e.g. on the board's LEDs.

Once it works, and provided your TX and RX sides have a somewhat nice interface, tying them together should not be hard. And that will give you a proper loopback.

Good luck! Don't hesitate to ask if there's issues. (But note that I can only read VHDL, not Verilog).

Edited by reddish
Link to comment
Share on other sites

I think that @reddishcovered the basics to get you started pretty well.

You can find Verilog and VHDL uart implementations to get a fast start. But definitely do consider doing your own design. A UART is a good project form someone with some HDL design skills. It's also a great general purpose interface to have in your HDL toolbox. Make sure that you write a testbench to verify operation before trying it out in hardware.

Keep in mind that, generally a UART is used for transferring 7-bit ascii data. But it's possible to transfer 8-bit binary if your OS doesn't think that it's a COM/TTY device. There are some not so obvious glitches you can run into doing binary mode UART communications. Also, a USB UART is a USB device on one end though it may look like a UART on the other side.

UART stands for Universal Asynchronous Receiver Transmitter. The basic unit is the baud period. This is important in terms of how you want to implement your UART. Historically, UARTs needed to accomodate a wide (+/- 15%) baud period variations between DCE and DTE ends because the reference clock that generated baud frequencies  could vary considerably from DTE toi DCE ends. For UART baud rates up to 921600 on a modern USB UART you can dispense with flow control or worrying about baud frequency variations. But I prefer to work with UART IP that can tolerate a wide baud period variation between ends. Some people prefer a simpler approach by implementing an USART, which relies on close matching of baud frequencies. At 8 Mbaud and above this gets to be problematic though. It doesn't hurt to pretend that it's the 1980's and conceptualize the UART for what it once was as a matter of educational edification. UARTs are nice low speed interfaces. They only need 1 clock domain. They are relatively simple to understand and use. You need 2 FPGA pins to use them; 4 pins for high baud rate connections transferring lots of data.

At one point or another I has UART in all of my designs, either for debugging purposes or as a user interface to control and see the output of a design. Love the UART....

Once you get comfortable with asynchronous concepts and understand how the UART works, you can create some pretty interesting board to board interfaces. https://forum.digilent.com/topic/20479-inter-board-data-transfer-project/


Edited by zygot
Link to comment
Share on other sites

Thank you @reddish and @zygot

I have gotten started with this UART project: https://github.com/projf/projf-explore/tree/main/lib/uart which I can confirm does something on my Arty board. As to whether UART is actually working correctly, I do not know, but here is what I observe:

I am sending data to the USB descriptor (on which arty board is connected) via:

echo "AAAA" > /dev/ttyUSB3

In the other terminal I am running a `minicom` set up with 9600 baud rate with 8N1 configuration and get the following output (when the above echo command is ran):


At this point I am not certain why I observe that half the input is being echoed back as my expectation was I would see all of it echoed back. I will continue playing with this project and may be I can figure this out :)

Link to comment
Share on other sites

One way to track down such curiosities is to create an ILA and use the Vivado Hardware Manager to see what's getting into and out of your UART.

One problem that you might run into is that Vivado Hardware Manager keep pinging the JTAG connection at a pretty high rate and this can cause USB device disconnects and Vivado will go haywire. I've recently run into this while using an ILA and doing DPTI USB transfers on the Nexys Video. I've had issues with CMODs and Vivado Hardware Manager but this was a new experience.

I typically use Putty to observe UART communications. You have to play with the terminal settings for your setup. Is you FPGA application echoing characters or lines?
Link to comment
Share on other sites

On 11/27/2022 at 9:31 PM, zygot said:

I typically use Putty to observe UART communications. You have to play with the terminal settings for your setup. Is you FPGA application echoing characters or lines?

I have set minicom (a unix serial comms utility) to wrap lines on the receiving end. So what I get echo'd back is half the characters that I transmit.

As to your other suggestion, I will see what I can do with JTAG.

Link to comment
Share on other sites

The ILA is one way to see what your FPGA design is actually doing. The correct, and by far best, way to verify a logic design is to write a testbench and do a simulation. I suspect that this might be most informative. People just beginning to learn logic design tend to want to see hardware do stuff and not learn new skills. Simulation should be thought of as a (necessary) step in the design process regardless of design complexity or skill level. If you need help understanding simulation you know where to ask.

BTW, your post belongs in a different section of the Digilent Forum... perhaps in the FPGA section....
Link to comment
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
  • Create New...