Jump to content
  • 0

Arty A7 100 UART echo example [repost]


silantyeved

Question

15 answers to this question

Recommended Posts

  • 0

I want to know if anyone on this forum has ever managed to implement a UART echo application and managed to use tools available in a Unix OS to send and receive serial data (e.g. `minicom`, `echo`). My specific board is Arty a7 100T, but from what I understand the interface is universal (it is in the name) so other board owners input is welcome. 

Link to comment
Share on other sites

  • 0
2 hours ago, silantyeved said:

I want to know if anyone on this forum has ever managed to implement a UART echo application and managed to use tools available in a Unix OS to send and receive serial data

Sure.

Perhaps a UART echo project isn't where you want to start.

You could look at this project: https://forum.digilent.com/topic/4348-a-uart-based-debugger-tool/

This is a transmit only example but might help you resolve any OS related issues that might be getting in the way. It has a testbench example to help you with simulation.

It's not clear what the problems are that you've encountered from suggestions to the earlier post. Reducing the number of things that can cause a failure is always a good way to proceed when you aren't having success. You should be able to figure out a way to use the UART_DEBUGGER.vhd from the testbench, but I've posted other code that uses it if you are having a hard time doing so.

A common problem that people have using UARTs is figuring out whether it's the FPGA or the USB UART that's driving TxD and RxD. Some USB UARTs require the CTSn be asserted correctly, but the ones on Digilent's boards do not.

Edited by zygot
Link to comment
Share on other sites

  • 0

Hi @silantyeved

A few concrete steps to help you in debugging:

(1) Are you capable to get an LED to blink for a well-defined time on the Arty board (say, at 1 Hz, so 1 cycle per second)? If not, first you have to make sure you can do that; the UART stuff is a step up in complexity from that. If you can't get this to work, let us know.

(2) Then, change your HDL to increase the frequency to 4800 Hz. if you have one, verify on an oscilloscope that you see a nice square wave at 4800 Hz, on some output FPGA pin. If not, report back.

(3) Connect the 4800 Hz to the TX side of the UART.

Concretely, if your serial output signal is called UART_OUT, this means you should have something like this in your constraints:
 

set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { UART_OUT }];


Since on the Arty A7 board, the D10 pin of the FPGA chip is connected to the TX pin of the serial-to-USB chip.

(4) If you run that program, you are now outputting a valid 9600 baud datastream to the serial-to-USB chip, and it will dutifully transfer that to the PC, if the PC opens the device for reading.

On your PC side, start minicom or another terminal program at 9600 baud, 8 databits, no parity, and 1 stop-bit.

You should see a continuous stream of "U" characters coming in (ASCII code 0x55, binary "01010101"). This works because the start bit, data bits, and stop bit at 9600 baud form a nice and continuous 4800 Hz square wave.

If not, you may be looking at the wrong TTY device, or you may have no permissions, or there can be some more possble but less likely causes.


If you want us to be able to help you, try these steps and report back where you get stuck. I have gotten serial communication to work on about 10 different FPGA boards (including the Arty) so I'm sure we can pinpoint the problem; but you need to provide concrete information on what you tried and what you saw. Just saying "I am stuck" doesn't provide enough information on my side to be able to figure out what is going wrong on your side.

Link to comment
Share on other sites

  • 0
Did you look over the VHDL in the reference project in the link that I provided in my last post?

It has everything that you should need to at least see data flow between your OS and the FPGA ( OK, you will actually have to write a simple entity to use the IP ). The testbench has a full duplex UART. The first step in programmable logic development is to verify that your logic is at least correct on the behavioral and RTL level; and that is done in simulation. Vivado has the ability to do simulation. If you can't get even a basic simulation to work then trying to get a design to work on hardware will be very difficult. If it works in simulation, then you can at least simplify the debugging process that allows you to do what you want to do.

Does this code in the UartDebuggerproject make any sense to you? Were you able to run a simulation in Vivado and look at the component signals?

Unless you are trying to complete a course assignment there's no embarrassment asking questions. But as reddish pointed out, it's hard to help when you don't have enough information to work with. Edited by zygot
Link to comment
Share on other sites

  • 0

@reddish thanks a lot.

I was able to get a continuous stream of "U"s out in minicom by using 10417 as a count param to switch LEDs (and then UART pin) on and off:

image.thumb.png.87ebd208367b357cb6ea81fc01321107.png

I suppose that confirms that:

1. UART output pin on an FPGA is working as expected

2. Minicom is set up correctly

I will appreciate any further guidance you may give me to get the echo working.

Ed  

Link to comment
Share on other sites

  • 0

Hi @silantyeved

Indeed this confirms that a lot in your design is working, and that there are no issues with USB traffic or permissions in linux, etc.

I kindly invite you to re-read my previous message, because it lists the obvious next steps:

 


One important thing when doing FPGA designs is that you really need to chop stuff up in small steps (and or modules), and you need to build confidence at each step that everything is working as expected. This is a good idea already for "normal" programming, but it is an order of magnitude more important in FPGA work because debugging a complicated HDL design is so much harder. You want to avoid debugging as much as possible.

So the chopping-up of your "loopback" end-goal from where you are now consists of (a) implementing a state machine that is capable of transmitting something other than 0x55; (b) making sure this state-machine has a nice interface; (c) forget the "TX" side for the time being and implement a serial receiver that is capable of recognizing the start bit falling edge and gets the timing right to sample the incoming data bits smack in the middle of their baud periods, showing the end result on the Arty's LEDs once it's done; (d) make sure the receiver has a proper interface and then finally (e) tie together the TX and RX sides to make a loopback.

