4. ESP32S3 使用USB 加载SD_SDIO 当作 U盘使用

本文介绍了如何使用ESP32-S2和ESP32-S3通过USB接口作为U盘使用,包括挂载内部Flash和SPI-SD卡。通过TinyUSB库进行配置和初始化,实现USBMSC和CDC功能,创建无线U盘。此外,文章提到了调整TinyUSBMSCFIFO大小以提高数据传输速度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.ESP32-S2 USB烧录 输出日志
2.ESP32-S2 USB 挂载内部Flash,当作U盘使用,无线U盘
3.ESP32-S2 USB 挂载SPI-SD,当作U盘使用,无线U盘
4. ESP32S3 使用USB 加载SD_SDIO 当作 U盘使用

1.环境搭建,下载USB库

需要IDF-v4.4 的环境,因为后面使用到的tinyusb依赖v4.4

USB库下载链接:github.com/espressif/esp-iot-solution

在这里插入图片描述
将拉取下来的库放到IDF的根目录下
在这里插入图片描述

2.将tinyusb添加至项目中

这里使用 SDMMC 官方例程进行移植

注意:你放置的esp-iot-solution是不是在IDF的根目录下!

set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/esp-iot-solution/components/usb/tinyusb)

在这里插入图片描述

3.Configuration配置

首先将芯片设置为 ESP32S3,否则下面步骤无法操作

3.1 使能 Use TinyUSB Stack

在这里插入图片描述

3.2 Enable TinyUSB MSC

在这里插入图片描述

3.3 Enable TinyUSB CDC 虚拟串口

在这里插入图片描述

4.修改main.c

/* SD card and FAT filesystem example.
   This example code is in the Public Domain (or CC0 licensed, at your option.)
 
   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
 
// This example uses SDMMC peripheral to communicate with SD card.
 
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
#include "driver/sdmmc_host.h"
#include "tusb_msc.h"
#include "tusb_cdc_acm.h"
 
static const char *TAG = "example";
 
 
#define MOUNT_POINT "/sdcard"
static bool usb_install = false;
static bool usb_cdc = false;
static uint8_t buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE + 1];
static void tinyusb_cdc_rx_callback(int itf, cdcacm_event_t *event)
{
    /* initialization */
    size_t rx_size = 0;
 
    printf("%s need = %d\n", __func__, CONFIG_TINYUSB_CDC_RX_BUFSIZE);
    /* read */
    esp_err_t ret = tinyusb_cdcacm_read(itf, buf, CONFIG_TINYUSB_CDC_RX_BUFSIZE, &rx_size);
    if (ret == ESP_OK) {
 
        printf("rx_buf[%s]\n", buf);
 
    } else {
        ESP_LOGE(TAG, "Read error");
    }
 
}
 
void usb_cdc_init(void)
{
	if(usb_install == false)
	{
		tinyusb_config_t tusb_cfg = {
			.descriptor = NULL,
			.string_descriptor = NULL,
			.external_phy = false // In the most cases you need to use a `false` value
		};
		ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg));
		usb_install = true;
	}
 
 
    tinyusb_config_cdcacm_t amc_cfg = { 
        .usb_dev = TINYUSB_USBDEV_0,
        .cdc_port = TINYUSB_CDC_ACM_0,
        .rx_unread_buf_sz = 4096,
        .callback_rx = &tinyusb_cdc_rx_callback, // the first way to register a callback
        .callback_rx_wanted_char = NULL,
        .callback_line_state_changed = NULL,
        .callback_line_coding_changed = NULL
    }; // the configuration uses default values
    ESP_ERROR_CHECK(tusb_cdc_acm_init(&amc_cfg));
	usb_cdc = true;
    ESP_LOGI(TAG, "USB initialization cdc device DONE");
}
 
void usb_msc_init(void)
{
	if(usb_install == false)
	{
		tinyusb_config_t tusb_cfg = {
			.descriptor = NULL,
			.string_descriptor = NULL,
			.external_phy = false // In the most cases you need to use a `false` value
		};
		ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg));
		usb_install = true;
	}
    tinyusb_config_msc_t msc_cfg = {
        .pdrv = 0,
    };
    ESP_ERROR_CHECK(tusb_msc_init(&msc_cfg));
    ESP_LOGI(TAG, "USB initialization msc device DONE");
 
}
void cdc_printf(const char* fmt,...) 
{
	if(usb_cdc == true)
	{
		uint8_t buffer[256] = {0};
		va_list ap;
		va_start(ap,fmt);          			//ap指向fmt的地址
		vsprintf((char *)buffer,fmt,ap);	//vsprintf返回数组的长度
		va_end(ap);
		
		tinyusb_cdcacm_write_queue(0,buffer,strlen((const char *)buffer));
		tud_cdc_n_write_flush(0);
//	tinyusb_cdcacm_write_flush(0, 0);
	}
}
 
