fm4dd / gatemate-riscv

RISCV CPU implementation tutorial steps for Cologne Chip Gatemate E1, adopted from https://github.com/BrunoLevy/learn-fpga
BSD 3-Clause "New" or "Revised" License
11 stars 2 forks source link

step-17 and above - UART speed differs from Verilog encoded baudrate #3

Open fm4dd opened 1 year ago

fm4dd commented 1 year ago

The target UART speed is configured inside the SOC module as 1.000.000 baud. However the real output rate on the UART USB adapter is well below the target value. This is the baud rate setting in SOC.v:

   corescore_emitter_uart #(
      .clk_freq_hz(`CPU_FREQ*1000000),
      .baud_rate(1000000)                           
   ) UART(
      .i_clk(clk),
      .i_rst(!resetn),
      .i_data(mem_wdata[7:0]),  
      .i_valid(uart_valid),
      .o_ready(uart_ready),
      .o_uart_tx(TXD)                                
   );

On the output, Sigrok PulseView measured a baudrate of 833.333 instead:

I am using Digilent's PMOD-USBUART plugged into port PMOD-B, and connected a protocol analyzer like this:

The UART speed, that is supposed to stay fixed at 1Mbaud, changes along with changing the FPGA CPU frequency setting CPU_FREQ. I recorded the following values:

Verilog corescore_emitter_uart() baud_rate setting 1000000 (original):

CPU_FREQ measured baud_rate
5 MHz n/a (program fails execution)
10 MHz 833.333
20 MHz 909.090
30 MHz 952.380
40 MHz n/a (program fails execution)
Trying to raise the Verilog corescore_emitter_uart() baud_rate setting to 1100000: CPU_FREQ measured baud_rate
5 MHz n/a (program fails execution)
10 MHz 909.090
20 MHz 1.000.000
30 MHz 1.052.631
40 MHz n/a (program fails execution)
fm4dd commented 1 year ago

A check of the same code on a Lattice IceBreaker FPGA board shows very similar timing deviations:

CPU_FREQ measured baud_rate
16 MHz n/a (program fails execution)
20 MHz 909.090
30 MHz 952.380
40 MHz 952.380
50 MHz n/a (program fails execution)

It seems to be caused by design.

Further attempts on Gatemate perfomance optimizations under yosys synthesis (-retime and -luttree) or place and route (timing mode -tm 1 or 2) brought only marginal changes, if any.

Interim conclusion is to try these bitrates for serial communication: 833.333, 909.090, 952.380, 1.000.000

If the serial synchronization mismatch is not far off, the terminal already shows garbled character strings such as this: ��o�į������o�l����p�O�����

From observation, the serial protocol can withstand the bitrate to be "off" by a few percent, giving a (small) window of operation. A good Google search string for it is "baud rate deviation tolerance"

Elektronikus commented 2 hours ago

I think, in the emitter_uart.v is an error localparam START_VALUE = clk_freq_hz/baud_rate; localparam WIDTH = $clog2(START_VALUE); should be: localparam START_VALUE = (clk_freq_hz/baud_rate) - 2; localparam WIDTH = $clog2(START_VALUE+2); Than the terminal works with 1000000