Five steps, each could take hours or days if you haven't done this before, and that's fine. You will learn a lot in the process. FPGA programming is quite hard, I'm afraid.

If you don't like hard work, you can find plenty of UART implementations by googling -- some of them are even well done, although you won't be able to judge which ones until you get the necessary experience. But really, I thoroughly recommend doing it yourself, as it is a perfect opportunity to make a lot of mistakes in a relatively small design, and the experience will teach you a lot of things that will come in handy later when you want to do more advanced designs.

Edited by reddish
Link to comment
Share on other sites

  • 0

Thanks for your guidance @reddish. My current state of affairs is as follows. I have switched focus to RX side of UART with goal of outputting first (or last?) 4 bits of an ASCII character via Arty's LEDs. While, I am observing some action on the LEDs, it is definitely not consistent with binary representations of characters I am sending to USB file descriptor via UNIX shell. Exact symptoms are as follows:

When I do:

echo "A" > /dev/ttyUSB1

I get the following output on the LEDs (PFA). In fact this output presents itself for any character I try to send. My prime suspect is timing. I am not certain that I have gotten the counter correct, because fiddling with it can lead to different outputs on LEDs, though by no means does it lead to expected output on LEDs. For inspiration I have used Verilog code from https://nandland.com/project-7-uart-part-1-receive-data-from-computer/. Here is the code that I am programming Arty with: 

`timescale 1ns / 1ps

module top(
  input        clock,
  input        sw1,
  input        sw2,
  output[0:3]  led,
  output[0:3]  led_g,
  input        uart_rx, 
  output       uart_tx 
);

 // UART BAUD
 // (100,000,000 (CLK) / 9600 (BAUD)) =  10417
 parameter CLKS_PER_BIT    = 10417;
 reg [31:0] reg_clks_cnt = 0;

 // RX
 localparam IDLE         = 3'b000;
 localparam RX_START_BIT = 3'b001;
 localparam RX_DATA_BITS = 3'b010;
 localparam RX_STOP_BIT  = 3'b011;
 localparam CLEANUP      = 3'b101;

 reg [3:0] rx_state;
 reg [7:0] rx_byte;
 reg [2:0] rx_byte_idx;
 reg [7:0] led_reg;
 reg [3:0] debug_reg;

 always @(posedge clock)
 begin
     case(rx_state)
     IDLE:
     begin
        reg_clks_cnt <= 0;
        rx_byte_idx  <= 0;
        if (uart_rx == 1'b0) // start bit
        begin
            rx_state       <= RX_START_BIT;
            debug_reg            <= 4'b1111;
        end
        else
        begin
            rx_state       <= IDLE;
        end     
     end
     RX_START_BIT:
     begin
        if (reg_clks_cnt == (CLKS_PER_BIT - 1) / 2)
        begin
            if (uart_rx == 1'b0) // check start bit still low at the middle of BAUD period
            begin
                reg_clks_cnt <= 0;
                rx_state     <= RX_DATA_BITS;                 
            end
            else
            begin
                rx_state     <= IDLE;
            end          
        end
        else
        begin
            // still sampling for the middle of start bit
            reg_clks_cnt <= reg_clks_cnt + 1;
            rx_state     <= RX_START_BIT;
        end     
     end
     RX_DATA_BITS:
     begin
        if (reg_clks_cnt < CLKS_PER_BIT - 1)
        begin
            reg_clks_cnt <= reg_clks_cnt + 1;
            rx_state     <= RX_DATA_BITS;
        end
        else
        begin
            reg_clks_cnt         <= 0;
            rx_byte[rx_byte_idx] <= uart_rx;
            
            if (rx_byte_idx < 7)
            begin
                rx_byte_idx <= rx_byte_idx + 1;
                rx_state     <= RX_DATA_BITS; 
            end
            else
            begin
                rx_byte_idx <= 0;
                rx_state    <= RX_STOP_BIT; 
            end
        end 
     end
     RX_STOP_BIT:
     begin
        if (reg_clks_cnt < CLKS_PER_BIT - 1)
        begin
            reg_clks_cnt <= reg_clks_cnt + 1;
            rx_state     <= RX_STOP_BIT;
        end
        else
        begin
            reg_clks_cnt <= 0;
            rx_state     <= CLEANUP;
        end      
     end
     CLEANUP:
     begin
        rx_state <= IDLE;
     end
     default:
     begin
        rx_state <= IDLE;
     end
     endcase
  end
 
  always @ (posedge clock)
  begin
    if (sw1) begin
        led_reg <= debug_reg;
    end
    else begin
        led_reg <= rx_byte;
    end
  end 
  
  assign led = led_reg;

endmodule

Any suggestions as to how I can debug this further?

20221209_173616.jpg

Link to comment
Share on other sites

  • 0

That was it, @reddish! Tested with A-G and so far I can see the last 4 bits of each letter being displayed by LEDs as expected. I will test a bit more with the current design and then will do the same but pointing `led_reg` at the first 4 bits instead; or even better, switching between first and last 4 bits using a switch.

After, I will get to the next portion of you initial suggestion and clean up the RX module interface and then start tying in TX part of the UART.

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...