Logic analyzer 8 kênh và PulseView: bắt và giải mã UART, I2C, SPI, PWM của ESP32

Dùng logic analyzer 8 kênh giá rẻ với PulseView: nối dây với ESP32, cài driver bằng Zadig, bắt tín hiệu bằng kích hoạt, giải mã UART, I2C, SPI, đo PWM và chọn tốc độ lấy mẫu.

Chương trình gửi dữ liệu qua UART, I2C hay SPI mà thiết bị bên kia không phản hồi, câu hỏi đầu tiên là: tín hiệu có thật sự ra tới chân chưa, đúng tốc độ chưa, đúng byte chưa? Đồng hồ vạn năng không trả lời được, vì tín hiệu đổi mức hàng nghìn lần mỗi giây. Logic analyzer (máy phân tích logic) ghi lại mức 0/1 của nhiều chân cùng lúc, còn phần mềm PulseView vẽ dạng sóng và giải mã thành byte, địa chỉ, ACK. Bài này dùng một máy đo 8 kênh giá rẻ với ESP32: nối dây, cài PulseView, bắt và giải mã UART, I2C, SPI, đo PWM, chọn tốc độ lấy mẫu cho đúng.

1. Logic analyzer là gì

Một logic analyzer 8 kênh tự làm: mạch in trong hộp nhựa trắng, cổng USB, dải LED báo mức, dây cáp dẹt nhiều màu nối tới các kẹp móc đo
Một logic analyzer 8 kênh tự làm, dây cáp dẹt nối tới kẹp móc đo. Ảnh: Dilshan Jayakody, CC BY-SA 2.0, Wikimedia Commons; đã cắt.

Logic analyzer đọc mỗi kênh ở những thời điểm cách đều nhau (tốc độ lấy mẫu, ví dụ 8 triệu lần mỗi giây) và chỉ ghi lại một trong hai giá trị: cao hay thấp. Dữ liệu chuyển qua USB vào máy tính, phần mềm vẽ lại thành dạng sóng và tự đọc ra nội dung theo giao thức bạn chọn.

  • Máy 8 kênh giá rẻ phổ biến hiện nay dùng chip USB loại FX2, tốc độ lấy mẫu tối đa ghi 24 MHz, hợp với UART, I2C, SPI tốc độ vừa của ESP32 và Arduino.
  • PulseView là phần mềm mã nguồn mở của dự án sigrok, chạy trên Windows, Linux, macOS, nhận loại máy này qua driver fx2lafw.
  • Khác máy hiện sóng: logic analyzer có nhiều kênh và giải mã giao thức, nhưng không thấy điện áp thật. Muốn xem sườn chậm, nhiễu, điện áp bao nhiêu volt thì cần máy hiện sóng.

Mạch ESP32 dùng mức 3,3 V, đo trực tiếp được. Với mạch 5 V, xem thông số đầu vào của máy đang có; không nối kênh đo vào điện áp cao hơn 5 V hay vào điện lưới.

2. Chuẩn bị

3. Nối dây

Sơ đồ: ESP32 DevKit V1 nối logic analyzer: D0 tới TX2, D1 tới D22, D2 tới D21, D3 tới D18, D4 tới D23, D5 tới D5, D6 tới D25, GND tới GND; màn hình OLED: GND, VCC tới 3V3, SCL tới D22, SDA tới D21
Bảy kênh đo bảy chân tín hiệu; GND của máy đo nối GND của ESP32.
Kênh trong PulseViewChân ESP32Tín hiệu
D0GPIO17 (TX2)UART 9600 baud
D1GPIO22I2C SCL
D2GPIO21I2C SDA
D3GPIO18SPI SCK
D4GPIO23SPI MOSI
D5GPIO5SPI CS
D6GPIO25PWM 1 kHz
GNDGNDĐất chung, bắt buộc

