透传设备方案

概述

USB CDC ACM (Communication Device Class - Abstract Control Model) 协议采用 USB 批量传输(Bulk Transfer)机制,提供通用的高速数据透传通道,适用于高吞吐量数据流的实时传输与指令交互。

Ameba 遵循 USB-IF 标准实现 CDC ACM 功能,实现双向透传。Host 主机可通过标准 USB 接口与 Ameba 内部逻辑或后端外设直接交换原始数据(Raw Data),实现了对底层传输细节的屏蔽与抽象。

Ameba USB CDC ACM 设备

特性

  • 可被识别为标准串口设备,支持通用的串口工具,例如 PuTTY/TeraTerm

  • 支持 USB 热插拔

  • 支持描述符全定制

  • 支持配置传输缓存大小、批量传输长度、速度模式等参数

  • 可选择性配置中断 IN 端点,方便在不需要中断 IN 的应用中节省带宽

  • 支持双向通信, 可执行数据的同步或异步回传操作

应用场景

作为 USB 数据透传桥接设备,Ameba 可通过 USB 接口建立主设备(Host,如 PC 或嵌入式主机)与外界的高速数据链路,并结合其他外设接口实现多种典型应用,例如:

  • 传感器采集与机器人控制:Ameba 充当高性能传感器节点,采集前端的高速环境或运动数据,通过 USB 通道实时上传至机器人控制系统,支持高频原始数据的零丢包传输及闭环控制指令的快速下发。

  • 设备管理与固件维护:面向物联网设备的生命周期管理,管理终端可通过 CDC 通道与设备建立通信,进行参数配置、运行状态诊断,并支持通过该数据链路完成固件的升级(OTA)与维护。

  • 无线数据网关:借助内部集成的 Wi-Fi 与蓝牙模块,Ameba 可作为无线网桥,将 USB 接收到的主机数据流透传至无线网络,为不具备无线功能的工控主机或管理终端提供即插即用的无线接入能力。

协议简介

CDC (Communication Device Class) 是 USB 规范定义的通用通信设备类标准。在其 PSTN 子类下,最常用的是 ‌ACM‌ (Abstract Control Model)。它定义了一套标准化的命令集,用于控制通信参数,例如:

  • 设置波特率(如 9600、115200)

  • 配置数据位、停止位、校验位

  • 控制 DTR/RTS 等线路状态信号

正是通过 ACM,USB CDC 设备才能被主机识别为一个标准的“虚拟串口”。

协议文档

USB-IF 官方发布了 CDC 类基础协议及 PSTN 子类规范。开发过程中请参考以下核心文档:

规范类型

文档

CDC (通信类基础协议)

Class definitions for Communication Devices

PSTN (PSTN 子类)

协议文档包含在上述 CDC 规范的压缩包中

协议框架

CDC ACM 协议规定设备必须使用 双接口 机制分离控制流与数据流,并通过 联合功能描述符 (Union Functional Descriptor) 将二者逻辑绑定为单一功能单元。

  • 通信类接口 (Communication Class Interface, CCI)

    负责设备的管理控制与信令交互。

    • 控制传输:通过默认控制端点传输类特定请求。

      • 主机主要发送 PSTN 控制命令,核心指令包括配置波特率/数据位的 SetLineCoding 以及控制 RTS/DTR 握手信号的 SetControlLineState。

    • 中断传输:利用中断输入端点实现设备向主机的异步状态通报 (Notification)。

      • 典型应用是通过 SERIAL_STATE 实时报告 DCD、DSR 或 Ring 等硬件信号状态的变化。

  • 数据类接口 (Data Class Interface, DCI)

    负责承载应用层的业务数据流。该接口通常配置为一对批量端点,负责透传数据流,不涉及控制指令的解析与处理。

协议交互示例:

../../../_images/usb_cdc_acm_class.svg

描述符结构

CDC ACM 设备除遵循标准的 USB 描述符(如设备描述符、配置描述符、端点描述符)外,还定义了 类特定功能描述符 (Class-Specific Functional Descriptors)来定义抽象控制模型的能力。

CDC ACM 描述符拓扑 (Descriptor Topology)

下面以高速配置为例,展示描述符的拓扑结构:

Device Descriptor
└── Identifies basic device information (Class: 0x02 CDC, SubClass: 0x02 ACM)

