Skip to content

Decoding I2C and UART

By the end of this lesson you will:

  1. Set up the I2C decoder, and read the address, read/write bit and ACK from a bus scan
  2. Set up the UART decoder at the correct baud rate, and describe the symptoms of setting it wrong
  • You can already connect a logic analyzer, set its sample rate, and use a trigger (lesson Capturing a first digital signal)
  • A TESAIoT Dev Kit flashed with the QWA309 Header I/O Test example, which has a Scan button that scans the I2C bus and a UART Echo button that sends a short packet out the header’s UART pin
  • The board’s pinout diagram, to find the SDA and SCL pins of the I2C bus on the header, and pin P15.1 (UART TX)
  • If using the Eva Kit, scan the I2C bus and print text over UART with your own program — the decoding steps are exactly the same

Press the Scan button on the header test program’s screen. It prints a table of addresses 0x08 through 0x77; a cell where a device responds shows a number, and other cells show --. It then reports “Found N device(s),” followed by a list of addresses.

How does the program know a device is at a given address? It asks each address in turn, 112 times in all, and listens for anyone answering “present.” In this lesson, we will eavesdrop on all 112 of those conversations on the real wires, and prove with our own eyes that the table on screen tells the truth.

1. I2C on the wire: START, address, R/W, ACK, STOP

Section titled “1. I2C on the wire: START, address, R/W, ACK, STOP”

I2C uses two wires, SCL (the clock, driven by the master) and SDA (data). Both are open-drain — a device can only pull the line down. A pull-up resistor is what pulls the line back up, the same principle as the active-low button in the lesson Pull-ups, pull-downs and buttons.

SCL SDA 0 1 1 0 0 0 0 W A S address 0x30 R/W ACK P
An I2C frame: START (S) is SDA falling while SCL is high, followed by a 7-bit address (0x30 = 0110000), the R/W bit (0 = write), then the target device pulls SDA down to ACK, ending with STOP (P), SDA rising while SCL is high.
  • START (S): SDA falls while SCL is still high — the signal that “I am about to speak”
  • The 7-bit address: sent MSB first. Data on SDA must stay steady while SCL is high, and may change only while SCL is low
  • R/W: the 8th bit; 0 = write, 1 = read
  • ACK / NACK: on the 9th clock pulse, the master releases SDA. If the addressed device really exists, it pulls SDA down (ACK); if no one does, SDA stays high via the pull-up (NACK)
  • STOP (P): SDA rises while SCL is high

The 7-bit address versus the byte on the wire. The first byte on the wire is the address shifted left by one bit, with the R/W bit appended. So address 0x30 as a write becomes the byte 0x60, and as a read becomes 0x61. Some datasheets write the address in its 8-bit form (0x60), which confuses people very often. sigrok’s decoder shows it in 7-bit form by default (e.g. “Address write: 30”).

What the bus-scan tool does. The header test program sends START + address + W, then STOP, for each address in turn — no other data at all. Whichever address gets an ACK is where a device lives. Per the board’s SDK documentation, the I2C bus on the TESAIoT Dev Kit’s header has a CapSense chip (PSoC 4000T) that answers at 0x08, so you should see an ACK at 0x08 at minimum. Compare any other address that answers against the list the screen prints.

Sizing an I2C pull-up (formula from TI SLVA689). The resistor must not be so small that a device cannot pull the line down to V_OL, and not so large that the rising edge is slower than the spec allows.

R_p(min) = (V_CC − V_OL(max)) / I_OL = (3.3 − 0.4) V / 3 mA = 967 Ω
R_p(max) = t_r / (0.8473 × C_b)
Fast-mode 400 kHz (t_r ≤ 300 ns), a 100 pF bus → 300 ns / (0.8473 × 100 pF) = 3.54 kΩ
Standard-mode 100 kHz (t_r ≤ 1000 ns), a 100 pF bus → 11.8 kΩ

So a 400 kHz bus with 100 pF of capacitance can choose anywhere between 967 Ω and 3.54 kΩ — for example, 2.2 kΩ. The constant 0.8473 comes from ln(0.7 / 0.3), the time an RC curve takes to rise from 0.3 × V_CC to 0.7 × V_CC — exactly I2C’s V_IL and V_IH thresholds.

2. UART on the wire: no clock, so both sides must agree on speed beforehand

Section titled “2. UART on the wire: no clock, so both sides must agree on speed beforehand”

UART sends data on a single wire per direction (one side’s TX connects to the other side’s RX), with no clock wire at all, so both sides must set the same baud rate in advance. The most common format is 8N1: 8 data bits, no parity bit, 1 stop bit.