Dây GND là dây quan trọng nhất: thiếu nó, máy đo không có mốc để so mức, dạng sóng sẽ loạn hoặc đứng yên. Dùng dây ngắn, cắm chắc. Trên vỏ máy đo, kênh có thể ghi CH1–CH8 hoặc CH0–CH7; trong PulseView kênh đầu tiên luôn là D0.

4. Chương trình tạo tín hiệu mẫu

Chương trình chỉ dùng thư viện có sẵn trong gói ESP32 cho Arduino IDE. Cứ 500 ms phát một lượt: hai ký tự "PY" qua UART2, một gói I2C tới địa chỉ 0x3C (byte 0x00 và 0xAE, là lệnh tắt hiển thị nếu có màn hình SSD1306), hai byte 0xA5, 0x3C qua SPI. Kênh PWM chạy liên tục 1 kHz với độ rộng xung 25%.

// PYWORLD.VN - Tín hiệu mẫu để tập đo bằng logic analyzer và PulseView
// PYWORLD.VN - Mỗi 500 ms phát một lượt: UART 9600 baud, I2C 100 kHz, SPI 1 MHz; PWM 1 kHz chạy liên tục
// PYWORLD.VN - Nối kênh D0..D6 của logic analyzer theo bảng trong bài, GND chung với ESP32

#include <Wire.h>
#include <SPI.h>

// Chân phát tín hiệu
const int CHAN_UART_RX = 16;  // Serial2 cần khai báo chân nhận, bài này không dùng
const int CHAN_UART_TX = 17;  // -> D0
const int CHAN_SCL = 22;      // -> D1
const int CHAN_SDA = 21;      // -> D2
const int CHAN_SCK = 18;      // -> D3
const int CHAN_MOSI = 23;     // -> D4
const int CHAN_CS = 5;        // -> D5
const int CHAN_MISO = 19;     // SPI cần khai báo chân nhận, bài này không dùng
const int CHAN_PWM = 25;      // -> D6

const uint32_t BAUD_UART = 9600;
const uint32_t TAN_SO_I2C = 100000;
const uint32_t TAN_SO_SPI = 1000000;
const uint32_t TAN_SO_PWM = 1000;
const uint8_t DO_PHAN_GIAI_PWM = 8;  // 0..255
const uint32_t DUTY_PWM = 64;        // 64/256 = 25 %

// Địa chỉ màn hình OLED 0.96 inch SSD1306. Không gắn thiết bị thì sẽ thấy NACK.
const uint8_t DIA_CHI_I2C = 0x3C;

uint32_t soLuot = 0;

void setup() {
  Serial.begin(115200);
  Serial2.begin(BAUD_UART, SERIAL_8N1, CHAN_UART_RX, CHAN_UART_TX);
  Wire.begin(CHAN_SDA, CHAN_SCL, TAN_SO_I2C);

  SPI.begin(CHAN_SCK, CHAN_MISO, CHAN_MOSI, -1);
  pinMode(CHAN_CS, OUTPUT);
  digitalWrite(CHAN_CS, HIGH);  // CS nghỉ ở mức cao

  ledcAttach(CHAN_PWM, TAN_SO_PWM, DO_PHAN_GIAI_PWM);
  ledcWrite(CHAN_PWM, DUTY_PWM);

  Serial.println("Tin hieu mau cho logic analyzer");
  Serial.println("D0=GPIO17 UART  D1=GPIO22 SCL  D2=GPIO21 SDA  D3=GPIO18 SCK  D4=GPIO23 MOSI  D5=GPIO5 CS  D6=GPIO25 PWM");
}

