ESP32 không chạy? 18 lỗi thường gặp và cách khắc phục – Phần 1
Cách mình chẩn đoán 8 lỗi ESP32 thường gặp: nạp code, boot, brownout, serial, GPIO, I2C, SPI và PCB riêng không chạy.
Chia sẻ

ESP32 không chạy thường tạo cảm giác rất “ngẫu nhiên”: đổi cáp thì nạp được, bật Wi-Fi lại reset, cảm biến hôm qua còn thấy mà hôm nay i2cdetect không trả về gì. Mình từng mất khá nhiều thời gian sửa code trong khi nguyên nhân chỉ là cáp USB không có data hoặc một module đang kéo sai chân boot.
Trong phần 1 này, mình tập trung vào tám lỗi ở lớp thấp nhất: nguồn, quá trình boot, nạp firmware, kết nối phần cứng và bring-up PCB riêng. Phần crash, watchdog, bộ nhớ và mạng sẽ để sang phần 2.
Tên chân cụ thể vẫn khác giữa ESP32, C3, S3, C6 và các board bên thứ ba, nên trước khi cắm dây, bạn hãy mở pinout hoặc schematic đúng phiên bản mình đang dùng.
Trước khi sửa: debug từ dưới lên
Đi từ lớp thấp lên lớp cao giúp bạn tránh sửa firmware khi lỗi thật nằm ở nguồn hoặc dây nối.
Thứ tự mình hay dùng là:
Nguồn → EN/BOOT → serial log → nạp firmware → GPIO → I2C/SPI
Nếu rail 3,3 V đang sụt, việc đổi thư viện màn hình gần như không giúp gì. Ngược lại, khi nguồn và boot log đã ổn, bạn mới có cơ sở để nghi ngờ pin mapping hoặc driver.
1. Không nạp được code: Failed to connect hoặc No serial data received

Khi esptool không kết nối được, hãy thu gọn hệ thống về board, cáp data và đúng cổng serial trước.
Hai thông báo này chưa có nghĩa là chip hỏng. Theo hướng dẫn troubleshooting của esptool, nguyên nhân có thể nằm ở cổng serial, quyền truy cập, chương trình khác đang giữ cổng, nguồn không ổn, đường RX/TX hoặc chip chưa vào download mode.
Mình kiểm tra theo thứ tự ngắn sau:
- Rút các module ngoài, chỉ để ESP32 và USB.
- Chọn lại đúng board, đúng chip target và đúng port.
- Đóng Serial Monitor hoặc ứng dụng khác đang dùng port.
- Đổi sang một cáp đã chắc chắn truyền được data, rồi thử cổng USB khác.
- Hạ tốc độ nạp nếu quá trình thường hỏng giữa chừng.
- Nếu auto-reset không hoạt động, giữ
BOOT, nhấnEN/RESET, thảEN, bắt đầu nạp rồi thảBOOT.
Với board dùng USB native như một số ESP32-S3/C3, firmware có thể cấu hình lại chân USB khiến cổng biến mất. Khi đó, đưa chip về ROM download mode thủ công thường là bước cứu hộ đầu tiên. Đừng cài lại toàn bộ toolchain trước khi loại trừ cáp, port và boot mode.
2. Board chỉ chạy khi giữ BOOT, hoặc reset vào sai chế độ
ESP32 đọc các strapping pin tại thời điểm reset để chọn chế độ boot và một số cấu hình phần cứng. Trên ESP32 đời đầu, GPIO0 bị kéo thấp lúc reset sẽ đưa chip vào serial bootloader; các dòng mới có chân và điều kiện khác. Nếu cảm biến, nút nhấn hoặc mạch kéo ngoài giữ một strapping pin ở mức sai, board có thể không chạy application dù firmware đã nạp thành công.
Dấu hiệu thường gặp là:
Wrong boot mode detectedkhi nạp.- Nạp xong nhưng board vẫn quay lại download mode.
- Board chạy khi tháo một module ngoài hoặc khi chạm nút
BOOT. - DevKit chạy ổn nhưng PCB tự thiết kế không boot.
Hãy đo mức logic tại BOOT và EN ngay lúc reset, không chỉ đo khi board đã đứng yên. Kiểm tra điện trở kéo, mạch DTR/RTS auto-reset và tụ trên EN theo reference schematic của đúng chip. Một quy tắc thực tế là chưa gắn tải quan trọng vào strapping pin cho tới khi bạn hiểu trạng thái của tải đó lúc cấp nguồn.
3. Brownout detector was triggered hoặc reset khi bật Wi-Fi

