ESP32 S2 使用Arduino实现ESPTingUSB的步骤-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 7621|回复: 2

ESP32 S2 使用Arduino实现ESPTingUSB的步骤

[复制链接]
发表于 2021-2-19 23:19 | 显示全部楼层 |阅读模式
本帖最后由 topdog 于 2021-2-21 12:48 编辑

ESP32-S2 是乐鑫生产的一款高度集成、高性价比、低功耗、主打安全的单核 Wi-Fi SoC,具备强大的功能和丰富的 IO 接口。ESP32-S2 集成了丰富的外围设备,有 43 个可编程 GPIO,可以灵活配置为 USB OTG、LCD 接口、摄像头接口、SPI、I2S、UART、ADC、DAC 等常用功能。ESP32-S2 具有 LCD 接口和 14 个可配置的电容触摸 GPIO,可为基于触摸屏和触摸板的设备提供良好的 HMI 解决方案。建议购买双type-c的版本,左侧是烧录程序的串口UART0,右侧是实现TinyUSB 功能的USB CDC。
11.PNG

第一:安装开发环境

1,下载安装Arduino IDE下载地址:
https://downloads.arduino.cc/arduino-1.8.13-windows.exe

2,首选项添加板型管理器(BoardsManager)的网址 :
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json
3,在工具栏开发管理器中在线安装支持esp32 Arduino SDK 版本号1.0.5 rc7


8.PNG

4,下载支持ESP32 S2分支的arduino esp32 sdk文件,下载地址:
https://github.com/espressif/arduino-esp32/archive/esp32s2.zip

5,覆盖相应的文件
解压ESP32 S2分支文件按照下图选择文件或者文件夹,
1.PNG
复制黏贴到C:\Users\xxx\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.5-rc7文件夹中。(xxx是你电脑的用户名)

2.PNG
还有一种快捷到达该文件夹的技巧,打开Arduino  IDE-->文件->首选项,点下图红笔笔迹处。


12.png

6,下载开发工具解压到tools文件夹
开发ESP32-S2需要esptool 3.0版本,下载地址:https://dl.espressif.com/dl/esptool-3.0.0-windows.zip

xtensa-esp32s2-elf的下载地址:https://dl.espressif.com/dl/xtensa-esp32s2-elf-gcc8_4_0-esp-2020r3-win64.zip

两个文件解压以后,复制黏贴到C:\Users\xxx\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.5-rc7\tools

7.PNG


第二:实现
TinyUSB
Hathach的TinyUSB 库是用于嵌入式系统的开源跨平台 USB 主机设备堆栈,旨在内存安全,无需动态分配,所有中断事件的线程安全可延迟,然后在非 ISR 任务函数中处理。
tingusb.jpg
Chegewara的EspTinyUSB是ESP32-S2的简单且静止的WiP库为了锻炼学习TinyUSB两个库结合起来可以让ESP32 S2实现以下功能:CDC,通信设备类;MSC,大规模存储类;HID,人界面设备类:键盘,鼠标,游戏板,通用的进出;MIDI,乐器数字界面类;DFU,设备固件更新类;WebUSB,它使用供应商类来显示webusb的使用情况。


1,下载Chegewara的EspTinyUSB之sd_msc分支,下载地址:https://github.com/chegewara/EspTinyUSB/archive/sd_msc.zip  解压到C:\Users\xxx\Documents\Arduino\libraries\文件夹下。


2,用Hathach的TinyUSB 库中的msc_disk.c替换示例中的msc_disk.c 下面修改过的代码源于:

https://github.com/hathach/tinyusb/blob/master/examples/device/cdc_msc_freertos/src/msc_disk.c

[pre]#include "tusb.h"

#if CFG_TUD_MSC

// Some MCU doesn't have enough 8KB SRAM to store the whole disk
// We will use Flash as read-only disk with board that has
// CFG_EXAMPLE_MSC_READONLY defined

