ESP32S2应用开发——USB通信(CDC类)
目录
- ESP32S2应用开发——USB通信(CDC类)
- 前言
- 1 硬件介绍
- 1.1 硬件连接
- 2 软件开发
- 2.1 安装开发板
- 2.2 安装库
- 2.3 运行示例代码
- 2.4 USB传输速度测试
- 结束语
前言
ESP32-S2是继ESP32之后新出的一款的MCU,而USB接口是ESP32-S2的一大特色,虽然使用的只是USB1.1协议,但是相比于串口而言传输速度还是要快很多的。对于音频或者视频等数据的传输,使用usb明显是比串口有优势的。
因为前段时间项目需求,需要用到ESP32-S2的USB,于是就花了些时间研究了一下,发现网上关于ESP32-S2 USB的介绍很少而且大多资料都过时了,于是就有了这篇博客。
好了,废话不多说了,马上开始讲解。
1 硬件介绍
本文的硬件配置如下:
模块 | 型号 | 说明 |
ESP32-S2 | ESP32-S2-WROVER | 这是乐鑫的一款模组,内部主要是用乐鑫的ESP32-S2再加上一个4M FLASH和2M PSRAM组成,开发板用的是乐鑫的ESP32-S2-SAOLA |
ESP32-S2的引脚很多我就不一一介绍了,这一讲主要用到的UART0和USB(GPIO19,GPIO20)。
1.1 硬件连接
我这里用的是开发板,硬件连接比较简单。
UART0通过USB转TTL芯片连接到PC端。
USB通过GPIO19和GPIO20直连PC端的USB接口。
引脚 | 描述 | 说明 |
GPIO19 | USB D- | USB信号线,直连PC端即可,不需要接转换芯片 |
GPIO20 | USB D+ | USB信号线,直连PC端即可,不需要接转换芯片 |
U0TXD | 串口TX | 方便调试使用,需要接USB转换TTL才能连接到PC端 |
U0RXD | 串口RX | 方便调试使用,需要接USB转换TTL才能连接到PC端 |
2 软件开发
2.1 安装开发板
关于ESP32-S2 Arduino的环境搭建我之前出过教程了,这里就不多说了,不懂的同学可以先看下我之前的博客。
2.2 安装库
打开Arduino IDE,依次打开 工具 -> 管理库…
在搜索框输入需要安装的库名称,找到对应的库,点击安装即可。
本文需要使用的Arduino库如下:
Arduino库 | 版本 | 说明 |
ESP32TinyUSB | 1.3.4 | USB相关库,使用该库要确保ESP32库版本在2.0.0以上 |
esp32 | 2.0.1 | 建议使用该版本,v2.0.2有个usb相关的结构体定义改了,跟ESP32TinyUSB库不兼容。 如果非要用2.0.2以上版本就需要在ESP32TinyUSB和esp32两者之前选择一个把client_event_callback的定义改掉 |
2.3 运行示例代码
ESP32TinyUSB库自带很多examples,我们打开一个cdc的示例代码先测试一下USB通讯。
示例代码如下:
/**
* Simple CDC device connect with putty to use it
* author: chegewara
* Serial - used only for logging
* Serial1 - can be used to control GPS or any other device, may be replaced with Serial
*/
#include "cdcusb.h"
#if CFG_TUD_CDC
CDCusb USBSerial;
class MyUSBCallbacks : public CDCCallbacks {
void onCodingChange(cdc_line_coding_t const* p_line_coding)
{
int bitrate = USBSerial.getBitrate();
Serial.printf("new bitrate: %d\n", bitrate);
}
bool onConnect(bool dtr, bool rts)
{
Serial.printf("connection state changed, dtr: %d, rts: %d\n", dtr, rts);
return true; // allow to persist reset, when Arduino IDE is trying to enter bootloader mode
}
void onData()
{
int len = USBSerial.available();
Serial.printf("\nnew data, len %d\n", len);
uint8_t buf[len] = {};
USBSerial.read(buf, len);
Serial.write(buf, len);
}
void onWantedChar(char c)
{
Serial.printf("wanted char: %c\n", c);
}
};
void setup()
{
Serial.begin(115200);
USBSerial.setCallbacks(new MyUSBCallbacks());
USBSerial.setWantedChar('x');
if (!USBSerial.begin())
Serial.println("Failed to start CDC USB stack");
}
void loop()
{
while (Serial.available())
{
int len = Serial.available();
char buf1[len];
Serial.read(buf1, len);
int a = USBSerial.write((uint8_t*)buf1, len);
}
}
#endif
运行结果如下:
设备管理器能看到两个com口(一个是串口转换芯片,一个是ESP32-S2的USB)。
用串口助手先打开UART对应的端口,波特率115200。再打开一个串口助手,连接USB虚拟串口对应的com口,此时能看到UART会出现一些log。
USB连接上之后,两个串口助手之间可以互发数据,说明USB通讯是没问题的。
提示:如果烧录程序之后出现一直重启的现象,可能是因为MCU原本出厂的固件有一部分没有被擦除导致的,可以使用乐鑫的flash烧录工具对整个MCU进行擦除之后再烧录Arduino的程序。
2.4 USB传输速度测试
简单写一个测试代码用来测试USB数据传输的速度。
示例代码如下:
#include "cdcusb.h"
#include "Arduino.h"
#include <esp_heap_caps.h>
#define FILE_SIZE 971240 // 测试文件的大小
uint8_t *rx_buf;
uint32_t rx_num = 0;
uint8_t first_time_flag = 1;
long lTime;
CDCusb CDCUSBSerial;
class MyCDCCallbacks : public CDCCallbacks {
void onCodingChange(cdc_line_coding_t const* p_line_coding)
{
int bitrate = CDCUSBSerial.getBitrate();
Serial.printf("new bitrate: %d\n", bitrate);
}
bool onConnect(bool dtr, bool rts)
{
Serial.printf("connection state changed, dtr: %d, rts: %d\n", dtr, rts);
return true; // allow to persist reset, when Arduino IDE is trying to enter bootloader mode
}
void onData()
{
if(first_time_flag)
{
first_time_flag = 0;
lTime = micros();
}
int len = CDCUSBSerial.available();
CDCUSBSerial.read(&rx_buf[rx_num], len);
rx_num += len;
if(rx_num >= FILE_SIZE)
{
lTime = micros() - lTime;
Serial.printf("time: %f s \n", lTime / 1000000.0);
Serial.printf("speed:%f kb/s", ((float)FILE_SIZE / 1024.0) / (lTime / 1000000.0));
first_time_flag = 1;
rx_num = 0;
}
}
};
void setup()
{
Serial.begin(115200);
if (!CDCUSBSerial.begin())
Serial.println("Failed to start CDC USB stack");
CDCUSBSerial.setCallbacks(new MyCDCCallbacks());
rx_buf = (uint8_t*)ps_malloc(FILE_SIZE);
}
void loop()
{
}
通过串口助手往USB发送一个大文件(971240字节,约948.5kb)。
提示:这里串口助手打开文件时显示的时间是按当前波特率估算出来的,但是实际上我们用的是虚拟串口,USB传输是没有波特率这个参数的,这里波特率不管设置为多少,实际的速度都一样,都是以USB传输速度为准。
通过ESP32-S2的串口0打印实际的传输的时间和速度。
经过sscom这个串口助手传输文件测试,ESP32-S2 USB的最大传输速度在190kb/s左右,实际上加上一些应用代码之后,速度会有所下降,约160kb/s左右(这个速度跟具体的应用有关)。
因为USB接收是中断处理的,MCU如果一直处于闲置状态,那USB的数据传输速度可以达到最大。反之,MCU如果一直在运行其他应用代码,那么在接收USB数据时只能通过频繁的中断来完成数据的读取,此时接收的效率明显是要下降一些的。另外,传输速度跟MCU的接收方式也有关系,USB1.1最大支持一次接收64字节,所以MCU在进入回调函数时,应该根据把当前收到的所有数据一次性读取完,而不是每次回调只读一个字节。
后期测试补充:
在使用sscom这个串口助手时,文件的传输速度跟设置的波特率无关,但是后来用另外一个串口助手(UartAssist)时发现用这个工具设置的波特率跟实际传输速度有关联,这就很奇怪了,因为这个只是虚拟串口,实际上是按照USB1.1协议来传输数据的,理论上不应该出现这种情况的。然后我测试了多种不同的波特率,发现波特率较小时,实际传输速度与波特率基本一致,波特率越大速度越快,当波特率增大到2M时,速度与之前sscom串口助手测试的速度接近。继续增大波特率到某个值之后,不管波特率设置多少,速度都不再增大了。最大传输速度在270kb/s左右。
从目前的现象来看,USB的传输速度跟串口工具本身也有关系,具体的原因还没搞清楚,有懂的老哥解答一下吗?
结束语
好了,关于ESP32-S2 USB的使用就介绍到这里。如果这篇文章对你有帮助,可以点赞收藏,如果还有什么问题,欢迎在评论区留言或者私信给我。
补充说明:
最近我经常收到一些私信,这是不是真的USB?这是串口转USB吧?
所以我这里统一补充说明一下,如何区分USB CDC和串口。
CDC类USB和HID不同,它枚举出来的设备确实是一个串行设备,看着是很像串口,但实际上是不一样的。
主要有以下几个区别:
区别 | USB | 串口 |
1 | 两个USB之间是直连的,不需要转换电平 | 串口是TTL电平的,如果没有转换芯片,是没法直接连接PC端的USB接口的。常用的转换IC如:CH340、CP2102、PL2303、FT232、MAX232等 |
2 | 传输速度快 | 传输速度慢 |
3 | 遵循USB协议(可通过逻辑分析仪抓取和解析) | 遵循串口协议(可通过逻辑分析仪抓取和解析) |
4 | USB有枚举过程(可通过BusHound抓取通讯过程) | 串口不存在枚举过程 |
Arduino开发教程汇总: