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. Day 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
);
// Character ROM: 5 characters (H, E, L, L, O), repeated forever
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 character per ~0.5 s so you can watch in terminal
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
r_send every 0.5s; the UART TX latches the current character and transmits; the index advances to the next character. Entire composition: ~25 lines of new code, using your UART as a ready-to-use building block.
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 labs/week3_day11/ex4_hello/
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 — most students will remember this moment of their 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 Day 11
Day 12 · UART RX · SPI · IP Integration · Week 3 Capstone
▸ WHY THIS MATTERS NEXT
You transmit. Day 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.