Configuration Descriptor
├── Includes total length, power attributes (Self-powered), etc.
│
├── Communication Class Interface Descriptor (Interface 0)
│   ├── Standard Interface Descriptor (Class: 0x02, SubClass: 0x02, Protocol: 0x01 AT Commands)
│   │
│   ├── Class-Specific Functional Descriptors (Defines ACM capabilities)
│   │   ├── Header Functional Descriptor (Declares CDC Spec version)
│   │   ├── Call Management Functional Descriptor (Call handling capabilities)
│   │   ├── ACM Functional Descriptor (Line coding & state capabilities)
│   │   └── Union Functional Descriptor (Binds Interface 0 and Interface 1)
│   │
│   └── Standard Endpoint Descriptor (Interrupt IN)
│       └── Used for Serial State notifications
│
├── Data Class Interface Descriptor (Interface 1)
│   ├── Standard Interface Descriptor (Class: 0x0A Data, SubClass: 0x00, Protocol: 0x00)
│   │
│   ├── Standard Endpoint Descriptor (Bulk OUT)
│   │   └── Host -> Device Data Stream
│   │
│   └── Standard Endpoint Descriptor (Bulk IN)
│       └── Device -> Host Data Stream
│
├── Device Qualifier Descriptor
│   └── Device information for other speed modes
│
└── Other Speed Configuration Descriptor
    └── Configuration information for Full Speed mode

功能描述符 (Functional Descriptor)

在通信接口中,CDC 必须包含以下特殊的“功能描述符”头部:

  • Header Functional Descriptor: 指明 CDC 版本。

  • Call Management Functional Descriptor: 指明设备如何处理呼叫管理。

  • Abstract Control Management Functional Descriptor: 指明支持哪些命令(如 Set_Line_Coding)。

  • Union Functional Descriptor: 指定哪个是 Master 接口,哪个是 Slave 接口。

  • Header Functional Descriptor

Header Functional Descriptor
├── bLength            : 1 byte   → Total descriptor length (Fixed = 5 bytes)
├── bDescriptorType    : 1 byte   → 0x24 (CS_INTERFACE: Class-Specific Interface)
├── bDescriptorSubtype : 1 byte   → 0x00 (HEADER)
└── bcdCDC             : 2 bytes  → USB Class Definitions for Communication Devices Specification Release Number
                                    • 0x0110 = Release 1.10 (Common for ACM)
  • Call Management Functional Descriptor

Call Management Functional Descriptor
├── bLength            : 1 byte   → Total descriptor length (Fixed = 5 bytes)
├── bDescriptorType    : 1 byte   → 0x24 (CS_INTERFACE)
├── bDescriptorSubtype : 1 byte   → 0x01 (CALL_MANAGEMENT)
├── bmCapabilities     : 1 byte   → The capabilities that this configuration supports:
│                                   • Bit 0 = 0: Device does not handle call management itself
│                                   • Bit 0 = 1: Device handles call management itself
│                                   • Bit 1 = 0: Call management commands does not sent over Data Class Interface
│                                   • Bit 1 = 1: Call management commands can be sent over Data Class Interface
│                                   • Bits 2-7: Reserved (Reset to zero)
└── bDataInterface     : 1 byte   → Interface number of Data Class interface optionally used for call management
                                    (Zero if no data interface is used)
  • ACM Functional Descriptor

Abstract Control Management (ACM) Functional Descriptor
├── bLength            : 1 byte   → Total descriptor length (Fixed = 4 bytes)
├── bDescriptorType    : 1 byte   → 0x24 (CS_INTERFACE)
├── bDescriptorSubtype : 1 byte   → 0x02 (ABSTRACT_CONTROL_MANAGEMENT)
└── bmCapabilities     : 1 byte   → The capabilities that this configuration supports:
                                    • Bit 0: Comm_Feature (Supports Set_Comm_Feature, Clear_Comm_Feature, Get_Comm_Feature)
                                    • Bit 1: Line_Coding (Supports Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, Serial_State)
                                    • Bit 2: Send_Break (Supports Send_Break)
                                    • Bit 3: Network_Connection (Supports Network_Connection)
                                    • Bits 4-7: Reserved (Reset to zero)
  • Union Functional Descriptor

Union Functional Descriptor
├── bLength            : 1 byte   → Total descriptor length (3 + Number of slave interfaces)
├── bDescriptorType    : 1 byte   → 0x24 (CS_INTERFACE)
├── bDescriptorSubtype : 1 byte   → 0x06 (UNION)
├── bMasterInterface   : 1 byte   → The interface number of the Communication or Data Class interface
│                                   (Designated as the controlling interface for the union)
└── bSlaveInterface0   : 1 byte   → Interface number of the first subordinate interface in the union
│    ⋮
└── bSlaveInterface(N) : 1 byte   → Interface number of the last subordinate interface in the union

