ESP32-USB Serial/JTAG Controller使用

ESP32-USB Serial/JTAG Controller使用

  • 概述
  • CDC-ACM功能描述
  • 环境说明
  • 硬件查询方式使用
    • 关键函数说明
    • 示例代码
  • 官方中断方式使用
    • 关键函数说明
      • 包含头文件
      • 安装卸载驱动
      • 收发数据
    • 示例程序

概述

ESP32-c3内部带有1个USB Serial/JTAG控制器,可用于下载flash程序、JTAG调试、虚拟串口通信等功能。硬件框图如下:
ESP32-USB Serial/JTAG Controller使用_第1张图片
其主要特性如下:

  • 支持usb全速设备(12Mbps),不支持高速(480Mbps)
  • 固定为CDC-ACM设备(Communication Device Class - Abstract Control Model)
  • 64byte硬件缓冲区
  • 大多数操作系统即插即用

CDC-ACM功能描述

由下表可见,ESP32-C3只能响应主机设置RTS/DTR指令,以实现芯片复位和程序下载,设置波特率无效。
ESP32-USB Serial/JTAG Controller使用_第2张图片
RTS/DTR状态说明:
ESP32-USB Serial/JTAG Controller使用_第3张图片
esp32-c3通过内部APB总线与CDC-ACM连接,cpu通过读写寄存器判断USB_SERIAL_JTAG_SERIAL_OUT_EP_DATA_AVAIL1(表示接收buf有数据)接收主机发来的数据;并可通过判断USB_REG_SERIAL_IN_EP_DATA_FREE1(表示发送buf未满)可向发送buf写入数据,随后设置USB_SERIAL_JTAG_WR_DONE==1,以发送buf数据到主机。

环境说明

  • 软件采用IDF4.4.2版本
  • 硬件采用esp32-c3芯片
  • 硬件需具备usb和uart接口,uart配置用于控制台打印信息

注意: 使用该功能前需要禁止控制台打印到USB,否则控制台打印信息会和usb打印信息混在一起,配置如下:
ESP32-USB Serial/JTAG Controller使用_第4张图片

硬件查询方式使用

关键函数说明

#include "hal/usb_serial_jtag_ll.h"

//检测接收buf是否有数据
static inline int usb_serial_jtag_ll_rxfifo_data_available(void)//返回:0-没数据  1-有数据

//从接收buf读取数据,返回值:实际接收的字节数
static inline int usb_serial_jtag_ll_read_rxfifo(
		uint8_t *buf, //接收数据指针
		uint32_t rd_len)//读取长度,最大64,当设置为最大值64时,会将接收buf读空,并返回读取的实际字节数

//写数据到发送buf
static inline uint32_t usb_serial_jtag_ll_write_txfifo(
		const uint8_t *buf, //发送数据指针
		uint32_t wr_len)//写入长度,最大64,如果写入过程中,发送buf满了,则函数退出并返回写入的实际字节数

//刷新发送buf
static inline void usb_serial_jtag_ll_txfifo_flush(void)//即发送buf数据到主机

示例代码

本示例代码采用uart0输出调试信息,基本功能是将usb发来的任意数据进行环回发出。该代码采用单任务循环检查接收buf,占用cpu资源,后期改成中断形式更佳,代码如下:

#include 
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"

#include "string.h"
#include "hal/usb_serial_jtag_ll.h"

void mytask1(void *pvParameter)
{
    uint8_t *rxbuf;
    int cnt;
    rxbuf = (uint8_t *)malloc(64);
    int rxcnt;
    while (1)
    {
        if (usb_serial_jtag_ll_rxfifo_data_available())//等待接收buf非空
        {
            rxcnt = usb_serial_jtag_ll_read_rxfifo(rxbuf, 64);//接收buf中的所有数据
            cnt = (int)usb_serial_jtag_ll_write_txfifo((const uint8_t *)rxbuf, rxcnt);//将接收数据回环发送
            usb_serial_jtag_ll_txfifo_flush();//刷新发送buf
            printf("Send %d characters to host \n", cnt);//在调试串口打印发送的数量
        }
        vTaskDelay(pdMS_TO_TICKS(10));
    }
    free(rxbuf);//与malloc成对使用
    vTaskDelete(NULL);
}
void app_main(void)
{
    xTaskCreate(mytask1, "mytask1", 1024 * 5, NULL, 1, NULL);

}

