Uploaded sketch with HID.h difficult to upload new sketch

I was trying a simple sketch to test out some of the stuff I mentioned in the thread:

#include <HID.h>
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  while(!Serial && millis() < 5000) {}
  delay(1000);

}

int loop_count = 0;
void loop() {
  Serial.print("Loop Count: ");
  Serial.print(++loop_count, DEC);
  Serial.print(" Baud: ");
  Serial.println(Serial.baud(), DEC);
}

I started this as new thread, in case others run into issues where they setup their WIFI board to do HID and have similar difficulties.

And confirmed that Serial was the native USB serial... i.e. the baud() method exists.

tried to add a delay at the end of loop.

And then found it very difficult to upload. For a bit I felt like the board was bricked.

Probably related to when the board is in ESP32 controlling USB versus the RA4M1 controlling USB, they are different COM ports COM3 and COM13.

I finally was able to get it to upload
It appears to take several iterations of double clicks of the reset button, until I hear the windows notification that some device changed. And then I need to go up to the Tools ->port menu and verify that it now has the other port and select it. And finally, could upload a sketch.

Note: The above sketch will not build if <HID.h> is not included as
Serial.baud() is not defined. Side note: I also verified that with HID included, other source files that do Serial.print and do not include HID.h their output does not output to the Serial port.

Wondering if bootloader on the main processor should have USB support in it? For example, monitor the baud rate and if special baud... ?

1 Like

Thanks @KurtE. This poor user experience is tracked by the developers here:

and there is a proposal for how to fix it here:

1 Like

@KurtE
I think that HID library has nothing to do with it. The problem is that you are continuously borrowing the Serial used for downloading.
Try removing the HID header and see if the problem still happens.

Thanks, @ptillisch!

I subscribed to those items and will be interesting to see the solution.

I figured it was known. It will be interesting to see if the approaches mentioned will fix the problem. I have not studied it enough in details, but wondering things like:
a) If the host does the change baud rate to 1200 or 2400 does anyone see it, if the USB is in RA4M1 USB mode (pin 21 high)?

b) If my sketch switches pin 21 back low, the ESP32 does not output anything I output on UART1, almost like it needs someone to do a USB reset operation.

c) It feels like the reset/double reset operations may be timing related. Almost like, I need to do a reset, and then there is a timing window that if I then do a double click of the reset it works. Like maybe after the first reset, the call to __USBStart is in some state, like maybe the buss reset, when then the new double click takes over and the ESP32 sees the buss in a reset state and recovers/resets... But again, just a WAG.

You are right that I am not doing anything with HID here. Maybe I should have labeled, this as: If your sketch sets digital Pin 21 high, then... Or if your sketch calls __USBStart(), then.

Note: It is not borrowing the Serial, but the sketch chose to use the RA4M1 built-in USB instead of going through a UART to the ESP32-S3, over a non-FIFO Uart at some relatively slow speed who then forwards the data to the host over USB.

I am sort of curious why Arduino choose to have the ESP32-S3 by default do the USB communications on the WIFI. Currently every sketch has the USB including USB Serial code built into their sketch, you have to switch things up to do HID, you waste a hardware UART, ... I might understand if maybe the ESP32-S3 supported USB High Speed, but as far as I can tell it only supports Full Speed, just like the RA4M1...

But that is a different topic. Maybe at some point we will finish a different variant that is setup, that does this, which includes a different bootloader and works when you solder the USB jumper on the bottom of the board.

I thought one way to reset the ESP32-S3 after switching the USB mux might be to send "AT+RESET" to the ESP32-S3 AT command processor. This should result in ESP.restart(). Hopefully, the PC USB host will enumerate the ESP32-S3 so bossac can upload. This would only be needed if the USB mux has been switched to the RA4M1.

Proof of concept sketch that includes HID.h then switches back to the ESP32-S3 for the next upload.

