在 ESP32 S2上使用 USB Host 模块

这次实验在 ESP32 S2 Saola 开发板上使用前面设计的Micro USB Host【参考1】。

首先遇到的问题是:ESP32 S2 的 SPI 在 Arduino 环境下工作不正常(对于这个问题的分析请参阅【参考2】)。为此,我们需要直接修改 位于 C:\Users\用户名\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.1\libraries\SPI\src\SPI.cpp 文件中的如下内容:

#if CONFIG_IDF_TARGET_ESP32
//LabZDebug_Start
#if CONFIG_IDF_TARGET_ESP32S2
        SPIClass SPI(HSPI);
#else
        SPIClass SPI(VSPI);
#endif
//LabZDebug_End
#else
SPIClass SPI(FSPI);
#endif

接下来修改 USB Host Shield 库文件:

  1. USB_Host_Shield_Library_2.0\usbhost.h 这个文件有下面3个地方需要修改:
    1. 1 这里给出用到的 SCK/MISO/MOSI/SS Pin的编号
#elif defined(ESP32)
//LABZDebug typedef SPi< P18, P23, P19, P5 > spi;
//LABZDebug_Start
           //SCK  MISO MOSI SS
typedef SPi< P10, P21, P19, P13 > spi;
//LABZDebug_End
#elif defined(ARDUINO_NRF52840_FEATHER)

1.2 给出SPI需要引脚编号才能正确的进行SPI初始化:

#elif defined(SPI_HAS_TRANSACTION)
        static void init() {
                //LABZDebug USB_SPI.begin(); // The SPI library with transaction will take care of setting up the pins - settings is set in beginTransaction()
				//LABZDebug_Start
				                USB_SPI.begin(10,21,19,13); // The SPI library with transaction will take care of setting up the pins - settings is set in beginTransaction()
				//LABZDebug_End
                SPI_SS::SetDirWrite();
                SPI_SS::Set();
        }
#elif defined(STM32F4)

1.3 降低速度(Max3421e 最高支持26Mhz, 但是因为 ESP32 无法分频出26M,所以实际上SPI 会以是20M速度工作。但是因为这次实验都是排线,所以频率高了之后会出现通讯错误的问题,为此需要进行降频)到4Mhz。

将文件中

        //LABZDebug USB_SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0
		//LABZDebug_Start
		USB_SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
		//LABZDebug_End

2.USB_Host_Shield_Library_2.0\UsbCore.h 这里给出用到的SS 和 INT Pin编号

#elif defined(ESP32)
//LABZDebug typedef MAX3421e<P5, P17> MAX3421E; // ESP32 boards
//LABZDebug_Start
               // SS  INT
typedef MAX3421e<P13, P5> MAX3421E; // ESP32 boards
//LABZDebug_End
#elif (defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__))
typedef MAX3421e<Pb4, Pb3> MAX3421E; // Sanguino

3.USB_Host_Shield_Library_2.0\avrpins.h 这里主要是声明前面用到的PXX 的定义否则编译会出错

MAKE_PIN(P3, 3); // RX0
//LABZDebug_Start
MAKE_PIN(P4, 4);   // INT
MAKE_PIN(P13, 13);   // CLK
MAKE_PIN(P26, 26);   // SS
//LABZDebug_End
MAKE_PIN(P21, 21); // SDA

之后使用 USBHIDBootMouse.ino 进行测试:

#include <hidboot.h>
#include <usbhub.h>

// Satisfy the IDE, which needs to see the include statment in the ino too.
#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif
#include <SPI.h>

class MouseRptParser : public MouseReportParser
{
protected:
	void OnMouseMove	(MOUSEINFO *mi);
	void OnLeftButtonUp	(MOUSEINFO *mi);
	void OnLeftButtonDown	(MOUSEINFO *mi);
	void OnRightButtonUp	(MOUSEINFO *mi);
	void OnRightButtonDown	(MOUSEINFO *mi);
	void OnMiddleButtonUp	(MOUSEINFO *mi);
	void OnMiddleButtonDown	(MOUSEINFO *mi);
};
void MouseRptParser::OnMouseMove(MOUSEINFO *mi)
{
    Serial.print("dx=");
    Serial.print(mi->dX, DEC);
    Serial.print(" dy=");
    Serial.println(mi->dY, DEC);
};
void MouseRptParser::OnLeftButtonUp	(MOUSEINFO *mi)
{
    Serial.println("L Butt Up");
};
void MouseRptParser::OnLeftButtonDown	(MOUSEINFO *mi)
{
    Serial.println("L Butt Dn");
};
void MouseRptParser::OnRightButtonUp	(MOUSEINFO *mi)
{
    Serial.println("R Butt Up");
};
void MouseRptParser::OnRightButtonDown	(MOUSEINFO *mi)
{
    Serial.println("R Butt Dn");
};
void MouseRptParser::OnMiddleButtonUp	(MOUSEINFO *mi)
{
    Serial.println("M Butt Up");
};
void MouseRptParser::OnMiddleButtonDown	(MOUSEINFO *mi)
{
    Serial.println("M Butt Dn");
};

USB     Usb;
USBHub     Hub(&Usb);
HIDBoot<USB_HID_PROTOCOL_MOUSE>    HidMouse(&Usb);

MouseRptParser                               Prs;

void setup()
{
    Serial.begin( 115200 );
#if !defined(__MIPSEL__)
    while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
#endif
    Serial.println("Start");

    if (Usb.Init() == -1)
        Serial.println("OSC did not start.");

    delay( 200 );

    HidMouse.SetReportParser(0, &Prs);
}

void loop()
{
  Usb.Task();
}

运行结果如下:

关于 USB Host Shield 调试建议如下:

  1. 首先跑 board_qc.ino 确定SPI 连接是否正确。如果一直有问题,那么是 SPI 不通,需要研究MOSI信号是否正常发送;如果 MOSI/SCLK 都正常但是没有 MOISO 回复,那么请检查 RESET 是否为高;
  2. 接下来跑USBHIDBootMouse.ino 代码测试,如果有问题,应该是 INT Pin 设置的错误;
  3. 如果有线鼠标无法使用,那么可以实验无线鼠标,因为前者要求的功耗比较高,可能你从开发板中拉出来的5V供电不足。

参考:

  1. https://mc.dfrobot.com.cn/thread-312057-1-1.html 做一个Micro USB Host
  2. https://www.arduino.cn/thread-106240-1-1.html ESP32 S2 的 SPI

2022年5月28日 更新

偶然发现了 ESP32 S2 默认的 SPI 引脚【https://www.arduino.cn/thread-106240-1-1.html】,于是尝试不修改库的情况下直接使用。

硬件连接:


名称   
ESP32 S2ESP32 S2名称
INTIO17IO35MOSI
GNDGNDIO37MISO
MD-USB 母头 D-IO5SS
MD+USB 母头 D+IO36SCLK
VBCOMPN/A3.3VRESET
GNDGND3.3V3.3V

运行例子是 USB_Host_Shield_Library_2.0\examples\HID\USBHIDBootMouse

未经修改的 USB Host Shield 库如下:

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注