Video 4 of 4 · ~8 minutes
Dr. Mike Borowczak · Electrical & Computer Engineering · CECS · UCF
Every FPGA dev board has a USB-UART bridge chip (FT232H, CP2102, CH340G) that translates USB to 3.3V UART. The Go Board uses an FT2232H. Your laptop sees it as /dev/ttyUSB0 (Linux), /dev/cu.usbserial-XYZ (macOS), or COM3 (Windows). Python's pyserial, screen, minicom, and PuTTY all speak to it. This standard pipeline is how every FPGA/MCU developer moves data between chip and laptop.
Today's setup is your lifeline. Your capstone will print debug info over UART, read configuration over UART, or stream sensor data over UART. Topic 12 RX lets you receive bytes FROM the PC. By the end of the week, you have full bidirectional communication.
“UART is UART. Connect my FPGA's TX to any UART RX and it works.”
Modern 3.3V UART (FPGA/MCU) uses positive logic: idle=3.3V (HIGH), start=0V (LOW). True RS-232 (9-pin connectors from the PC era) uses inverted bipolar levels: idle=-12V, active=+12V. Connecting 3.3V UART directly to an RS-232 port can damage the FPGA. Go Board's on-board USB-UART bridge handles conversion to 3.3V; external RS-232 devices need a MAX3232 level-shifter.
iCE40 HX1K FT2232H USB-UART Host (Laptop)
┌────────────┐ ┌────────────────┐ ┌──────────────┐
│ │ │ │ │ │
│ UART TX │──TX──────│ RX chip USB│─────────│ /dev/ttyUSB0 │
│ (your RTL)│ │ │ │ pyserial │
│ │──RX──────│ TX (D+)(D−) │ minicom │
│ │ │ │ │ │
│ GND │──────────│ GND VBUS── │ (5V USB power)│
└────────────┘ └────────────────┘ └──────────────┘
3.3V TTL 115200 baud
screen /dev/ttyUSB0 115200 opens it; screen -X quit closes it (or Ctrl-A K).
module hello_tx (
input wire i_clk, i_btn, output wire o_tx
);
// 5 chars (H, E, L, L, O), looped
reg [7:0] rom [0:4];
initial begin
rom[0] = 8'h48; rom[1] = 8'h45; rom[2] = 8'h4C;
rom[3] = 8'h4C; rom[4] = 8'h4F;
end
// Slow timer — one char per 0.5 s
reg [23:0] r_timer;
reg [2:0] r_idx;
reg r_send;
always @(posedge i_clk) begin
r_send <= 1'b0;
r_timer <= r_timer + 1;
if (r_timer == 24'd12_500_000) begin
r_timer <= 0;
r_send <= 1'b1;
r_idx <= (r_idx == 3'd4) ? 3'd0 : r_idx + 1'b1;
end
end
uart_tx #(.CLKS_PER_BIT(217)) u_tx (
.i_clk(i_clk), .i_reset(1'b0),
.i_valid(r_send), .i_data(rom[r_idx]),
.o_busy(), .o_tx(o_tx)
);
endmodule
You flash the board. Terminal shows: æ²■µÌ instead of HELLO.
CLKS_PER_BIT doesn't match screen's rate. Check:
CLKS_PER_BIT = 217 ← assumes 25 MHz / 115200screen /dev/ttyUSB0 115200 (not 9600)~5 minutes — end-to-end
▸ COMMANDS
cd lecture_examples/week3_day11/d11_s4_ex2/
make prog
# in another terminal:
screen /dev/ttyUSB0 115200
# (Ctrl-A K to quit)
# Or via Python:
python3 rx_display.py
▸ EXPECTED TERMINAL
HELLOHELLOHELLOHELLO
HELLOHELLOHELLOHELLO
HELLOHELLOHELLOHELLO
HELLOHELLO...
▸ THE MOMENT
Character-by-character HELLO streams into your terminal. Your Verilog is driving a real signal into your laptop. Take a moment — you'll likely remember this moment of your FPGA career.
Ask AI: “My UART TX is outputting garbage on the terminal. What are the top five causes and how do I diagnose each?”
TASK
AI diagnoses a UART bring-up bug.
BEFORE
Predict: baud mismatch, CLKS_PER_BIT off-by-one, bit order (LSB/MSB), inverted idle, wrong parity.
AFTER
Strong AI gives concrete diagnostic steps (scope the line, check idle level). Weak AI just lists causes without diagnostics.
TAKEAWAY
A good AI debugging session produces an ordered diagnostic sequence, not just a list of possibilities.
Q1: At 25 MHz clock and 115200 baud, what's CLKS_PER_BIT (rounded)?
25_000_000 / 115_200 = 217.01. Round to 217. Actual baud: 25e6/217 = 115207.4 — 0.006% error, well within tolerance.Q2: Why do we need a USB-UART bridge chip between the FPGA and laptop?
Q3: You see random characters in your terminal. What do you check first?
Q4: Why transmit at 0.5 s intervals instead of full baud rate?
🔗 End of Topic 11
Topic 12 · UART RX · SPI · IP Integration · Week 3 Capstone
▸ WHY THIS MATTERS NEXT
You transmit. Topic 12 is receiving — harder than transmitting, because you don't control the timing. You'll learn 16× oversampling (the standard UART RX trick), start-bit detection, and then round out Week 3 with SPI (a different serial protocol) and a full IP-integration methodology. By Friday: bidirectional UART + SPI = you can talk to any peripheral in the embedded world.