// Uno R4 WiFi serial console to WiFi/BT AT command processor running on the
// ESP32-S3. Including HID.h results in the USB mux switching to the RA4M1.
// The serial console (Serial) is the RA4M1 USB controller.
//
// Example Send:    "AT+FWVERSION?\n" Receive: "+FWVERSION: 0.3.0\r\nOK\r\n"
//  
// Special feature: If '~' is received on the serial console, the USB mux is
// switched back to the ESP32-S3. And the ESP32-S3 is restarted via
// ESP.restart(); This forces the USB host to enumerate the ESP32-S3 so bossac
// works again.
//
// This easier since it does not require double clicking the reset button.
//
// One glitch. After uploading this program, the Linux device is /dev/ttyACM2
// (2341:006D). The pass through works fine.
//
// After sending the '~', the board enumerates as /dev/ttyACM3 (2341:1002)
// probably because the IDE is holding open /dev/ttyACM2. The IDE port must be
// switched to ACM3 to do the bossac upload. After upload is done the board
// enumerates as ACM2 again.

#include <HID.h>  // This switches the USB mux to the RA4M1

// The following code switches the USB mux back to the ESP32-S3 on Uno R4 WiFi
// Soure: arduino-renesas-bootloader/src/bossa.c
//
/* Key code for writing PRCR register. */
#define BSP_PRV_PRCR_KEY	 (0xA500U)
#define BSP_PRV_PRCR_PRC1_UNLOCK ((BSP_PRV_PRCR_KEY) | 0x2U)
#define BSP_PRV_PRCR_LOCK	 ((BSP_PRV_PRCR_KEY) | 0x0U)

void my_restore_usb_switch() {
  ioport_instance_ctrl_t port_ctrl;
  if (R_SYSTEM->VBTBKR[1] == 40) {
    // The following does the same as?
    // pinMode(21, OUTPUT);
    // digitalWrite(21, HIGH);
    // delay(2);
    // digitalWrite(21, LOW);
    // Maybe because the mux control pin has an external pull-down so it is
    // not necessary to keep it LOW.
    // pinMode(21, INPUT);
    R_IOPORT_PinCfg(&port_ctrl, BSP_IO_PORT_04_PIN_08, IOPORT_CFG_PORT_DIRECTION_OUTPUT);
    R_IOPORT_PinWrite(&port_ctrl, BSP_IO_PORT_04_PIN_08, BSP_IO_LEVEL_HIGH);
    R_BSP_SoftwareDelay((uint32_t) 2, BSP_DELAY_UNITS_MILLISECONDS);
    R_IOPORT_PinWrite(&port_ctrl, BSP_IO_PORT_04_PIN_08, BSP_IO_LEVEL_LOW);
    R_IOPORT_PinCfg(&port_ctrl, BSP_IO_PORT_04_PIN_08, IOPORT_CFG_PORT_DIRECTION_INPUT);
    // VBTBKR[1] is used as a flag to reflect the state of the USB mux.
    // It is not cleared by hardware reset. But writing to
    // BOOT_DOUBLE_TAP_DATA will overwrite it!
    R_SYSTEM->PRCR = (uint16_t) BSP_PRV_PRCR_PRC1_UNLOCK;
    R_SYSTEM->VBTBKR[1] = 0;
    R_SYSTEM->PRCR = (uint16_t) BSP_PRV_PRCR_LOCK;
  }
}

void setup() {
  Serial.begin(115200);   // USB serial baudrate is don't care
  Serial2.begin(115200);  // WiFi/BT AT command processor on ESP32-S3
}

void loop() {
  uint8_t b;
  uint32_t bytes_avail;
  uint32_t bytes_out;

  bytes_avail = Serial.available();
  while (bytes_avail-- > 0) {
    b = Serial.read();
    if (b == '~') {
      my_restore_usb_switch();
      static const char RESET[] = "AT+RESET\n";
      Serial2.write(RESET, sizeof(RESET) - 1);
    }
    bytes_out = Serial2.write(b);
    assert(bytes_out == 1);
  }
  bytes_avail = Serial2.available();
  while (bytes_avail-- > 0) {
    b = Serial2.read();
    bytes_out = Serial.write(b);
    assert(bytes_out == 1);
  }
}
2 Likes