#define README_CONTENTS \
"This is tinyusb's MassStorage Class demo.\r\n\r\n\
If you find any bugs or get any questions, feel free to file an\r\n\
issue at github.com/hathach/tinyusb"

enum
{
  DISK_BLOCK_NUM  = 16, // 8KB is the smallest size that windows allow to mount
  DISK_BLOCK_SIZE = 512
};

#ifdef CFG_EXAMPLE_MSC_READONLY
const
#endif
uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
{
  //------------- Block0: Boot Sector -------------//
  // byte_per_sector    = DISK_BLOCK_SIZE; fat12_sector_num_16  = DISK_BLOCK_NUM;
  // sector_per_cluster = 1; reserved_sectors = 1;
  // fat_num            = 1; fat12_root_entry_num = 16;
  // sector_per_fat     = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0;
  // drive_number       = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
  // filesystem_type    = "FAT12   "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
  // FAT magic code at offset 510-511
  {
      0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
      0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T' , 'i' , 'n' , 'y' , 'U' ,
      'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,

      // Zero up to 2 last bytes of FAT magic code
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
  },

  //------------- Block1: FAT12 Table -------------//
  {
      0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file
  },

  //------------- Block2: Root Directory -------------//
  {
      // first entry is volume label
      'T' , 'i' , 'n' , 'y' , 'U' , 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x08, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      // second entry is readme file
      'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' , 'T' , 'X' , 'T' , 0x20, 0x00, 0xC6, 0x52, 0x6D,
      0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
      sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes)
  },

  //------------- Block3: Readme Content -------------//
  README_CONTENTS
};

// Invoked when received SCSI_CMD_INQUIRY
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
{
  (void) lun;

  const char vid[] = "TinyUSB";
  const char pid[] = "Mass Storage";
  const char rev[] = "1.0";

  memcpy(vendor_id  , vid, strlen(vid));
  memcpy(product_id , pid, strlen(pid));
  memcpy(product_rev, rev, strlen(rev));
}

// Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted
bool tud_msc_test_unit_ready_cb(uint8_t lun)
{
  (void) lun;

  return true; // RAM disk is always ready
}

// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
// Application update block count and block size
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
{
  (void) lun;

  *block_count = DISK_BLOCK_NUM;
  *block_size  = DISK_BLOCK_SIZE;
}

// Invoked when received Start Stop Unit command
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
{
  (void) lun;
  (void) power_condition;

  if ( load_eject )
  {
    if (start)
    {
      // load disk storage
    }else
    {
      // unload disk storage
    }
  }

  return true;
}

// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
  (void) lun;

  uint8_t const* addr = msc_disk[lba] + offset;
  memcpy(buffer, addr, bufsize);

  return bufsize;
}

// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and return number of written bytes
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
{
  (void) lun;

#ifndef CFG_EXAMPLE_MSC_READONLY
  uint8_t* addr = msc_disk[lba] + offset;
  memcpy(addr, buffer, bufsize);
#else
  (void) lba; (void) offset; (void) buffer;
#endif

  return bufsize;
}

// Callback invoked when received an SCSI command not in built-in list below
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
// - READ10 and WRITE10 has their own callbacks
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
{
  // read10 & write10 has their own callback and MUST not be handled here

  void const* response = NULL;
  uint16_t resplen = 0;

  // most scsi handled is input
  bool in_xfer = true;

  switch (scsi_cmd[0])
  {
    case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
      // Host is about to read/write etc ... better not to disconnect disk
      resplen = 0;
    break;

    default:
      // Set Sense = Invalid Command Operation
      tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);

      // negative means error -> tinyusb could stall and/or response with failed status
      resplen = -1;
    break;
  }

  // return resplen must not larger than bufsize
  if ( resplen > bufsize ) resplen = bufsize;

  if ( response && (resplen > 0) )
  {
    if(in_xfer)
    {
      memcpy(buffer, response, resplen);
    }else
    {
      // SCSI output
    }
  }

  return resplen;
}