Đo tại các chân cấp nguồn sát board sẽ hữu ích hơn chỉ nhìn điện áp đặt trên bộ nguồn.
Brownout không phải là lỗi “khó hiểu” của firmware. Bộ phát hiện brownout reset chip khi điện áp rơi xuống mức không còn an toàn. Wi-Fi thường làm lỗi lộ ra vì dòng tăng theo xung; đồng hồ số có thể vẫn hiển thị 3,3 V trung bình trong khi rail đã sụt rất ngắn.
Mình sẽ kiểm tra:
- Nguồn 3,3 V có đủ dòng đỉnh hay không. Espressif khuyến nghị nguồn ít nhất 500 mA cho ESP32 cổ điển và tụ tối thiểu 10 µF ở đầu vào nguồn của board.
- Cáp USB có quá dài, quá mảnh hoặc đầu nối lỏng không?
- Tụ 100 nF có gần chân nguồn và tụ bulk có gần module không?
- Motor, relay, loa hoặc backlight có dùng chung một đường nguồn hẹp với ESP32 không.
- Điện áp có sụt ngay tại chân
3V3vàGNDkhi Wi-Fi transmit không?
Nếu có oscilloscope, trigger tại thời điểm reset. Nếu chỉ có multimeter, thử một nguồn tốt đã biết, dây ngắn hơn và tạm tháo tải ngoài. Tắt brownout detector chỉ che triệu chứng; nó không biến một rail yếu thành rail ổn định.
4. Serial Monitor trống hoặc toàn ký tự lạ
Serial log là thứ mình xem trước cả LED. Khi màn hình trống, hãy phân biệt ba trường hợp: không có boot log, có dữ liệu nhưng sai baud, hoặc log đang đi qua interface khác.
Với ESP32 thông thường, ROM boot log xuất hiện trên UART0. Một số chip/board mới có thể dùng USB Serial/JTAG hoặc USB CDC tùy cấu hình. Bạn nên:
- Chọn đúng port vừa xuất hiện khi cắm board.
- Thử baud mà project cấu hình; log ứng dụng ESP-IDF thường dùng
115200. - Nối chéo
TX → RX,RX → TXvà luôn nối GND chung nếu dùng USB-UART rời. - Nhấn reset rồi chụp toàn bộ log đầu tiên, không chỉ dòng cuối.
- In reset reason sớm bằng
esp_reset_reason()khi dùng ESP-IDF.
Nếu ký tự rác chỉ xuất hiện ở vài byte đầu rồi log ứng dụng đọc được, đó có thể là baud của ROM boot log khác cấu hình monitor, không nhất thiết là lỗi chip. Nhưng nếu không có bất kỳ cạnh tín hiệu nào trên TX, hãy quay lại nguồn, EN và boot mode.
5. Chọn nhầm GPIO: LED không sáng, input luôn sai hoặc board không boot
“GPIO nào cũng giống nhau” là giả định dễ gây lỗi nhất khi chuyển giữa các dòng ESP32. Có chân chỉ input trên một số chip, chân nối flash/PSRAM trong module, strapping pin, chân USB native và chân không được đưa ra header. Ngoài ra, ESP32 dùng logic 3,3 V; không nên mặc định GPIO chịu được 5 V.
Trước khi đổ lỗi cho thư viện, mình kiểm tra bốn thứ:
- Số GPIO trong code có đúng với tên in trên board không.
- Chân có bị flash, PSRAM, USB hoặc peripheral khác chiếm không.
- Tải ngoài có làm thay đổi mức strapping lúc reset không.
- Input có pull-up/pull-down rõ ràng hay đang floating.
Khi bring up PCB mới, hãy bắt đầu bằng output chậm hoặc đọc input đơn giản trên một chân an toàn. Đừng thử ngay màn hình, SD card và interrupt cùng lúc; khi lỗi xảy ra, bạn sẽ không biết lớp nào sai.
6. I2C không thấy thiết bị hoặc báo timeout