void loop() {
  // 1. UART: hai ký tự "PY" (0x50, 0x59), khung 8N1
  Serial2.print("PY");
  Serial2.flush();  // chờ phát xong bit cuối
  delayMicroseconds(200);

  // 2. I2C: địa chỉ 0x3C + ghi, byte điều khiển 0x00 (lệnh), lệnh 0xAE (tắt hiển thị của SSD1306)
  Wire.beginTransmission(DIA_CHI_I2C);
  Wire.write(0x00);
  Wire.write(0xAE);
  uint8_t ketQua = Wire.endTransmission();
  delayMicroseconds(200);

  // 3. SPI chế độ 0, bit cao trước: hai byte 0xA5, 0x3C liền nhau trong một lần CS thấp
  const uint8_t goi[2] = {0xA5, 0x3C};
  SPI.beginTransaction(SPISettings(TAN_SO_SPI, MSBFIRST, SPI_MODE0));
  digitalWrite(CHAN_CS, LOW);
  SPI.writeBytes(goi, sizeof(goi));
  digitalWrite(CHAN_CS, HIGH);
  SPI.endTransaction();

  soLuot++;
  if (ketQua == 0) {
    Serial.printf("Luot %u: I2C 0x%02X -> ACK\n", (unsigned)soLuot, DIA_CHI_I2C);
  } else if (ketQua == 2) {
    Serial.printf("Luot %u: I2C 0x%02X -> NACK (khong co thiet bi tra loi)\n", (unsigned)soLuot, DIA_CHI_I2C);
  } else {
    Serial.printf("Luot %u: I2C loi ma %u\n", (unsigned)soLuot, (unsigned)ketQua);
  }
  delay(500);
}

Mở Serial Monitor ở 115200 baud: mỗi lượt in một dòng như Luot 12: I2C 0x3C -> ACK khi có màn hình OLED, hoặc NACK (khong co thiet bi tra loi) khi không gắn gì. Cả hai trường hợp đều đo được.

5. Cài PulseView và nhận máy đo

Sáu bước: cài PulseView có kèm Zadig; mở Zadig gán WinUSB cho máy đo, có thể phải gán lần hai; chọn driver fx2lafw, quét thiết bị; đặt số mẫu và tốc độ lấy mẫu; kích hoạt sườn xuống ở D0 rồi bấm Run; thêm bộ giải mã UART, I2C, SPI, PWM
Từ cài phần mềm tới khi thấy chữ giải mã dưới dạng sóng.
  1. Tải bộ cài PulseView cho Windows ở trang tải về của dự án sigrok (sigrok.org). Bộ cài có kèm sẵn công cụ Zadig để đổi driver USB.
  2. Cắm máy đo, mở Zadig. Nếu không thấy thiết bị trong danh sách, bật Options → List All Devices. Chọn máy đo, chọn driver WinUSB, bấm cài (Replace Driver hoặc Install Driver).
  3. Mở PulseView, mở hộp kết nối thiết bị: chọn driver fx2lafw, giao diện USB, bấm quét thiết bị (Scan for devices), chọn máy đo rồi OK. Máy giá rẻ có thể hiện dưới tên một dòng máy khác vì dùng chung mã USB; vẫn chọn bình thường.
  4. Lần đầu kết nối, PulseView nạp firmware vào máy đo, máy đo kết nối lại với mã USB mới. Nếu PulseView báo không mở được thiết bị, mở Zadig gán WinUSB thêm một lần cho thiết bị mới hiện ra.

Windows nhớ driver theo cổng USB: cắm máy đo sang cổng khác thì có thể phải gán WinUSB lại.

6. Bắt một lượt tín hiệu

  • Tốc độ lấy mẫu: 8 MHz (đủ cho SPI 1 MHz, xem mục 10).
  • Số mẫu: 1 M mẫu ở 8 MHz là 125 ms, đủ chứa một lượt (khoảng 3 ms).
  • Kích hoạt (trigger): bấm vào tên kênh D0, chọn sườn xuống. UART nghỉ ở mức cao, nên sườn xuống đầu tiên chính là bit start của chữ "P"; phần mềm bắt đầu ghi từ đó. Không dùng kích hoạt thì chọn số mẫu đủ dài hơn 500 ms (ví dụ 5 M mẫu ở 8 MHz).
  • Bấm Run, phóng to quanh điểm kích hoạt bằng con lăn chuột.

