加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
    • 1 硬件介紹
    • 2 軟件開發(fā)
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

ESP32-S2應(yīng)用開發(fā)——USB通信(CDC類)

10/27 07:14
6718
閱讀需 16 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

ESP32-S2是繼ESP32之后新出的一款的MCU,而USB接口是ESP32-S2的一大特色,雖然使用的只是USB1.1協(xié)議,但是相比于串口而言傳輸速度還是要快很多的。對(duì)于音頻或者視頻等數(shù)據(jù)的傳輸,使用usb明顯是比串口有優(yōu)勢(shì)的。

因?yàn)榍岸螘r(shí)間項(xiàng)目需求,需要用到ESP32-S2的USB,于是就花了些時(shí)間研究了一下,發(fā)現(xiàn)網(wǎng)上關(guān)于ESP32-S2 USB的介紹很少而且大多資料都過時(shí)了,于是就有了這篇博客。

好了,廢話不多說了,馬上開始講解。

1 硬件介紹

本文的硬件配置如下:

模塊 型號(hào) 說明
ESP32-S2 ESP32-S2-WROVER 這是樂鑫的一款模組,內(nèi)部主要是用樂鑫的ESP32-S2再加上一個(gè)4M FLASH和2M PSRAM組成,開發(fā)板用的是樂鑫的ESP32-S2-SAOLA

ESP32-S2的引腳很多我就不一一介紹了,這一講主要用到的UART0和USB(GPIO19,GPIO20)。

1.1 硬件連接

我這里用的是開發(fā)板,硬件連接比較簡(jiǎn)單。

UART0通過USB轉(zhuǎn)TTL芯片連接到PC端。

USB通過GPIO19和GPIO20直連PC端的USB接口。

引腳 描述 說明
GPIO19 USB D- USB信號(hào)線,直連PC端即可,不需要接轉(zhuǎn)換芯片
GPIO20 USB D+ USB信號(hào)線,直連PC端即可,不需要接轉(zhuǎn)換芯片
U0TXD 串口TX 方便調(diào)試使用,需要接USB轉(zhuǎn)換TTL才能連接到PC端
U0RXD 串口RX 方便調(diào)試使用,需要接USB轉(zhuǎn)換TTL才能連接到PC端

2 軟件開發(fā)

2.1 安裝開發(fā)板

關(guān)于ESP32-S2 Arduino的環(huán)境搭建我之前出過教程了,這里就不多說了,不懂的同學(xué)可以先看下我之前的博客。

2.2 安裝庫(kù)

打開Arduino IDE,依次打開 工具 -> 管理庫(kù)…

在搜索框輸入需要安裝的庫(kù)名稱,找到對(duì)應(yīng)的庫(kù),點(diǎn)擊安裝即可。

本文需要使用的Arduino庫(kù)如下:

Arduino庫(kù) 版本 說明
ESP32TinyUSB 1.3.4 USB相關(guān)庫(kù),使用該庫(kù)要確保ESP32庫(kù)版本在2.0.0以上
esp32 2.0.1 建議使用該版本,v2.0.2有個(gè)usb相關(guān)的結(jié)構(gòu)體定義改了,跟ESP32TinyUSB庫(kù)不兼容。
如果非要用2.0.2以上版本就需要在ESP32TinyUSB和esp32兩者之前選擇一個(gè)把client_event_callback的定義改掉
在這里插入圖片描述

2.3 運(yùn)行示例代碼