start 0 b0 1 b1 0 b2 1 b3 0 b4 0 b5 1 b6 0 b7 1 stop 1 idle 0xA5 = 1010 0101, sent LSB first · 115200 baud: 8.68 µs per bit
A UART 8N1 frame carrying byte 0xA5: the idle line is 1, the start bit is 0, followed by 8 data bits sent least-significant bit (LSB) first, then a stop bit of 1.
  • The idle line is 1
  • The start bit is 0 for one bit period — the receiver uses this falling edge to set its timing
  • The 8 data bits are sent least-significant bit first (LSB first) — the opposite of I2C
  • The stop bit is 1. If the receiver reads 0 here instead, it reports a framing error

The numbers at 115200 baud:

1 bit = 1 / 115200 s = 8.68 µs
1 byte = 10 bits (start + 8 + stop) = 86.8 µs
Maximum throughput = 115200 / 10 = 11,520 bytes per second

Example: byte 0xA5 = 1010 0101, sent LSB first. The bits on the wire after the start bit are therefore 1, 0, 1, 0, 0, 1, 0, 1, followed by a stop bit of 1.

The header test program’s UART Echo. It sends a 4-byte packet out pin P15.1 at 115200 8N1: A5 11 <counter> <checksum>. The counter starts at 0 and increments by one on every press; the checksum is the XOR of the first three bytes, so the first press gives A5 11 00 B4 (0xA5 XOR 0x11 = 0xB4). The program also prints the bytes it sent on screen, in a TX: line, so we have an answer key to check the decoder against. If no ESP32-S3 board answers as the example expects, per the constants in the code, the program waits 250 ms for a reply, pauses 10 ms, and resends — up to 4 times in total. Measure the real spacing from the capture yourself.

A wrong baud setting. The decoder measures bits at the wrong rhythm, giving garbled bytes and framing errors.

  • Setting 9600 against a real 115200 signal: one bit the decoder expects is 104 µs, but the whole 4-byte packet (about 347 µs) only lasts about 3.3 bits at 9600, so the decoder sees a single garbled byte or an error
  • Setting 57600 (half speed): each bit the decoder reads spans two real bits, giving wrong byte values, usually with framing errors
  • Setting too fast, e.g. 230400: the decoder sees one real bit as two, and the resulting bytes are meaningless

Finding the baud rate from a capture. Zoom in on the narrowest pulse (one bit), then compute baud ≈ 1 / that width. An 8.68 µs pulse is 115200; a 104 µs pulse is 9600. Then choose the nearest standard value — UART tolerates only a small baud error (generally, the combined error of both sides should stay under about 2 to 3%).

Other symptoms a capture can reveal:

What you see Possible cause
I2C: every address gets a NACK No device present, the device has no power, SDA and SCL are swapped, or the address is wrong
I2C: SDA or SCL stuck low the whole time A device is stuck mid-transaction, or a wire is shorted to ground
I2C: the rising edge is a long, slow curve (needs an oscilloscope to see) The pull-up is too large, or the bus is long enough that capacitance is high
UART: nothing on the RX wire even though the other side is sending TX is wired to TX (TX and RX must be crossed), or a common GND was forgotten

Problem: decode the header test program’s I2C bus scan, and confirm the result against the screen.

  1. Connect the leads. The device’s GND to GND, channel 0 to SCL, channel 1 to SDA of the I2C bus on the header (find their positions from the board’s pinout diagram).
  2. Sample rate. Not knowing the bus speed yet, use 8 MHz to start, which covers up to 400 kHz (20 samples per SCL period). Capture, then measure SCL’s period. If it turns out to be 100 kHz, you can lower the sample rate to capture for longer.
  3. Trigger on SDA’s falling edge (which happens at START). Press Run, then press Scan on screen.
  4. Add a decoder. In PulseView, add a decoder named I2C, and set SCL = channel 0 and SDA = channel 1.
  5. Read the result. The decoder track shows the sequence Start → Address write: 08 → ACK or NACK → Stop, repeating for each address in turn.
  6. Check. Address 0x08 should get an ACK (the CapSense chip); addresses with no device get a NACK. Count every address that got an ACK, and compare against “Found N device(s)” on screen — every address must match.
  7. Look at the raw byte. Switch the decoder’s display to show the address in 8-bit form; address 0x08 as a write must show as 0x10.