Một lần kiểm tra dây, GND chung và pin mapping thường tiết kiệm nhiều thời gian sửa code.
I2C chỉ cần SDA và SCL nhưng lại nhạy với pull-up, điện dung dây và địa chỉ. Example i2c_tools của ESP-IDF rất hữu ích vì cho phép cấu hình chân, tốc độ rồi chạy i2cdetect mà chưa cần viết driver cho cảm biến.
Checklist ngắn của mình:
- Xác nhận SDA/SCL không bị đảo và mọi board có GND chung.
- Scan địa chỉ 7-bit; đừng chép máy móc địa chỉ 8-bit trong datasheet.
- Kiểm tra module đã có pull-up chưa. Nhiều module cùng bus có thể làm pull-up tổng quá mạnh; không có pull-up lại làm cạnh lên quá chậm.
- Hạ bus từ 400 kHz xuống 100 kHz và rút ngắn dây.
- Đo mức idle: SDA và SCL thường phải ở mức cao. Nếu một đường bị giữ thấp, tháo từng thiết bị để tìm thủ phạm.
Tài liệu ESP-IDF gợi ý vùng pull-up thường gặp 1–10 kΩ, trong đó 2–5 kΩ là điểm bắt đầu thực tế, nhưng giá trị cuối phụ thuộc vào điện dung bus và số module. Scanner thấy địa chỉ mới chỉ chứng minh ACK hoạt động; driver vẫn phải đúng register map, timing và điện áp logic.
7. SPI, màn hình hoặc SD card im lặng
SPI không có cơ chế địa chỉ như I2C, nên nối sai CS, sai mode hoặc để một thiết bị khác giữ bus có thể chỉ cho kết quả “không phản hồi”. Mình thường thu gọn về một thiết bị rồi kiểm tra:
SCLK,MOSI,MISO,CScó đúng hướng và đúng pin mapping không.- Mỗi thiết bị có một
CSriêng và cácCSkhông dùng được kéo về trạng thái inactive. - SPI mode (
CPOL/CPHA) và tốc độ có đúng datasheet không. - Dây clock có ngắn, GND return có tốt và nguồn module có đúng 3,3 V không.
- SD card có dòng khởi động lớn hoặc yêu cầu pull-up mà breakout hiện tại không đáp ứng không.
Hãy bắt đầu ở tốc độ thấp, chỉ gắn một peripheral và dùng example chính thức tương ứng. Khi nó chạy, thêm từng thiết bị trở lại. Logic analyzer rất hữu ích: có clock mà không có CS là lỗi cấu hình; có CS và clock nhưng MISO đứng yên thường do dây, nguồn, mode hoặc thiết bị chưa được reset đúng.
8. Dev board chạy nhưng PCB riêng không chạy
Đây là lỗi mình gặp khá nhiều khi chuyển từ DevKit sang PCB đầu tiên. Firmware gần như không đổi, module vẫn cùng loại, nhưng board riêng không có regulator, tụ, mạch auto-reset và USB bridge đã được nhà sản xuất DevKit xử lý sẵn. Vì vậy, hãy xem đây là một bài toán bring-up phần cứng thay vì vội sửa code.
Trước hết, mình đo nguồn ngay tại module và quan sát EN trong lúc cấp nguồn hoặc reset. Kiểm tra điện trở kéo của EN và BOOT, tụ trên EN, tụ bulk ở đầu vào cùng các tụ decoupling đặt sát chân nguồn. Một giá trị đúng trên schematic chưa đủ nếu đường nguồn quá hẹp, tụ đặt xa hoặc GND return đi vòng.
Tiếp theo là đường nạp firmware:
- Nếu dùng USB-UART, kiểm tra
TX/RXđã nối chéo, GND chung và mạch DTR/RTS có thực sự điều khiểnEN/BOOTđúng trình tự hay không. Hãy chừa test point để có thể kéo BOOT và reset thủ công. - Nếu dùng USB native, đối chiếu đúng chân
D+/D-của chip, điện trở series theo reference design, nguồn VBUS và đường return. Route hai đường như differential pair, hạn chế via và giữ reference plane liên tục.
Với module có PCB antenna, hãy ưu tiên đặt antenna nhô ra cạnh board. Không đổ đồng, chạy trace hay đặt linh kiện trong keepout được quy định cho đúng module; đồng thời để ý pin, shield kim loại và vỏ sản phẩm phía trên antenna. Board có thể boot bình thường nhưng Wi-Fi/BLE rất yếu nếu vùng này bị vi phạm.
Cuối cùng, tháo hoặc cô lập từng tín hiệu ngoại vi nối vào strapping pin, EN, BOOT và các chân flash/PSRAM. Level shifter, pull-up, màn hình hoặc cảm biến có thể kéo mức logic đúng sau khi boot nhưng sai ngay tại thời điểm reset. Trên revision đầu, mình thường chừa điện trở 0 Ω hoặc jumper để ngắt từng nhánh; nếu board boot khi tháo một nhánh, bạn đã thu hẹp được lỗi mà chưa cần thay ESP32.
Checklist 10 phút trước khi sửa code
- Tháo tải ngoài, dùng cáp data và nguồn đã biết tốt.
- Xác nhận đúng chip target, board, port và không có app giữ serial.
- Kiểm tra
EN,BOOTvà strapping pin lúc reset. - Lưu toàn bộ boot log và reset reason.
- Đo 3,3 V ngay tại module trong lúc lỗi xảy ra.
- So pinout với đúng biến thể ESP32, không dựa vào một sơ đồ trên mạng.
- Với I2C/SPI, giảm tốc độ và chỉ giữ một thiết bị.
- Chỉ đổi một thứ mỗi lần và ghi lại kết quả.
Kết luận
Điểm chung của phần lớn lỗi ESP32 ở giai đoạn bring-up là bạn dễ đi quá nhanh lên lớp phần mềm. Nếu bạn giữ đúng thứ tự nguồn → boot → log → flash → GPIO → bus, mỗi phép thử sẽ loại bỏ được một nhóm nguyên nhân và việc debug bớt phụ thuộc vào may mắn.
Ở phần 2, mình sẽ đi tiếp vào Guru Meditation, backtrace, watchdog, stack/heap, FreeRTOS, Wi-Fi/BLE, deep sleep và OTA.
Tham khảo
Chia sẻ
Tiếp tục khám phá
Đọc tiếp
Bài viết liên quan
MEMS mic thực sự là gì? Từ màng rung silicon đến I2S trên ESP32
Tìm hiểu microphone MEMS, khác biệt analog, PDM, I2S, thông số quan trọng và lỗi PCB, nguồn, acoustic port khi dùng với ESP32.
Thiết kế nguồn pin cho ESP32: Từ USB-C, mạch sạc đến rail 3.3V
Phân tích đường nguồn ESP32-S3 từ USB-C, TP4056 và pin Li-ion đến bảo vệ, power-path, LDO 3,3 V, tụ lọc và ngân sách tải.
ESP32-C3 hay ESP32-S3: Nên chọn chip nào cho robot Mochi?
So sánh ESP32-C3 và ESP32-S3 theo GPIO, RAM, PSRAM, USB, I2S và khả năng chạy LVGL, kèm lựa chọn cụ thể cho Mochi cơ bản và Mochi AI.