7. Giải mã UART

Dạng sóng kênh D0 của hai ký tự PY ở 9600 baud; hàng bit ghi start, 0 0 0 0 1 0 1 0, stop, start, 1 0 0 1 1 0 1 0, stop; hàng byte ghi 50 P và 59 Y; 1 bit 104,2 micro giây, 2 ký tự 2,08 ms
Kiểu hiển thị của bộ giải mã: dạng sóng ở trên, hàng bit và hàng byte ở dưới (vẽ lại, không phải ảnh chụp màn hình).

Bấm nút thêm bộ giải mã giao thức, gõ tìm UART. Bấm vào tên bộ giải mã vừa thêm để đặt: chân RX = D0, tốc độ 9600, 8 bit dữ liệu, không parity, 1 bit stop; định dạng hiển thị chọn hex hoặc ASCII. Bên dưới D0 hiện các hàng chữ: bit start, từng bit dữ liệu, bit stop và byte 50 ('P'), 59 ('Y').

Đây cũng là cách đo tốc độ baud thật: một bit ở 9600 baud dài 104,2 µs. Đặt hai con trỏ đo thời gian của PulseView ở hai sườn cách nhau một bit để kiểm tra; nếu lệch nhiều, phía nhận sẽ đọc sai ký tự.

8. Giải mã I2C

Dạng sóng SCL trên D1 và SDA trên D2; hàng bit 0 1 1 1 1 0 0 0 A, 0 0 0 0 0 0 0 0 A, 1 0 1 0 1 1 1 0 A; hàng gói ghi Start, Địa chỉ 3C, Ghi, ACK, Dữ liệu 00, ACK, Dữ liệu AE, ACK, Stop; SCL 100 kHz, cả gói khoảng 285 micro giây
Gói I2C ghi hai byte vào địa chỉ 0x3C khi có màn hình OLED trả lời (thời điểm theo lý thuyết).

Thêm bộ giải mã I2C, đặt SCL = D1, SDA = D2. PulseView ghi nhãn tiếng Anh như Start, Address write: 3C, ACK, Data write: 00, Stop; trong hình đã ghi lại bằng tiếng Việt. Không gắn thiết bị thì sau 8 bit đầu là NACK: SDA vẫn cao ở nhịp thứ 9, ESP32 dừng gói.

Gặp lỗi "không tìm thấy thiết bị I2C", logic analyzer cho biết ngay: ESP32 có gửi đúng địa chỉ không, thiết bị có ACK không, SDA có bị kéo xuống mãi không. Chỉ có điện trở kéo lên bên trong ESP32 (khá yếu) thì sườn lên chậm hơn; module OLED thường đã có sẵn điện trở kéo lên.

9. Giải mã SPI và đo PWM

Phía trên: CS trên D5 xuống thấp suốt 16 xung SCK trên D3, MOSI trên D4 giải mã thành A5 và 3C; phía dưới: PWM trên D6 có độ rộng xung 0,250 ms, chu kỳ 1,000 ms tức 1000 Hz, mỗi chu kỳ ghi 25,0 phần trăm
SPI chế độ 0 và PWM 1 kHz, duty 64/256 (thời điểm theo lý thuyết; trên mạch thật có khoảng hở giữa CS và xung nhịp đầu tiên).
  • SPI: thêm bộ giải mã SPI, đặt CLK = D3, MOSI = D4, CS = D5 (kích hoạt mức thấp), chế độ 0 (CPOL = 0, CPHA = 0), bit cao trước, 8 bit mỗi từ. Hàng MOSI hiện A5, 3C. Chọn sai chế độ, các byte sẽ lệch một bit.
  • PWM: thêm bộ giải mã PWM cho D6, mỗi chu kỳ hiện tỉ lệ độ rộng xung (25%). Dùng con trỏ đo thời gian để thấy chu kỳ 1 ms, tức 1 kHz.