备注

关于 CDC ACM 传输协议规范,请参考 USB CDC ACM Specification

类特定请求

CDC ACM 设备的控制请求分为 标准请求(Standard Requests)类特定请求 (Class-Specific Requests)

本节主要介绍 CDC ACM 特有的 类特定请求,用于实现虚拟串口的串口参数配置、流控信号管理等核心功能。

请求名称

规范要求

描述

SEND_ENCAPSULATED_COMMAND

必须

主机向设备发送封装后的命令,数据格式需遵循设备支持的 控制协议(例如:AT 指令集)。

GET_ENCAPSULATED_RESPONSE

必须

主机从设备获取封装命令的响应数据,响应格式遵循设备支 持的协议。

SET_COMM_FEATURE

可选

设置特定通信特性的状态。具体目标特性由功能选择器指定。

GET_COMM_FEATURE

可选

查询特定通信特性的当前设置状态。

CLEAR_COMM_FEATURE

可选

清除特定通信特性的设置,将其重置为默认状态。

SET_LINE_CODING

可选 (+)

主机配置异步串行通信的线路编码属性(如波特率、停止位、 校验位、数据位)。

GET_LINE_CODING

可选 (+)

主机查询当前配置的异步串行通信线路编码属性。

SET_CONTROL_LINE_STATE

可选

主机控制 RS-232/V.24 标准的控制信号状态(如 DTR 和 RTS 信号电平)。用于流控或复位。

SEND_BREAK

可选

主机请求设备在发送端生成一段持续时间的“断开”(Break) 信号,模拟 RS-232 风格的线路中断。

备注

  • 上述请求均属于 通信类(Communications Class) 特定请求。

  • 对于 模拟调制解调器(Analog Modem) 应用,虽然规范将标记为 (+) 的请求列为可选,但 强烈建议 实现这些请求以保证兼容性。

类驱动

驱动描述符结构

本节展示了驱动层定义的 CDC ACM 类特定描述符结构体。这些结构体对应于 USB 协议规范中的标准描述符定义。

Device Descriptor
└─ USB Version 2.00 (CDC ACM)

Configuration Descriptor (Interfaces 2)
│
├─ Communication Interface (IF 0, CCI)
│  ├─ Header Functional (CDC 1.10)
│  ├─ Call Management Functional (Data IF=1, Handled by Host)
│  ├─ ACM Functional (Cap=0x02: Line Coding & Serial State)
│  ├─ Union Functional (Master=0, Slave=1)
│  └─ Endpoint: INTR IN, maxpkt=HS_INTR_SIZE, Interval=HS_Interval
│
└─ Data Interface (IF 1, DCI)
   ├─ Endpoint: BULK OUT, maxpkt=0x0200 (512 bytes)
   └─ Endpoint: BULK IN,  maxpkt=0x0200 (512 bytes)

Device Qualifier Descriptor
└─ USB 2.0

Other Speed Configuration Descriptor (Interfaces 2)
│
├─ Communication Interface (IF 0, CCI)
│  ├─ Header Functional (CDC 1.10)
│  ├─ Call Management Functional (Data IF=1, Handled by Host)
│  ├─ ACM Functional (Cap=0x02: Line Coding & Serial State)
│  ├─ Union Functional (Master=0, Slave=1)
│  └─ Endpoint: INTR IN, maxpkt=FS_INTR_SIZE, Interval=FS_Interval
│
└─ Data Interface (IF 1, DCI)
   ├─ Endpoint: BULK OUT, maxpkt=0x0040 (64 bytes)
   └─ Endpoint: BULK IN,  maxpkt=0x0040 (64 bytes)

类特定请求实现

驱动已实现了 CDC ACM 规范定义的核心类特定请求(Class-Specific Requests),主要包括:

  • SET_LINE_CODING

  • GET_LINE_CODING

  • SET_CONTROL_LINE_STATE

备注

开发者可参考现有实现来扩展其他类型的请求。CDC ACM 驱动源码路径: {SDK}/component/usb/device/cdc_acm

端点配置

端点

数量

描述

控制 IN/OUT 端点

1

EP0,用于处理 USB 主机发送的标准请求及 CDC 类特定请求。

中断 IN 端点

1