效果:
在调试接口打印信息:

Send 11 characters to host
Send 11 characters to host
Send 11 characters to host
Send 11 characters to host
Send 11 characters to host
Send 11 characters to host

在usb接口打印信息如下:

[21:28:37.884]发→◇hello world□
[21:28:37.884]收←◆hello world
[21:28:38.888]发→◇hello world□
[21:28:38.888]收←◆hello world
[21:28:39.886]发→◇hello world□
[21:28:39.886]收←◆hello world

官方中断方式使用

关键函数说明

包含头文件

#include "driver/usb_serial_jtag.h"

安装卸载驱动

由于硬件buf为64byte,环形buf至少应能容纳主机一次发送的最大64byte数据,因此其大小应大于64字节。

//环形buf配置结构体
usb_serial_jtag_driver_config_t usb_cdc = {
    .rx_buffer_size = 65, //环形buf应大于64
    .tx_buffer_size = 65  //环形buf应大于64
};
//安装usb_serial_jtag驱动
esp_err_t usb_serial_jtag_driver_install(usb_serial_jtag_driver_config_t *usb_serial_jtag_config)//参数为环形buf配置的结构体地址

//卸载usb_serial_jtag驱动
esp_err_t usb_serial_jtag_driver_uninstall(void)

收发数据

收发数据函数实际读写环形buf,该驱动安装后会启用中断,对接收来说,当有数据到来时触发中断,并从硬件buf拷贝数据到环形buf。
当环形buf溢出时,主机仍能够发送数据,但会导致数据丢失。

//接收主机发送的数据,返回值为接收到的数据量
int usb_serial_jtag_read_bytes(
		void* buf, //接收数据指针
		uint32_t length, //接收数据长度
		TickType_t ticks_to_wait)//超时时间,portMAX_DELAY表示永久阻塞

//向主机发送数据,返回值为实际发送的数据量
int usb_serial_jtag_write_bytes(
		const void* src, //发送数据指针
		size_t size, //发送数据大小
		TickType_t ticks_to_wait)//超时时间,portMAX_DELAY表示永久阻塞

示例程序

#include 
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"

#include "string.h"
#include "driver/usb_serial_jtag.h"

void mytask1(void *pvParameter)
{
    uint8_t *rxbuf;
    int sendcnt;
    rxbuf = (uint8_t *)malloc(64);
    int rxcnt;
    while (1)
    {
        rxcnt = usb_serial_jtag_read_bytes((void *)rxbuf, 10, portMAX_DELAY); //阻塞当前任务,直到接收数据
        sendcnt = (int)usb_serial_jtag_write_bytes((const void *)rxbuf, rxcnt, portMAX_DELAY);
        printf("task1: Send %d characters to host \n", sendcnt);
        //vTaskDelay(pdMS_TO_TICKS(1000));
    }
    free(rxbuf); //释放缓冲区
}

void app_main(void)
{
    usb_serial_jtag_driver_config_t usb_cdc = {
        .rx_buffer_size = 65, //环形buf应大于64
        .tx_buffer_size = 65  //环形buf应大于64
    };
    TaskHandle_t task1_handler;
    ESP_ERROR_CHECK(usb_serial_jtag_driver_install(&usb_cdc)); //安装usb_serial驱动
    xTaskCreate(mytask1, "mytask1", 1024 * 5, NULL, 1, &task1_handler);
    printf("start loop back \n ");
    vTaskDelay(pdMS_TO_TICKS(30000)); //运行30s后退出任务1
    vTaskDelete(task1_handler);
    usb_serial_jtag_driver_uninstall(); //卸载usb_serial驱动
    printf("stop loop back \n ");
}

该程序在任务1中对usb接口进行了数据回环,启动后,主机可通过usb虚拟串口收发数据。

为验证环形buf溢出的情况,将任务1中的1s延迟打开,模拟处理时间,主机循环每10ms发1包数据,结果如下:

ESP32-USB Serial/JTAG Controller使用_第5张图片
环形buf只开了65个字节,因此返回大量数据丢失。调试接口打印信息为:

start loop back
task1: Send 10 characters to host
task1: Send 10 characters to host
task1: Send 10 characters to host
task1: Send 10 characters to host
task1: Send 10 characters to host
task1: Send 10 characters to host
task1: Send 5 characters to host
task1: Send 7 characters to host
stop loop back

你可能感兴趣的:(#,ESP32,单片机)