ESP32TinyUSB庫(kù)自帶很多examples,我們打開一個(gè)cdc的示例代碼先測(cè)試一下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: %dn", bitrate);
    }

    bool onConnect(bool dtr, bool rts)
    {
        Serial.printf("connection state changed, dtr: %d, rts: %dn", 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 %dn", len);
        uint8_t buf[len] = {};
        USBSerial.read(buf, len);
        Serial.write(buf, len);
    }

    void onWantedChar(char c)
    {
        Serial.printf("wanted char: %cn", 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

在這里插入圖片描述

運(yùn)行結(jié)果如下:

設(shè)備管理器能看到兩個(gè)com口(一個(gè)是串口轉(zhuǎn)換芯片,一個(gè)是ESP32-S2的USB)。

在這里插入圖片描述

用串口助手先打開UART對(duì)應(yīng)的端口,波特率115200。再打開一個(gè)串口助手,連接USB虛擬串口對(duì)應(yīng)的com口,此時(shí)能看到UART會(huì)出現(xiàn)一些log。

在這里插入圖片描述

USB連接上之后,兩個(gè)串口助手之間可以互發(fā)數(shù)據(jù),說明USB通訊是沒問題的。

在這里插入圖片描述

提示:如果燒錄程序之后出現(xiàn)一直重啟的現(xiàn)象,可能是因?yàn)镸CU原本出廠的固件有一部分沒有被擦除導(dǎo)致的,可以使用樂鑫的flash燒錄工具對(duì)整個(gè)MCU進(jìn)行擦除之后再燒錄Arduino的程序。

2.4 USB傳輸速度測(cè)試

簡(jiǎn)單寫一個(gè)測(cè)試代碼用來測(cè)試USB數(shù)據(jù)傳輸的速度。

示例代碼如下:

#include "cdcusb.h"
#include "Arduino.h"
#include <esp_heap_caps.h>

#define FILE_SIZE 971240   // 測(cè)試文件的大小
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: %dn", bitrate);
    }

    bool onConnect(bool dtr, bool rts)
    {
        Serial.printf("connection state changed, dtr: %d, rts: %dn", 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發(fā)送一個(gè)大文件(971240字節(jié),約948.5kb)。

提示:這里串口助手打開文件時(shí)顯示的時(shí)間是按當(dāng)前波特率估算出來的,但是實(shí)際上我們用的是虛擬串口,USB傳輸是沒有波特率這個(gè)參數(shù)的,這里波特率不管設(shè)置為多少,實(shí)際的速度都一樣,都是以USB傳輸速度為準(zhǔn)。

在這里插入圖片描述

通過ESP32-S2的串口0打印實(shí)際的傳輸?shù)臅r(shí)間和速度。

在這里插入圖片描述

經(jīng)過sscom這個(gè)串口助手傳輸文件測(cè)試,ESP32-S2 USB的最大傳輸速度在190kb/s左右,實(shí)際上加上一些應(yīng)用代碼之后,速度會(huì)有所下降,約160kb/s左右(這個(gè)速度跟具體的應(yīng)用有關(guān))。

因?yàn)閁SB接收是中斷處理的,MCU如果一直處于閑置狀態(tài),那USB的數(shù)據(jù)傳輸速度可以達(dá)到最大。反之,MCU如果一直在運(yùn)行其他應(yīng)用代碼,那么在接收USB數(shù)據(jù)時(shí)只能通過頻繁的中斷來完成數(shù)據(jù)的讀取,此時(shí)接收的效率明顯是要下降一些的。另外,傳輸速度跟MCU的接收方式也有關(guān)系,USB1.1最大支持一次接收64字節(jié),所以MCU在進(jìn)入回調(diào)函數(shù)時(shí),應(yīng)該根據(jù)把當(dāng)前收到的所有數(shù)據(jù)一次性讀取完,而不是每次回調(diào)只讀一個(gè)字節(jié)。

后期測(cè)試補(bǔ)充:

在使用sscom這個(gè)串口助手時(shí),文件的傳輸速度跟設(shè)置的波特率無關(guān),但是后來用另外一個(gè)串口助手(UartAssist)時(shí)發(fā)現(xiàn)用這個(gè)工具設(shè)置的波特率跟實(shí)際傳輸速度有關(guān)聯(lián),這就很奇怪了,因?yàn)檫@個(gè)只是虛擬串口,實(shí)際上是按照USB1.1協(xié)議來傳輸數(shù)據(jù)的,理論上不應(yīng)該出現(xiàn)這種情況的。然后我測(cè)試了多種不同的波特率,發(fā)現(xiàn)波特率較小時(shí),實(shí)際傳輸速度與波特率基本一致,波特率越大速度越快,當(dāng)波特率增大到2M時(shí),速度與之前sscom串口助手測(cè)試的速度接近。繼續(xù)增大波特率到某個(gè)值之后,不管波特率設(shè)置多少,速度都不再增大了。最大傳輸速度在270kb/s左右。

從目前的現(xiàn)象來看,USB的傳輸速度跟串口工具本身也有關(guān)系,具體的原因還沒搞清楚,有懂的老哥解答一下嗎?

結(jié)束語

好了,關(guān)于ESP32-S2 USB的使用就介紹到這里。如果這篇文章對(duì)你有幫助,可以點(diǎn)贊收藏,如果還有什么問題,歡迎在評(píng)論區(qū)留言或者私信給我。

補(bǔ)充說明:

最近我經(jīng)常收到一些私信,這是不是真的USB?這是串口轉(zhuǎn)USB吧?

所以我這里統(tǒng)一補(bǔ)充說明一下,如何區(qū)分USB CDC和串口。

CDC類USB和HID不同,它枚舉出來的設(shè)備確實(shí)是一個(gè)串行設(shè)備,看著是很像串口,但實(shí)際上是不一樣的。

主要有以下幾個(gè)區(qū)別:

區(qū)別 USB 串口
1 兩個(gè)USB之間是直連的,不需要轉(zhuǎn)換電平 串口是TTL電平的,如果沒有轉(zhuǎn)換芯片,是沒法直接連接PC端的USB接口的。常用的轉(zhuǎn)換IC如:CH340、CP2102、PL2303、FT232、MAX232等
2 傳輸速度快 傳輸速度慢
3 遵循USB協(xié)議(可通過邏輯分析儀抓取和解析) 遵循串口協(xié)議(可通過邏輯分析儀抓取和解析)
4 USB有枚舉過程(可通過BusHound抓取通訊過程) 串口不存在枚舉過程

 

相關(guān)推薦

電子產(chǎn)業(yè)圖譜