10. Chọn tốc độ lấy mẫu

Ký tự P ở 9600 baud lấy mẫu ở 20 kHz, 50 kHz, 100 kHz; ở 20 kHz chỉ 2,1 mẫu mỗi bit, đọc đúng PY 42 phần trăm số lần; ở 50 kHz và 100 kHz đọc đúng 100 phần trăm
Mô phỏng một bộ đọc UART đơn giản với 2000 thời điểm bắt đầu khác nhau.

Phần mềm chỉ biết mức ở các điểm lấy mẫu, nên vị trí sườn có thể lệch tới một khoảng mẫu. Ở 20 kHz mỗi bit UART 9600 baud chỉ có khoảng 2 mẫu, mô phỏng cho thấy chỉ khoảng 42% số lần đọc đúng "PY". Từ khoảng 5 mẫu mỗi bit trở lên thì đọc đúng ổn định. Quy tắc dễ nhớ: lấy mẫu nhanh gấp 4 lần trở lên so với tốc độ bit hoặc xung nhịp nhanh nhất, gấp 10 lần nếu cần đo thời gian chính xác.

Tín hiệuTốc độ bit / xung nhịpLấy mẫu tối thiểuNên dùng
UART 9600 baud9,6 kHz50 kHz100 kHz – 1 MHz
UART 115200 baud115,2 kHz500 kHz1–2 MHz
I2C 100 kHz100 kHz500 kHz1–2 MHz
I2C 400 kHz400 kHz2 MHz4–8 MHz
SPI 1 MHz1 MHz4 MHz8–12 MHz

Máy 24 MHz giá rẻ đọc tốt tới khoảng vài MHz xung nhịp. SPI nhanh hơn (ví dụ thẻ nhớ, màn hình chạy 10–40 MHz) thì nên giảm tốc độ SPI trong chương trình khi cần đo, hoặc dùng máy đo nhanh hơn. Tốc độ cao cũng làm đầy bộ đệm USB nhanh: nếu PulseView dừng giữa chừng, giảm tốc độ lấy mẫu hoặc cắm máy đo thẳng vào máy tính, không qua hub.

11. Lỗi hay gặp

Hiện tượngNguyên nhân thường gặpCách xử lý
PulseView không thấy máy đoChưa gán WinUSB, chọn sai driverGán WinUSB bằng Zadig, chọn fx2lafw, quét lại
Báo không mở được thiết bịDriver gắn với mã USB cũ hoặc cổng cũRút cắm lại, gán WinUSB lần hai cho thiết bị mới hiện ra
Mọi kênh là đường thẳngThiếu GND chung, cửa sổ ghi không có lượt tín hiệuNối GND; dùng kích hoạt sườn xuống ở D0 hoặc tăng số mẫu
UART ra ký tự lạ, báo lỗi khungSai baud, sai kênh RX, lấy mẫu chậmĐặt đúng 9600, RX = D0, lấy mẫu từ 100 kHz trở lên
I2C toàn NACKKhông có thiết bị, sai địa chỉ (0x3C hay 0x3D), dây SDA/SCL đảoKiểm tra dây, thử địa chỉ còn lại
Byte SPI lệch một bitSai chế độ SPI hoặc thứ tự bitĐặt chế độ 0, bit cao trước

12. Xem thêm


Tin tức liên quan

Các nguồn sai số khi đo lực bằng load cell: lệch tâm, rão, trễ, nhiệt độ và ngân sách sai số
Các nguồn sai số khi đo lực bằng load cell: lệch tâm, rão, trễ, nhiệt độ và ngân sách sai số

Vì sao đo lực thực tế sai hơn phiếu thông số load cell: lệch tâm và gá lắp, rão, trễ, phi tuyến, nhiệt độ, cáp và bộ đọc; ví dụ ngân sách sai số và danh sách kiểm tra nhanh.