@ptillisch and all - I thought I saw it some place, but supposed I wish to update the bootloader of the RA4M1 chip to on the WIFI to work more like the MINIMA, and to potentially solder the USB jumper (actually would be nice to find a small enough switch to solder there, but...

Are there instructions on how to build the different bootloaders:
Which I believe is in this github project:

arduino/arduino-renesas-bootloader: A tinyusb based project implementing the bootloader for Uno R4 and Portenta C33 (github.com)

And then how to flash the updated bootloader.... I did order a backup WIFI board just in case...

Thanks
Kurt

I am pretty sure the one I saw was posted by @Delta_G :

To compile: I had to sort of decipher:

git clone GitHub - arduino/arduino-renesas-bootloader: A tinyusb based project implementing the bootloader for Uno R4 and Portenta C33 git clone GitHub - hathach/tinyusb: An open source cross-platform USB stack for embedded system cd tinyusb # This step is temporary patch -p1 < ../arduino-renesas-bootloader/0001-fix-arduino-bootloaders.patch python tools/get_deps.py ra cd .. cd arduino-renesas-bootloader TINYUSB_ROOT=$PWD/../tinyusb make -f Makefile.minima # TINYUSB_ROOT=$PWD/../tinyusb make -f Makefile.wifi



git clone https://github.com/arduino/arduino-renesas-bootloader
git clone https://github.com/hathach/tinyusb 
cd tinyusb 
patch -p1 < ../arduino-renesas-bootloader/0001-fix-arduino-bootloaders.patch 
python tools/get_deps.py ra
cd .. 
cd arduino-renesas-bootloader 
export TINYUSB_ROOT=$PWD/../tinyusb 
make -f Makefile.minima 
make -f Makefile.wifi

Note: the above I need to copy the actual git projects.
Plus needed to install several other things..
for the compiler I add the path these boards use for the compiler to the path...

But compile fails:

CC usbd_control.o
arm-none-eabi-gcc: error: unrecognized command line option '-Wcast-function-type'; did you mean '-Wbad-function-cast'?
make: *** [/home/kurte/github/tinyusb/tools/make/toolchain/arm_gcc_rules.mk:56: _build/portenta_c33/obj/src/portable/renesas/rusb2/hcd_rusb2.o] Error 1
m

Wonder which version of gcc this was setup for?

Was trying to build using same version compiler as used to compile for UNO R4
#export PATH="$PATH":/home/kurte/.arduino15/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/bin

Turns out that option was not added untill GCC 8. something. So tried using the version installed for building for Teensy:

export PATH="$PATH":/home/kurte/.arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin

Gets a little farther now:

But fails to find a header file.

in file included from /home/kurte/github/tinyusb/src/portable/renesas/rusb2/rusb2_common.c:37:
/home/kurte/github/tinyusb/src/portable/renesas/rusb2/rusb2_ra.h:44:10: fatal error: bsp_api.h: No such file or directory
   44 | #include "bsp_api.h"
      |          ^~~~~~~~~~~
compilation terminated.
CC usbc.o
make: *** [/home/kurte/github/tinyusb/tools/make/toolchain/arm_gcc_rules.mk:56: _build/portenta_c33/obj/src/portable/renesas/rusb2/rusb2_common.o] Error 1
make: *** Waiting for unfinished jobs....
/home/kurte/github/tinyusb/hw/bsp/ra/family.c:38:10: fatal error: bsp_api.h: No such file or directory
   38 | #include "bsp_api.h"
      |          ^~~~~~~~~~~
compilation terminated.
make: *** [/home/kurte/github/tinyusb/tools/make/toolchain/arm_gcc_rules.mk:56: _build/portenta_c33/obj/hw/bsp/ra/family.o] Error 1
In file included from /home/kurte/github/tinyusb/src/portable/renesas/rusb2/dcd_rusb2.c:42:
/home/kurte/github/tinyusb/src/portable/renesas/rusb2/rusb2_ra.h:44:10: fatal error: bsp_api.h: No such file or directory
   44 | #include "bsp_api.h"
      |          ^~~~~~~~~~~
com

So far I have not found this file in either project.

Thanks,

I know I am missing from somewhere. How does the make find this file? As you mentioned it is installed with the Arduino install. Am I missing some steps, like supposed to install the core at some specific location or copy ...

Thanks
Kurt

EDIT: Found the problem my decoding on of the paragraph into commands was wrong.

The ra was supposed to be part of the getdeps python run.... Now it builds
I updated the steps above to hopefully be close to correct