Understanding the UART Glitch Issue on iCE40 FPGAs

When learning FPGA development with Verilog, implementing a UART (Universal Asynchronous Receiver-Transmitter) is a classic milestone. However, seeing unexpected positive glitches on your transmitter (TX) output pin during low states on an oscilloscope can be incredibly frustrating. This issue often occurs on boards like the Lattice iCEstick (iCE40HX1K) or the devantech iceFUN (iCE40-HX8K).

If your scope shows regular positive spikes exactly on bit transitions, the problem is rarely a faulty FPGA. Instead, it usually boils down to three common culprits: pin contention, measurement artifacts (scope probing), or a subtle Verilog syntax bug. Let's walk through how to diagnose and fix each of them.


1. The Hardware Culprit: Pin Contention on the iCEstick

The most common cause of "high impedance-like" glitches on the iCEstick is pin contention. On the Lattice iCEstick, the physical UART pins are shared with the FTDI chip (which handles USB-to-serial communication with your PC):

  • FPGA TX (Output) must connect to the FTDI RX pin (Pin 8).
  • FPGA RX (Input) must connect to the FTDI TX pin (Pin 9).

If you accidentally swap these pins in your Physical Constraints File (.pcf), your FPGA's o_tx pin will drive Pin 9. Since the FTDI's TX pin is also actively driving Pin 9 high during idle states, the two outputs will "fight" each other. When your FPGA tries to pull the line low, the FTDI chip pulls it high, resulting in severe voltage sagging, slow transition states, and transient glitches on bit transitions.

The Fix:

Double-check your .pcf constraints file. Ensure your UART pins are mapped correctly:

# Correct Pin Mapping for Lattice iCEstick
set_io o_tx 8
set_io i_rx 9

2. The Measurement Culprit: Scope Ground Loops

If your pin assignments are correct but you still see sharp spikes on your oscilloscope, you might be looking at a measurement artifact rather than an actual digital glitch.

Standard oscilloscope probes come with a long ground lead (the "alligator clip"). This long wire acts as an inductor, forming a loop antenna. When other pins on the FPGA (or internal high-speed clocks) transition, the rapid return currents induce transient voltage spikes across this ground loop. This makes perfectly clean digital signals look noisy and glitched on the screen.

The Fix:

To rule out probing noise, use the "tip and barrel" method or a ground spring instead of the long ground clip. Keep the ground connection as short as possible (ideally under 1 cm) directly to a ground header pin next to your signal pin.


3. The Software Culprit: Verilog Syntax Bug

Looking closely at the provided Verilog code, there is a dangerous syntax bug in the IDLE_STATE block. In Verilog, if you do not use begin and end blocks after an else statement, only the immediate next statement is considered part of that block.

Let's look at your original code:

IDLE_STATE :
    begin
        o_tx    <= 1;
        o_done  <= 0;
        counter <= 0;
        bit_index <= 0;
    
        if (i_data_avail == 1)
            begin
                o_active  <= 1;
                data_byte <= i_data_byte;
                state <= START_STATE;
            end
        else
            state <= IDLE_STATE;
            o_active  <= 0; // OOPS! This is outside the else block!
    end

Because of the missing begin and end around the else branch, the line o_active <= 0; is executed unconditionally every time the state machine is in IDLE_STATE. If i_data_avail is high, the simulator/synthesizer will try to assign o_active <= 1 and o_active <= 0 simultaneously in the same clock cycle. This can cause erratic behavior depending on how your synthesis tool (like Yosys or iCEcube2) resolves the conflict.

The Corrected Verilog Code:

Wrap the else statements in a proper begin ... end block to keep your state machine clean and predictable:

IDLE_STATE :
    begin
        o_tx    <= 1;
        o_done  <= 0;
        counter <= 0;
        bit_index <= 0;
    
        if (i_data_avail == 1)
            begin
                o_active  <= 1;
                data_byte <= i_data_byte;
                state     <= START_STATE;
            end
        else
            begin
                state    <= IDLE_STATE;
                o_active <= 0;
            end
    end

Summary Checklist

If you encounter glitches on your UART output, run through this quick checklist:

  • Check the PCF file: Verify that your FPGA transmitter output is routed to pin 8 (FTDI RX) and not pin 9.
  • Improve your scope probing: Swap your long ground clip for a short ground spring to eliminate ground bounce artifacts.
  • Audit your Verilog blocks: Ensure all multi-line conditional branches are explicitly wrapped in begin ... end blocks.