Nguồn điện, đi dây, công tắc hành trình và nút dừng khẩn cho máy CNC tự chế
Nguồn điện, đi dây, công tắc hành trình và nút dừng khẩn cho máy CNC tự chế

Chọn nguồn 24 V đủ công suất, sơ đồ đi điện có nút dừng khẩn, nối công tắc hành trình thường mở, thường đóng với GRBL, chống nhiễu và chọn tiết diện dây cho máy CNC, máy laser tự chế.

Mạch sạc pin 2S, 3S, 4S từ Type-C 5 V: chọn 1A, 2A, 4A, đấu dây và vì sao vẫn cần mạch bảo vệ BMS
Mạch sạc pin 2S, 3S, 4S từ Type-C 5 V: chọn 1A, 2A, 4A, đấu dây và vì sao vẫn cần mạch bảo vệ BMS

Mạch sạc tăng áp từ 5 V lên 8,4, 12,6, 16,8 V cho khối pin 2S, 3S, 4S: chân và cầu hàn, dòng sạc thực tế, nguồn cần dùng, đấu dây với mạch bảo vệ BMS và an toàn khi sạc.

Jack USB Type-C: phân biệt loại 2, 4, 5, 6 dây và các kiểu lắp
Jack USB Type-C: phân biệt loại 2, 4, 5, 6 dây và các kiểu lắp

Jack USB Type-C loại 2, 4, 5, 6 dây khác nhau ở tín hiệu đưa ra: nguồn, dữ liệu D+ D−, chân CC. Bài giải thích từng loại, màu dây, các kiểu lắp tròn, oval, dẹt có tai và cách chọn cho mạch.

Diode zener, Schottky và cầu chỉnh lưu: ổn áp đơn giản, nguồn từ biến áp
Diode zener, Schottky và cầu chỉnh lưu: ổn áp đơn giản, nguồn từ biến áp

Diode zener hoạt động thế nào, cách tính mạch ổn áp zener, khi nào chọn diode Schottky, nguyên lý cầu chỉnh lưu, điện áp ra và độ gợn khi có tụ lọc trong nguồn dùng biến áp.

Cảm biến mức: phao, điện cực, thủy tĩnh, siêu âm, radar – cấu tạo, nguyên lý và chế tạo
Cảm biến mức: phao, điện cực, thủy tĩnh, siêu âm, radar – cấu tạo, nguyên lý và chế tạo

Cảm biến mức hoạt động thế nào: phao, điện cực, điện dung, áp suất thủy tĩnh, siêu âm, radar, âm thoa rung, cách chế tạo và đo mức bồn nước bằng HC-SR04 với ESP32 có bù nhiệt độ.

RS-485 là gì: cặp dây vi sai, điện trở đầu cuối và cách dùng module MAX485 với ESP32
RS-485 là gì: cặp dây vi sai, điện trở đầu cuối và cách dùng module MAX485 với ESP32

Giải thích chuẩn RS-485: tín hiệu vi sai trên hai dây A, B, điện trở đầu cuối 120 Ω, truyền bán song công với chân DE, RE. Kèm sơ đồ nối module MAX485 và chương trình hỏi đáp giữa hai mạch ESP32.

Lập trình nuôi dưỡng tư duy sáng tạo của trẻ: bài toán nhiều lời giải, dự án mở, vòng học sáng tạo
Lập trình nuôi dưỡng tư duy sáng tạo của trẻ: bài toán nhiều lời giải, dự án mở, vòng học sáng tạo

Vì sao học lập trình nuôi dưỡng tư duy sáng tạo của trẻ: bằng chứng nghiên cứu, bài toán nhiều lời giải, học qua làm sản phẩm, vòng học sáng tạo, bốn tiêu chí và thử thách mở.


Bình luận
Đã thêm vào giỏ hàng