#endif[/pre]
3,安装windows 10支持的驱动的准备工作。
Zadig是一款 Windows 应用程序,可安装通用 USB 驱动程序。下载地址:https://github.com/pbatard/libwd ... /b730/zadig-2.5.exe

4,EspTinyUSB 全家桶的效果

把all in one 烧录到开发板上,再把 USB CDC接入计算机,使用Zadig自动安装Ting USB各协议需要的支持Windows10的驱动。

[pre]#include "Arduino.h"
#include "webusb.h"
#include "cdcusb.h"
#include "mscusb.h"
#include "dfuusb.h"

extern "C" void init_disk();

WebUSB USBSerial;
CDCusb USBSerial1;
MSCusb msc;
DFUusb dfu;

void conCB(bool isCon)
{
    Serial.printf("connection state changed, new state %s\n", isCon ? "connected" : "disconnected");
}

void mount_cb()
{
    Serial.println("Mount");
}

void umount_cb()
{
    Serial.println("Unmount");
}

void resume_cb()
{
    Serial.println("Resume");
}

void suspend_cb(bool remote_wakeup_en)
{
    Serial.println("Suspend");
}


void setup()
{   
    Serial.begin(115200);

    msc.deviceID(0x303a, 0x0002);
    if (!USBSerial.begin())
        Serial.println("Failed to start webUSB stack");
    if (!USBSerial1.begin())
        Serial.println("Failed to start CDC USB stack");

    dfu.begin();
    msc.begin();
    USBSerial.onConnect(conCB);
    USBSerial1.onConnect(conCB);
    EspTinyUSB::registerDeviceCallbacks(mount_cb, umount_cb, suspend_cb, resume_cb);
}

void echo_all(char c)
{
    USBSerial.write(c);
    USBSerial1.write(c);
    Serial.write(c);
}

void loop()
{
    while (USBSerial.available())
    {
        echo_all(USBSerial.read());
    }
    while (USBSerial1.available())
    {
        echo_all(USBSerial1.read());
    }
    while (Serial.available())
    {
        echo_all(Serial.read());
    }
}[/pre]

TingUSB的全家桶就安装好了 :)计算机设备管理器显示的驱动协议。原来USB不仅仅是一种功能,大家有了感性认识了吧!


all in one.PNG

5,开启WebUSB效果的钥匙。
在Microsoft Edge浏览器地址栏输入edge://flags/  启用 Experimental Web Platform features ,它是实验性Web平台功能,支持正在开发中的实验性Web平台的功能。

3.PNG


6,Arduino IDE先连接UART0烧录示例WebUSB,再把 USB CDC接入计算机,Microsoft Edge浏览器打开  https://www.tinyusb.org/examples/webusb-serial/  


9.png

点击网页上的connect,选择ESP32 arduino device - 已配对,双击连接,在左侧sender区逐个输入Hello WebUSB! 右侧 receiver区也会有反馈出现。

10.png

7,另外,用两根usb连接线分别接左侧烧录程序的串口UART0和右侧TinyUSB 功能USB CDC。打开Arduino  IDE的串口监视器的同时,用Microsoft Edge浏览器打开  https://www.tinyusb.org/examples/webusb-serial/  ,当连接ESP32 arduino device后,串口监视器马上显示回文:connection state changed, new state connected ,右下侧选择NL和CR,波特率115200,在输入栏输入一段英文文字,按发送,浏览器receiver区会有反馈出现。


13.png


(结束)




发表于 2021-4-16 10:22 | 显示全部楼层
C:\Users\Tim\Desktop\捕获.JPG

楼主,为啥我的一直编译不过...
 楼主| 发表于 2021-4-16 23:19 | 显示全部楼层
sbjataje 发表于 2021-4-16 10:22
楼主,为啥我的一直编译不过...

信息太少难以判断。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-12-1 00:59 , Processed in 0.106126 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表