IoTLabs

Nghiên cứu, Sáng tạo và Thử nghiệm

Series ESP32-S3 Dual-Core – Bài 7: USB OTG – Device, Host, CDC, HID

USB Native vs USB-UART: Khác Biệt Quyết Định

Trước khi viết dòng code nào, cần phân biệt rõ 2 loại USB trên board ESP32-S3:

USB-UART Bridge (CH340/CP2102)

  • Chip bridge riêng trên board (thường là CH340G hoặc CP2102)
  • Chuyển đổi UART của ESP32 → USB
  • Máy tính thấy: cổng COM/ttyUSB (Serial port)
  • Dùng để: upload code, Serial Monitor
  • Không phải USB native của ESP32-S3

USB OTG Native (ESP32-S3)

  • Trực tiếp từ chip ESP32-S3 ra connector USB
  • Máy tính thấy: tùy bạn lập trình — CDC, HID, Mass Storage, v.v.
  • Cần: board dẫn chân GPIO19 (D-) và GPIO20 (D+) ra connector USB
  • Đây là USB thực sự, do firmware ESP32-S3 điều khiển
Cổng USB thứ 1 (thường là UART/JTAG):
  → Qua CH340 → Upload code, Serial Monitor thông thường

Cổng USB thứ 2 (Native USB):
  → Trực tiếp từ ESP32-S3 → CDC, HID, MSC, Host

Board ESP32-S3-DevKitC-1 có cả 2 cổng USB, ghi rõ “UART” và “USB” trên board.

Tại Sao USB Native Hữu Ích?

Tính năngUSB-UART BridgeUSB OTG Native
Serial debugCó (CDC)
HID Keyboard/MouseKhông
USB Mass StorageKhông
USB AudioKhông
USB HostKhôngCó (giới hạn)
Tốc độTheo UART baud rateFull Speed 12 Mbps
Cần driver PCCH340 driverKhông (CDC tự nhận)

CDC: USB Serial Không Cần Driver

CDC (Communication Device Class) cho phép ESP32-S3 xuất hiện như một cổng Serial trên máy tính — không cần driver, tự nhận trên Windows 10+, macOS và Linux:

#include "USB.h"
#include "USBCDC.h"

USBCDC USBSerial;

void setup() {
    // Khởi động USB CDC
    USB.begin();
    USBSerial.begin(115200);  // Baud rate chỉ là placeholder, USB không dùng

    delay(1000);  // Chờ host nhận device
    USBSerial.println("ESP32-S3 USB CDC ready!");
}

void loop() {
    // Đọc từ máy tính
    if (USBSerial.available()) {
        String cmd = USBSerial.readStringUntil('\n');
        USBSerial.printf("Nhận: %s\n", cmd.c_str());

        if (cmd.trim() == "status") {
            USBSerial.printf("Heap: %lu KB\n", ESP.getFreeHeap() / 1024);
            USBSerial.printf("Core: %d\n", xPortGetCoreID());
        }
    }
}

Máy tính sẽ thấy cổng COM mới (Windows) hoặc /dev/ttyACM0 (Linux) — không cần cài driver.

HID Keyboard: Biến ESP32-S3 Thành Bàn Phím

HID (Human Interface Device) cho phép ESP32-S3 gửi keystroke, mouse movement đến máy tính:

#include "USB.h"
#include "USBHIDKeyboard.h"

USBHIDKeyboard Keyboard;

void setup() {
    // Đặt tên device (hiện trong Device Manager)
    USB.manufacturerName("IoTLabs");
    USB.productName("ESP32-S3 Macro Pad");
    USB.begin();
    Keyboard.begin();
    delay(1000);
}

void loop() {
    // Gửi Ctrl+C khi nút được nhấn
    if (digitalRead(BUTTON_PIN) == LOW) {
        Keyboard.press(KEY_LEFT_CTRL);
        Keyboard.press('c');
        delay(50);
        Keyboard.releaseAll();
        delay(200);  // Debounce
    }
}

Ứng dụng thực tế:

// Macro pad: gửi keyboard shortcut phức tạp
void sendVSCodeDebugShortcut() {
    Keyboard.press(KEY_LEFT_CTRL);
    Keyboard.press(KEY_LEFT_SHIFT);
    Keyboard.press('d');
    delay(100);
    Keyboard.releaseAll();
}

// Tự động điền form (cẩn thận với bảo mật!)
void typeText(const char* text) {
    Keyboard.print(text);  // Gõ cả chuỗi text
}