用于向 USB 主机发送串口状态通知(SERIAL_STATE)。

批量 OUT 端点

1

用于接收来自 USB 主机的下行数据流。

批量 IN 端点

1

用于向 USB 主机发送上行数据流。

API 说明

驱动 API

应用示例

应用设计

本节概述 CDC ACM 驱动的完整使用流程,涵盖驱动加载、热插拔管理、数据回显(Echo)处理及虚拟串口参数配置等核心环节。

加载驱动

定义配置结构体并注册回调函数,随后调用初始化接口,加载 USB 设备核心及 CDC ACM 类驱动。

// Do not change the settings unless indeed necessary
#define CONFIG_CDC_ACM_BULK_IN_XFER_SIZE            2048U
#define CONFIG_CDC_ACM_BULK_OUT_XFER_SIZE           2048U

static usbd_config_t cdc_acm_cfg = {
    .speed = CONFIG_USBD_CDC_ACM_SPEED,
    .isr_priority = INT_PRI_MIDDLE,
    .intr_use_ptx_fifo  = 0U,
};

static usbd_cdc_acm_cb_t cdc_acm_cb = {
    .init = cdc_acm_cb_init,                       /* USB init callback */
    .deinit = cdc_acm_cb_deinit,                   /* USB deinit callback */
    .setup = cdc_acm_cb_setup,                     /* USB setup callback */
    .received = cdc_acm_cb_received,               /* USB received callback */
    .status_changed = cdc_acm_cb_status_changed,   /* USB status change callback */
};

int ret = 0;

/**
    * Initialize USB device core driver with configuration.
    * param[in] cfg: USB device configuration.
    * return 0 on success, non-zero on failure.
    */
ret = usbd_init(&cdc_acm_cfg);
if (ret != HAL_OK) {
    return;
}

/**
    * Initializes class driver with application callback handler.
    * param[in] bulk_out_xfer_size: BULK OUT xfer buffer malloc length.
    * param[in] bulk_in_xfer_size: BULK IN xfer buffer malloc length.
    * param[in] cb: Pointer to the user-defined callback structure.
    * return 0 on success, non-zero on failure.
    */
ret = usbd_cdc_acm_init(CONFIG_CDC_ACM_BULK_OUT_XFER_SIZE, CONFIG_CDC_ACM_BULK_IN_XFER_SIZE, &cdc_acm_cb);
if (ret != HAL_OK) {
    /**
        * Deinitialize USB device core driver.
        * return 0 on success, non-zero on failure.
        */
    usbd_deinit();

    return;
}

热插拔事件处理

通过注册 status_changed 回调函数来监听 USB 连接状态变化(连接/断开)。建议使用信号量(Semaphore)通知专用任务线程进行处理,避免在中断上下文中执行耗时操作。

参考 设备连接状态检测 获取更多细节,下面是示例代码:

/* USB status change callback */
static usbd_cdc_acm_cb_t cdc_acm_cb = {
    .status_changed = cdc_acm_cb_status_changed
};

/* Callback executed in ISR context */
static void cdc_acm_cb_status_changed(u8 old_status, u8 status)
{
    RTK_LOGS(TAG, RTK_LOG_INFO, "Status change: %d -> %d \n", old_status, status);

    cdc_acm_attach_status = status;
    rtos_sema_give(cdc_acm_attach_status_changed_sema);
}

/* Thread handling the state machine */
static void cdc_acm_hotplug_thread(void *param)
{
    int ret = 0;
    UNUSED(param);

    for (;;) {
        if (rtos_sema_take(cdc_acm_attach_status_changed_sema, RTOS_SEMA_MAX_COUNT) == RTK_SUCCESS) {
                if (cdc_acm_attach_status == USBD_ATTACH_STATUS_DETACHED) {
                    RTK_LOGS(TAG, RTK_LOG_INFO, "DETACHED\n");

                    /* Clean up resources */
                    usbd_cdc_acm_deinit();
                    ret = usbd_deinit();
                    if (ret != 0) {
                        break;
                    }

                    /* Re-initialize for next connection */
                    ret = usbd_init(&cdc_acm_cfg);
                    if (ret != 0) {
                        break;
                    }
                    ret = usbd_cdc_acm_init(CONFIG_CDC_ACM_BULK_OUT_XFER_SIZE, CONFIG_CDC_ACM_BULK_IN_XFER_SIZE, &cdc_acm_cb);
                    if (ret != 0) {
                        usbd_deinit();
                        break;
                    }
                } else if (cdc_acm_attach_status == USBD_ATTACH_STATUS_ATTACHED) {
                    RTK_LOGS(TAG, RTK_LOG_INFO, "ATTACHED\n");
                } else {
                    RTK_LOGS(TAG, RTK_LOG_INFO, "INIT\n");
                }
        }
    }
    RTK_LOGS(TAG, RTK_LOG_INFO, "Hotplug thread fail\n");
    rtos_task_delete(NULL);
}

