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);
}
}