If the number of ACKs on the wire does not match the screen, do not blame the instrument yet — first check whether you captured all 112 addresses (was the capture time long enough?), and whether the sample rate was fast enough.

  1. A device has 7-bit address 0x44. What is the first byte on the wire for a write, and for a read?
  2. A decoder shows “Address read: 68” followed by NACK. What does this mean, and what should you check next?
  3. UART at 9600 8N1: how long is one bit, one byte, and what is the maximum throughput in bytes per second?
  4. Sending byte 0x55 over UART 8N1, what does the wire’s shape look like, and why is this byte useful for finding the baud rate?
  5. You measure the narrowest pulse on a UART wire at 26 µs. What is the baud rate likely to be?
  6. A 3.3 V I2C bus at 100 kHz has 200 pF of total capacitance. Find R_p(min) and R_p(max), then decide whether 4.7 kΩ works.
  7. Pressing UART Echo a third time (counter = 0x02), what should all 4 bytes of the packet be?
  1. Write: 0x44 shifted left one bit = 0x88. Read: 0x89.
  2. The master asked to read from address 0x68, and no one answered. Check that the device has power, is really on this same bus (a board may have several buses), and that the address matches the datasheet, including any address-select pins on the device.
  3. 1 bit = 1 / 9600 = 104.2 µs. 1 byte = 10 bits = 1.042 ms. Maximum throughput = 960 bytes per second.
  4. 0x55 = 0101 0101, sent LSB first gives 1, 0, 1, 0, 1, 0, 1, 0. Combined with the start bit (0) and stop bit (1), the wire alternates between 0 and 1 on every single bit — a square wave where every pulse is exactly one bit wide. Measuring that width gives the baud rate immediately.
  5. 1 / 26 µs = 38,462 baud. The nearest standard value is 38400.
  6. R_p(min) = (3.3 − 0.4) / 3 mA = 967 Ω. R_p(max) = 1000 ns / (0.8473 × 200 pF) = 5.90 kΩ. 4.7 kΩ falls within this range, so it works.
  7. A5 11 02 B6, because 0xA5 XOR 0x11 XOR 0x02 = 0xB6.

Answer at least 4 of the 5 questions in quiz.yaml correctly.

Part A: the I2C bus scan. Follow the worked example, then fill in the table.

What to check On the board’s screen From the decoder
SCL frequency not shown
Number of addresses asked 112 (0x08 to 0x77)
Addresses that got an ACK
Wire byte of the first ACK’d address (8-bit form) not shown

Part B: UART Echo

  1. Connect channel 0 to P15.1 (TX), and, if you have a spare channel, channel 1 to P15.0 (RX). Set the sample rate to 4 MHz, capture time 2 s, trigger on channel 0’s falling edge.
  2. Add a decoder named UART. Set baud 115200, 8 data bits, parity none, 1 stop bit, and set the decoder’s RX to read channel 0. (The names RX and TX in the decoder’s settings refer to which wire the decoder reads, not which side of the board they belong to.)
  3. Press UART Echo on screen. Compare the bytes the decoder reads against the TX: line on screen — every byte must match. Count how many times the packet was sent, and how far apart.
  4. Measure the start bit’s width, calculate the real baud rate from the capture, and compare it against 115200.
  5. Deliberately get it wrong. Change the decoder’s baud to 57600 and 9600. Record what the decoder shows, and explain it using section 3.
  6. Watch channel 1 (RX). If nothing answers, the wire stays idle at 1 the whole time. If you have an ESP32-S3 board as the example’s README describes, you should see a 5-byte reply starting with 0x5A.
Decoder’s baud What you see
115200
57600
9600

A logic analyzer can tell you when a signal is 0 or 1, but not what the real voltage looks like. The next lesson, Oscilloscope basics, will show us signal edges, overshoot, and noise that a logic analyzer cannot see. If you want to go further with I2C on this board, see the lesson Driving an RGB matrix over I2C in the TESAIoT Firmware Stack course.

Next time a program tells you “sent” or “device not found,” how many minutes would it take to prove with a logic analyzer what really happened on the wire — and is that worth more than guessing?

Review questions

