Uploaded sketch with HID.h difficult to upload new sketch

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