Logic Analyzer Tutorial: Decode UART, I2C and SPI in PulseView
USB logic analyzer tutorial: install PulseView, then decode an Arduino's UART, a sensor's I2C and an SPI flash chip. Plus: cheap clone or Saleae?
A USB logic analyzer is a small box that records the high or low state of several wires at once and displays them on your computer. With the free PulseView software, it turns those signals into readable bytes: a serial port's text, a sensor's registers, a flash chip's commands. An 8-channel model at around €20 is enough to learn with, as long as you set the sample rate correctly.
This tutorial installs PulseView on Windows, Linux or macOS. It then walks through three reproducible exercises on hardware you own: an Arduino, an I2C sensor and an SPI flash chip.
Logic analyzer vs oscilloscope
Both instruments plot signals over time, but they answer different questions.
| Logic analyzer | Oscilloscope | |
|---|---|---|
| What it measures | High or low (0/1) | The actual voltage, continuously |
| Channels | 8, 16 or more | Usually 2 or 4 |
| Capture length | Long (seconds, even minutes) | Short |
| Protocol decoding | Built in (UART, I2C, SPI, CAN…) | Depends on model, often an option |
| Typical question | "What are these chips saying to each other?" | "Is this signal clean?" |
| Entry price | ≈ €20 | ≈ €300 and up |
To read what travels on a serial bus, the logic analyzer is the right tool. An oscilloscope becomes essential when you suspect an electrical problem, such as slow edges, noise or wrong voltage levels.
The one principle to remember: a logic analyzer samples. It checks each wire at regular intervals. Sample at least 4 times, ideally 10 times, faster than the fastest signal. Otherwise edges slip between samples and decoding fails.
Installing PulseView/sigrok (fx2lafw drivers)
sigrok is an open-source suite of tools for test instruments, and PulseView is its graphical interface. Most cheap 8-channel analyzers are built around a Cypress FX2 chip. sigrok drives them with fx2lafw, an open-source firmware loaded into the device each time you plug it in, so nothing is flashed permanently. These modules are rated at 8 channels and up to 24 MHz. Real throughput depends on how many channels are active and on your USB port.
Windows
- Download the PulseView installer from the sigrok downloads page. The project recommends the nightly builds, which are more up to date than the last stable release (0.4.2).
- Plug in the analyzer.
- Run Zadig, which ships with the installer and is in the Start menu.
- Select the analyzer in the list. Depending on the model and firmware state, it may show a generic name or "fx2lafw". Choose the WinUSB driver and install it. If the list is empty, tick Options → List All Devices and select only the analyzer.
- If PulseView still can't find the device, repeat the Zadig step. The sigrok documentation notes that some devices change USB identity once the firmware is loaded, so they need the driver assigned twice.
Linux
Distribution packages work fine:
sudo apt install pulseview sigrok-cli sigrok-firmware-fx2lafw
sigrok-cli --scan
sigrok-cli --scan should list an fx2lafw device. If it doesn't, unplug and replug the analyzer so the USB access rules (udev) apply. Otherwise see sigrok's Linux page. If your distribution's packages are too old, the project also provides PulseView as an AppImage.
macOS
Download the nightly disk image from the downloads page. It is built for Intel processors, so on an Apple Silicon Mac it runs through Rosetta 2. There is no driver to install. Existing Homebrew recipes are not maintained by the project, which recommends its own binaries.
First launch
In PulseView, open the device list, choose fx2lafw, then Scan for devices. The analyzer appears with channels D0 to D7. Set the number of samples and the sample rate in the toolbar, then click Run.
Always connect the analyzer's ground (GND) to the circuit's ground before the signal channels. Without a common ground, the readings mean nothing.
Exercise 1: decode an Arduino's UART
UART is the simplest serial port: one wire per direction and no clock. Both sides agree on a baud rate in advance. It is also the first thing to look for on a device you open up, as our guide What is UART? Find a device's serial port explains.
Wiring (Arduino Uno or Nano):
| Analyzer | Arduino |
|---|---|
| GND | GND |
| D0 | Pin 1 (TX) |
Sketch:
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println("Hello PulseView");
delay(500);
}
Capture:
- Sample rate: 1 MHz, well over 10 times 9600 baud. Samples: 1 M, which gives one second.
- Click Run. Bursts of pulses appear on D0 every 500 ms.
- Add the decoder: click Add protocol decoder and type
UART. Set TX to D0, Baud rate to 9600 and the format to 8N1 (8 data bits, no parity, 1 stop bit). Set the data format to ascii.
"Hello PulseView" appears above the waveform, one character at a time.
Going further: change the sketch to Serial.begin(115200), leave the decoder at 9600, and watch the garbage characters appear. That is exactly what you see on an unknown device when you don't know its speed. Then measure the shortest bit with PulseView's cursors: 1 divided by that duration gives you the baud rate.
Exercise 2: I2C from a sensor
I2C connects a microcontroller to several chips over two wires: SCL (clock) and SDA (data). Each chip has an address. We use a BME280 sensor (temperature, humidity, pressure), common on breakout boards costing a few euros. Check that your module accepts 5 V. Many have a regulator, but not all; if yours doesn't, use a 3.3 V board.
Wiring:
| Analyzer | Arduino Uno | BME280 |
|---|---|---|
| GND | GND | GND |
| D1 | A5 (SCL) | SCL |
| D2 | A4 (SDA) | SDA |
Power the sensor from VIN/VCC as your module requires.
The sketch reads the chip-ID register at address 0xD0. According to Bosch's datasheet, on a BME280 it always holds 0x60.
#include <Wire.h>
const uint8_t ADDR = 0x76; // 0x77 on some modules
void setup() {
Serial.begin(9600);
Wire.begin();
}
void loop() {
Wire.beginTransmission(ADDR);
Wire.write(0xD0); // "chip id" register
Wire.endTransmission();
Wire.requestFrom(ADDR, (uint8_t)1);
if (Wire.available()) {
Serial.println(Wire.read(), HEX); // expected: 60
}
delay(1000);
}
Capture:
- Sample rate: 2 MHz or more. The Arduino's I2C runs at 100 kHz by default.
- Trigger: falling edge on D2 (SDA), to start capturing at the beginning of a transaction.
- Add the I²C decoder: SCL on D1, SDA on D2.
You can read the conversation in plain terms: Start, Address write: 76, Data write: D0, Start repeat or Stop, Address read: 76, Data read: 60, Stop.
If nothing answers (a NACK after the address), try address 0x77. And if your sensor returns 0x58, it is a BMP280, its cousin without humidity sensing. Sellers mix the two up often.
Exercise 3: SPI from a flash chip
SPI is faster than I2C and uses four wires: CS (chip select), SCK (clock), MOSI (controller to peripheral) and MISO (peripheral to controller). It is how most connected devices talk to the flash chip that holds their firmware. Watching it is the first step before ever reading that chip's contents.
Mind the voltage: common SPI flash chips such as Winbond's W25Qxx run at 3.3 V. Don't wire them straight to an Arduino Uno's 5 V pins. Use a 3.3 V board, such as one based on an ESP32 or RP2040, or a level shifter.
Wiring (adjust the SPI pin numbers to your board):
| Analyzer | SPI signal |
|---|---|
| GND | GND |
| D3 | CS |
| D4 | SCK |
| D5 | MOSI |
| D6 | MISO |
The sketch sends the standard 0x9F (JEDEC ID) command and reads three bytes: manufacturer, memory type and capacity.
#include <SPI.h>
const int CS_PIN = 5; // adjust for your board
void setup() {
Serial.begin(115200);
pinMode(CS_PIN, OUTPUT);
digitalWrite(CS_PIN, HIGH);
SPI.begin();
}
void loop() {
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
digitalWrite(CS_PIN, LOW);
SPI.transfer(0x9F);
uint8_t m = SPI.transfer(0);
uint8_t t = SPI.transfer(0);
uint8_t c = SPI.transfer(0);
digitalWrite(CS_PIN, HIGH);
SPI.endTransaction();
Serial.printf("%02X %02X %02X\n", m, t, c);
delay(1000);
}
Serial.printf exists on ESP32 and RP2040 boards. On other boards, replace it with three Serial.print(…, HEX) calls.
Capture:
- The SPI clock is 1 MHz, so sample at 8 MHz or more. If the analyzer drops data, disable unused channels (D0–D2, D7) to reduce USB load.
- Trigger: falling edge on D3 (CS).
- Add the SPI decoder (CS = D3, CLK = D4, MOSI = D5, MISO = D6, mode 0), then stack the SPI flash decoder on top.
PulseView shows Read JEDEC ID followed by the three bytes. On a Winbond chip the first is EF, the manufacturer ID. Check the other two against your chip's datasheet to find its capacity.
It is the same habit, observe before you act, that you later apply to the memory of a device you own and are studying.
8-channel clone vs Saleae: which to buy?
| 8-channel clone (fx2lafw) | Saleae Logic 8 | |
|---|---|---|
| Price | ≈ €10–25 | $499 (checked October 2026) |
| Digital sample rate | Up to 24 MHz claimed, less in practice on 8 channels | 100 MS/s |
| Analogue inputs | No | Yes (10 MS/s) |
| Software | PulseView / sigrok (open source) | Logic 2 (Saleae), very polished |
| Input protection | Varies by manufacturer | Documented |
| Decoders | 100+ in sigrok | Many, plus extensions |
Our take:
- For learning, hardware CTFs and most everyday devices, a clone is plenty. Slow UART, I2C and SPI make up most of what you'll meet at first.
- A Saleae earns its price if you debug hardware professionally: fast buses, analogue signals, more comfortable software, reliability. Saleae also offers discounts for students, educators and hobbyists, according to its discounts page.
- What not to do: run a clone with Saleae's software. Logic 2 only supports Saleae hardware, and PulseView does the job legally and for free.
Our 8-channel logic analyzer, at €19.90, is a module of this kind and works with sigrok and PulseView. It will be back in the shop soon: join the waitlist to be notified. To practise these skills on a challenge designed for it, with nothing to solder, our Firmware Dump puzzle, planned for 2028, is on a waitlist. The rest of our hardware is in the shop.
Frequently asked questions
Is a €20 logic analyzer good enough to start?
Yes, for slow to moderate UART, I2C and SPI, which covers most of what you'll learn and many everyday boards. Its limits show on fast buses above a few megahertz and on analogue signals.
What sample rate should I use?
At least 4 times, ideally 10 times, the frequency of the fastest signal. For example 1 MHz for 115,200 baud UART, 2 to 4 MHz for 400 kHz I2C, and 8 MHz or more for 1 MHz SPI.
Can I connect the analyzer to a 5 V board?
Many 8-channel modules accept both 3.3 V and 5 V logic, but check your model's datasheet. Never exceed the stated voltage, and always connect the analyzer's ground to the circuit's ground.
Does Saleae's Logic 2 software work with a clone?
No. Use PulseView and sigrok, which are free and open source and support these modules through the fx2lafw firmware.