Answer on your own first, then open the answer.

  1. A device has the 7-bit address 0x30. What is the first byte on SDA for a write? (Objective 1)

    1. 0x30
    2. 0x60
    3. 0x61
    4. 0x18
    Show answer

    Answer: B. 0x60

    ไบต์แรกคือ address เลื่อนซ้ายหนึ่งบิตแล้วต่อด้วยบิต R/W เขียนคือ 0 จึงได้ 0x60 ถ้าอ่านจะเป็น 0x61

  2. During a bus scan the decoder shows "Address write: 3C" followed by NACK. What does it mean? (Objective 1)

    1. อุปกรณ์ที่ 0x3C รับข้อมูลเรียบร้อย
    2. ไม่มีอุปกรณ์ตอบรับที่ address 0x3C ในจังหวะนาฬิกาที่ 9 SDA จึงค้างสูง
    3. บัสลัดวงจร
    4. decoder ตั้งความเร็วผิด
    Show answer

    Answer: B. ไม่มีอุปกรณ์ตอบรับที่ address 0x3C ในจังหวะนาฬิกาที่ 9 SDA จึงค้างสูง

    ในจังหวะที่ 9 มาสเตอร์ปล่อย SDA อุปกรณ์ที่มีอยู่จริงจะดึงลงเป็น ACK ถ้าไม่มีใครดึง pull-up ทำให้ SDA เป็น 1 คือ NACK เครื่องสแกนจึงสรุปว่าที่อยู่นี้ว่าง

  3. Which statements about I2C signalling are correct? (choose all that apply) (Objective 1)

    1. START คือ SDA ตกลงขณะ SCL สูง
    2. ACK คือฝั่งรับดึง SDA ลงในจังหวะนาฬิกาที่ 9
    3. ข้อมูลบน SDA ควรเปลี่ยนขณะ SCL สูง
    4. STOP คือ SDA ขึ้นขณะ SCL สูง
    Show answer

    Answer: A. START คือ SDA ตกลงขณะ SCL สูง · B. ACK คือฝั่งรับดึง SDA ลงในจังหวะนาฬิกาที่ 9 · D. STOP คือ SDA ขึ้นขณะ SCL สูง

    ข้อมูลต้องนิ่งขณะ SCL สูง และเปลี่ยนได้ตอน SCL ต่ำ การเปลี่ยน SDA ขณะ SCL สูงถูกสงวนไว้เป็นสัญญาณ START และ STOP เท่านั้น

  4. About how long is one bit on a 115200 baud UART? (Objective 2)

    1. 8.68 µs
    2. 86.8 µs
    3. 115 µs
    4. 0.87 µs
    Show answer

    Answer: A. 8.68 µs

    1 / 115200 = 8.68 µs ส่วน 86.8 µs คือหนึ่งไบต์แบบ 8N1 (10 บิตรวมบิตเริ่มและบิตหยุด)

  5. The line runs at 115200 baud but the decoder is set to 9600. What do you see? (Objective 2)

    1. ไบต์ถูกต้องแต่แสดงช้าลง
    2. ไบต์เพี้ยนหรือหายไปจำนวนมาก และมี framing error เพราะ decoder อ่านบิตผิดจังหวะ
    3. decoder ปรับ baud ให้เองอัตโนมัติ
    4. สายสัญญาณจะเปลี่ยนเป็น 9600 ตาม
    Show answer

    Answer: B. ไบต์เพี้ยนหรือหายไปจำนวนมาก และมี framing error เพราะ decoder อ่านบิตผิดจังหวะ

    UART ไม่มีสายนาฬิกา ฝั่งอ่านใช้จังหวะที่ตั้งไว้ ที่ 9600 หนึ่งบิตยาว 104 µs ครอบหลายบิตจริง ทั้งแพ็กเก็ตจึงกลายเป็นไบต์เพี้ยนไม่กี่ไบต์และ framing error วิธีแก้คือวัดพัลส์ที่แคบที่สุดแล้วหา baud จริง

Cite this lesson

If you teach from this lesson or reuse it in slides or documents, credit it with the text below. If you changed it, add (adapted) after the title.

"Decoding I2C and UART" from TESA Open Knowledge by the Thai Embedded Systems Association (TESA), https://github.com/tesaiot/tesa-qualification-program, licensed under CC BY-NC 4.0

Thai attribution: "ถอดรหัส I2C และ UART" จาก TESA Open Knowledge โดยสมาคมสมองกลฝังตัวไทย (Thai Embedded Systems Association: TESA) https://github.com/tesaiot/tesa-qualification-program สัญญาอนุญาต CC BY-NC 4.0

Lesson link: https://tesaiot.github.io/tesa-qualification-program/en/courses/electronics-and-instruments/m04-logic-analyzer/l02-decode-i2c-and-uart/

Full guide: how to cite TESA

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

Content is licensed CC BY-NC 4.0. Reuse it non-commercially and credit the Thai Embedded Systems Association (TESA) every time. · How to cite TESA