HID Mouse: Con Chuột USB

#include "USB.h"
#include "USBHIDMouse.h"

USBHIDMouse Mouse;

void setup() {
    USB.begin();
    Mouse.begin();
    delay(1000);
}

void loop() {
    int x = map(analogRead(JOYSTICK_X), 0, 4095, -10, 10);
    int y = map(analogRead(JOYSTICK_Y), 0, 4095, -10, 10);

    Mouse.move(x, y, 0);  // Di chuyển cursor

    if (digitalRead(CLICK_BTN) == LOW) {
        Mouse.click(MOUSE_LEFT);
        delay(200);
    }

    delay(20);  // ~50 fps
}

CDC + HID Kết Hợp

Một ESP32-S3 có thể vừa là CDC Serial vừa là HID cùng lúc (composite device):

#include "USB.h"
#include "USBCDC.h"
#include "USBHIDKeyboard.h"

USBCDC USBSerial;
USBHIDKeyboard Keyboard;

void setup() {
    USB.begin();
    USBSerial.begin();
    Keyboard.begin();
    delay(1000);

    USBSerial.println("Composite USB: CDC + HID ready");
}

void loop() {
    // Nhận lệnh từ Serial để gửi keypress
    if (USBSerial.available()) {
        String cmd = USBSerial.readStringUntil('\n');
        if (cmd.startsWith("key:")) {
            String keyStr = cmd.substring(4);
            Keyboard.print(keyStr.c_str());
            USBSerial.printf("Sent: %s\n", keyStr.c_str());
        }
    }
}

USB Host: Kết Nối Thiết Bị USB Vào ESP32-S3

ESP32-S3 có thể làm USB Host — kết nối bàn phím, chuột, USB hub vào ESP32-S3. Cần thêm mạch VBUS switch để cấp 5V cho thiết bị ngoài.

Thư viện: esp_tinyusb (ESP-IDF) hoặc USB Host Shield ported.

#include "usb/usb_host.h"
#include "class/hid/hid_host.h"

// Callback khi có thiết bị HID kết nối vào
void hid_host_event_callback(hid_host_device_handle_t hid_device_handle,
                              const hid_host_driver_event_t event, void* arg) {
    switch (event) {
        case HID_HOST_DRIVER_EVENT_CONNECTED:
            Serial.println("HID device connected!");
            // Lấy report descriptor, xác định là keyboard hay mouse
            break;

        case HID_HOST_DRIVER_EVENT_DISCONNECTED:
            Serial.println("HID device disconnected");
            break;
    }
}

USB Host thực tế trên ESP32-S3 còn hạn chế và cần ESP-IDF, chưa hoàn thiện trong Arduino framework. Dùng được cho kết nối bàn phím/chuột đơn giản.

Lưu Ý Quan Trọng

1. Bootloop khi chỉ có USB Native

Nếu board chỉ có cổng USB Native (không có UART bridge), bạn cần bật USB CDC On Boot trong Arduino IDE:

  • Tools → USB CDC On Boot: Enabled
  • Khi bật: Serial (UART) và USBSerial (CDC) hoạt động song song
  • Không bật: Serial.println() không ra USB CDC

2. Upload khi dùng USB Native

Khi upload qua cổng USB Native:

  1. Giữ nút BOOT
  2. Nhấn RESET
  3. Thả BOOT
  4. Board vào bootloader mode → upload được

3. Không phải board nào cũng có USB Native

Kiểm tra datasheet board: chân GPIO19 và GPIO20 phải được dẫn ra connector USB. Một số board chỉ dùng USB-UART bridge, không expose USB native.

Tổng Kết

Mode USBThư ViệnDùng Cho
CDC SerialUSBCDCDebug, command interface không cần driver
HID KeyboardUSBHIDKeyboardMacro pad, shortcut controller
HID MouseUSBHIDMouseCustom pointing device
HID GamepadUSBHIDGamepadGame controller
Mass StorageUSBMSCXuất file SD card qua USB
Host HIDusb_host (ESP-IDF)Đọc bàn phím/chuột cắm vào

Bài tiếp theo: Bài 8 — Edge AI Trên ESP32-S3: SIMD, ESP-DSP, ESP-NN và Giới Hạn Thực Tế — Vector instructions làm gì, ESP-DSP cho FFT và signal processing, TFLite Micro và thực tế AI trên chip nhúng.