void app_main(void)
{
    esp_err_t ret;
 
    // Options for mounting the filesystem.
    // If format_if_mount_failed is set to true, SD card will be partitioned and
    // formatted in case when mounting fails.
    esp_vfs_fat_sdmmc_mount_config_t mount_config = {
#ifdef CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED
        .format_if_mount_failed = true,
#else
        .format_if_mount_failed = false,
#endif // EXAMPLE_FORMAT_IF_MOUNT_FAILED
        .max_files = 5,
        .allocation_unit_size = 16 * 1024
    };
    sdmmc_card_t *card;
    const char mount_point[] = MOUNT_POINT;
    ESP_LOGI(TAG, "Initializing SD card");
 
    // Use settings defined above to initialize SD card and mount FAT filesystem.
    // Note: esp_vfs_fat_sdmmc/sdspi_mount is all-in-one convenience functions.
    // Please check its source code and implement error recovery when developing
    // production applications.
 
    ESP_LOGI(TAG, "Using SDMMC peripheral");
    sdmmc_host_t host = SDMMC_HOST_DEFAULT();
    // This initializes the slot without card detect (CD) and write protect (WP) signals.
    // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
    sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
 
    // To use 1-line SD mode, change this to 1:
    slot_config.width = 4;
    // On chips where the GPIOs used for SD card can be configured, set them in
    // the slot_config structure:
#ifdef SOC_SDMMC_USE_GPIO_MATRIX
    slot_config.clk = GPIO_NUM_14;
    slot_config.cmd = GPIO_NUM_11;
    slot_config.d0 = GPIO_NUM_4;
    slot_config.d1 = GPIO_NUM_45;
    slot_config.d2 = GPIO_NUM_48;
    slot_config.d3 = GPIO_NUM_13;
#endif
 
    // Enable internal pullups on enabled pins. The internal pullups
    // are insufficient however, please make sure 10k external pullups are
    // connected on the bus. This is for debug / example purpose only.
    slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
 
    ESP_LOGI(TAG, "Mounting filesystem");
    ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card);
 
    if (ret != ESP_OK) {
        if (ret == ESP_FAIL) {
            ESP_LOGE(TAG, "Failed to mount filesystem. "
                     "If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
        } else {
            ESP_LOGE(TAG, "Failed to initialize the card (%s). "
                     "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
        }
        return;
    }
    ESP_LOGI(TAG, "Filesystem mounted");
 
    // Card has been initialized, print its properties
    sdmmc_card_print_info(stdout, card);
 
    // Use POSIX and C standard library functions to work with files:
 
    // First create a file.
    const char *file_hello = MOUNT_POINT"/hello.txt";
 
    ESP_LOGI(TAG, "Opening file %s", file_hello);
    FILE *f = fopen(file_hello, "w");
    if (f == NULL) {
        ESP_LOGE(TAG, "Failed to open file for writing");
        return;
    }
    fprintf(f, "Hello %s!\n", card->cid.name);
    fclose(f);
    ESP_LOGI(TAG, "File written");
 
    const char *file_foo = MOUNT_POINT"/foo.txt";
 
    // Check if destination file exists before renaming
    struct stat st;
    if (stat(file_foo, &st) == 0) {
        // Delete it if it exists
        unlink(file_foo);
    }
 
    // Rename original file
    ESP_LOGI(TAG, "Renaming file %s to %s", file_hello, file_foo);
    if (rename(file_hello, file_foo) != 0) {
        ESP_LOGE(TAG, "Rename failed");
        return;
    }
 
    // Open renamed file for reading
    ESP_LOGI(TAG, "Reading file %s", file_foo);
    f = fopen(file_foo, "r");
    if (f == NULL) {
        ESP_LOGE(TAG, "Failed to open file for reading");
        return;
    }
 
    // Read a line from file
    char line[64];
    fgets(line, sizeof(line), f);
    fclose(f);
 
    // Strip newline
    char *pos = strchr(line, '\n');
    if (pos) {
        *pos = '\0';
    }
    ESP_LOGI(TAG, "Read from file: '%s'", line);
    usb_cdc_init();
    usb_msc_init();
    while(1)
    {
        cdc_printf("test\r\n") ;
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    // All done, unmount partition and disable SDMMC peripheral
    // esp_vfs_fat_sdcard_unmount(mount_point, card);
    ESP_LOGI(TAG, "Card unmounted");
}

编译烧录
使用的SDIO接口,但是速度都点慢。之前使用SPI_SD 上次速度都有600~300kb/s左右,之后慢慢研究。。。
在这里插入图片描述

补充:将 MSC FIFO size 修改成 4096 上传/下载的速度立马提升几倍
在这里插入图片描述

在这里插入图片描述
还有虚拟了一个串口,可以收发,就不演示了

感谢 :https://blog.csdn.net/wang123qweasd/article/details/127382780

评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值