数据收发处理

当 CDC ACM 枚举成功后,主机(Host)通过虚拟串口发送数据。驱动支持同步与异步两种数据处理模式,由宏 CONFIG_USBD_CDC_ACM_ASYNC_XFER 控制。

  • 数据接收回调

    所有来自主机的数据通过 cdc_acm_cb_received 回调函数传入。

  • 同步回显 (Sync Echo)

    若未开启异步传输,在接收回调中直接调用 usbd_cdc_acm_transmit() 将接收到的数据原样发回主机。

  • 异步传输 (Async Transfer)

    若开启异步传输,接收到的数据将被存入 cdc_acm_async_xfer_buf 环形缓冲区,并通过信号量唤醒发送线程 cdc_acm_xfer_thread。该线程负责分包发送数据,以避免在中断上下文中进行耗时操作或阻塞。

Sync Mode:
/* In callback: Echo immediately */
static int cdc_acm_cb_received(u8 *buf, u32 len)
{
    /* Directly transmit received data back to host */
    return usbd_cdc_acm_transmit(buf, len);
}

备注

完整的数据收发逻辑请参考 SDK 示例代码:{SDK}/example/usb/usbd_cdc_acm/example_usbd_cdc_acm.c

卸载驱动

在不再需要 CDC ACM 功能或系统关机时,按加载驱动的反序释放资源。

/* Deinitialize CDC ACM class driver. */
usbd_cdc_acm_deinit();

/* Deinitialize USB device core driver. */
usbd_deinit();

运行方式

本节介绍了一个完整的 USB CDC ACM(虚拟串口)回显示例,该示例演示了如何通过 CDC ACM 协议栈实现 PC 与开发板之间的双向字符通信。

该示例代码路径: {SDK}/example/usb/usbd_cdc_acm,可作为 USB 转串口透传或命令行交互界面(CLI)的基础参考。

配置与编译

  • 编译与烧录

    在 SDK 根目录下执行以下命令以配置环境,选择目标 SoC,编译工程,然后将生成的 Image 文件烧录至开发板。

    # Initialize environment (required for every new terminal)
    source env.sh or env.bat(Windows system)
    
    # Select Target SoC (replace xxx with your specific SoCs)
    ameba.py soc xxx
    
    ameba.py build -a usbd_cdc_acm -p
    
  • Menuconfig 配置确认

    若编译失败,请执行 ameba.py menuconfig,确认已选择 USBD CDC ACM

    - Choose `CONFIG USB --->`:
    
        [*] Enable USB
            USB Mode (Device)  --->
        [*] CDC ACM
    

结果验证

  • 启动设备

    重启开发板,观察串口日志,应显示如下启动信息:

[ACM-I] USBD CDC ACM demo start
  • 连接主机

    使用 USB 线缆将开发板连接至 PC(如 Windows 电脑)

  • 串口通信测试

    启动任意串口调试工具(例如 Tera Term 或 Realtek Trace Tool),打开 Ameba 开发板 USB 端口对应的虚拟串口。

    尝试向开发板发送任意字符消息,观察终端界面,开发板应能将接收到的消息原样回显(Echo)至主机。

备注

针对 Windows 7/XP 主机用户,系统可能无法自动安装驱动,请手动安装 CDC ACM 驱动文件 RtkUsbCdcAcmSetup.INF

在安装前,请务必确认 INF 文件中包含当前 CDC ACM 类所使用的 VID/PID 值,例如:

[DeviceList]
%DESCRIPTION%=DriverInstall, USB\VID_0BDA&PID_8720
%DESCRIPTION%=DriverInstall, USB\VID_0BDA&PID_8721
%DESCRIPTION%=DriverInstall, USB\VID_0BDA&PID_8722
%DESCRIPTION%=DriverInstall, USB\VID_0BDA&PID_8730
%DESCRIPTION%=DriverInstall, USB\VID_0BDA&PID_8006
%DESCRIPTION%=DriverInstall, USB\VID_0BDA&PID_8061
; Add support for new VID/PID