Creating variant for using UNO R4 WiFi in USB bridge bypass mode

I'm not aware of one. If someone makes one please do share it on the forum. I have a personal interest in such things as I try to keep track of all the available Arduino boards platforms.

I've tried my best to follow the thread, but I'm still having trouble understanding why this bypassing of the ESP32-S3 is necessary in this application of MIDI over serial. I understand why you might do it for something like Delta_G's USB host project, but not for this one.

My suggestion is that, rather than making your platform as a fork of arduino/ArduinoCore-renesas, you instead use that platform as a dependency of your own platform, referencing all the resources from the "Arduino UNO R4 Boards" platform using the feature documented here:

https://arduino.github.io/arduino-cli/latest/platform-specification/#referencing-another-core-variant-or-tool

This means your platform can consist only of the specific files that contain your own customizations (e.g. boards.txt and the core variant) instead of having to maintain a copy of every one of the many files of arduino/ArduinoCore-renesas in your own project.

A good example of a platform like that is David Mellis's foundational "attiny" platform:

That platform leverages the resources of the "Arduino AVR Boards" platform using the referencing system.

1 Like

Does the MD / P201 (26) pin impact such a variant?
On the Minima it is tied to 5V thru R6 and you short BOOT to GND in order to program the bootloader.

On the WiFi it is connected thru the Logic Level Translator to ESP_IO9.
They updated the WiFi schematic a few weeks ago to show R8 removed (the Interactive Viewer is still incorrect), but MD is also connected to BOOT on the WiFi header for some reason.

you can create a variant in the hardware folder
you will need this patch
https://github.com/JAndrassy/my_boards/blob/master/renesas_uno/platform.txt

2 Likes

Thanks @ptillisch and others:

Sorry I missed noticing that you did split this out from the other thread. Which makes total sense!

I thought I would bring over some of my other thoughts from that thread. Some of which I think have been covered:

That is, before that the ESP32 probably has conversation with host, and suddenly the RX/TX pins going to the USB connector are changed. How is that handled. Is there some form of USB reset issued?...


Also if you currently compile for WIFI, it has no USB support built in? how does that work. Serial object is still trying to talk to ESP32 through their UARTs

Now if you hack platform.txt to remove the NO_USB setting, then the UART to SerialX objects are probably messed up. Where Serial1, probably tries to talk to the ESP32, and Serial2 probably talks to pins 0 and 1... Could be wrong.

Where is the USB Descriptor defined?

What about bootloaders? If solder jumper in place, do you need new bootloader? Probably not the same one as MINIMA, if for no other reason, the LEDS (pin 13) are on different IO pins on the two boards. P111 for MINIMA and P102 on WIFI.

What does double click on the reset button do? I am assuming that the ESP32 sees it, and probably resets the main processor...


EDIT: I meant to then say, but creating a new variant should solve many of the above things :smiley:

Here is a thread I started awhile ago, that @ptillisch gave me a lot of good instructions on how to do this:

How to build and change the latest core sources? - UNO R4 / UNO R4 WiFi - Arduino Forum

I still wonder how the switch over from the ESP32 is controlling the USB and suddenly the other processor has it, is handled. Maybe the processor detects USB is available and does a USB reset? at which point the host will query it for it's descriptors and the like?

Will be interesting to try! Wonder if I should have a 2nd WIFI board...

1 Like

MD / P201 on the WiFi is connected thru the Logic Level Translator to ESP_IO9 on the ESP32.

May not be useful to the experienced crowd, but I found this bootloader tutorial helpful...
https://www.circuitbread.com/tutorials/renesas-ra-13-introduction-to-mcuboot-using-the-renesas-ra-family-part-4

Edited to add link

Here is my attempt at a bypass sketch. __USBStart() switches the USB mux then starts tinyusb running on the RA4M1. SerialUSB is the RA4M1 USB CDC ACM port. Since HID class switches the USB mux and adds a HID interface, the following sketch cherry picks code from HID.cpp and HID.h. The bypass does not need the HID interface so only a small amount is code is needed.

The __maybe_start_usb code comes hardware/renesas_uno/1.0.4/libraries/HID/HID.cpp.
The #define Serial comes from hardware/renesas_uno/1.0.4/libraries/HID/HID.h.

Maybe this is the starter for some brave soul to try tinyusb USB MIDI or USB Mass Storage Class for R4. I am not that brave.

I am not against a bypass board file. When using this method the ESP32-S3 must be put in upload mode by double tapping the reset button.

unor4wifi_bypass.ino

#ifdef ARDUINO_UNOWIFIR4
void __maybe_start_usb() {
    __USBStart();
}

#ifdef Serial
#undef Serial
#define Serial SerialUSB
#endif
#endif  // ARDUINO_UNOWIFIR4

void setup() {
  Serial.begin(115200);
  while (!Serial && (millis() < 3000)) delay(10);
}

void loop() {
  Serial.print(millis());
  Serial.println(": Hello from Uno R4 WiFi bypass");
  delay(1000);
}

The following is the output from sudo lsusb -vd 2341:006d.
Note if the USB mux is switched to the ESP32-S3, the VID:PID is 2341:1002.


Bus 001 Device 107: ID 2341:006d Arduino SA UNO R4 WiFi
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x2341 Arduino SA
  idProduct          0x006d 
  bcdDevice            1.00
  iManufacturer           1 Arduino
  iProduct                2 UNO R4 WiFi
  iSerial                 3 34111D1458313034465933324B572D91
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x005d
    bNumInterfaces          3
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xc0
      Self Powered
    MaxPower              500mA
    Interface Association:
      bLength                 8
      bDescriptorType        11
      bFirstInterface         0
      bInterfaceCount         2
      bFunctionClass          2 Communications
      bFunctionSubClass       2 Abstract (modem)
      bFunctionProtocol       0 
      iFunction               0 
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         2 Communications
      bInterfaceSubClass      2 Abstract (modem)
      bInterfaceProtocol      0 
      iInterface              4 CDC Port
      CDC Header:
        bcdCDC               1.20
      CDC Call Management:
        bmCapabilities       0x00
        bDataInterface          1
      CDC ACM:
        bmCapabilities       0x02
          line coding and serial state
      CDC Union:
        bMasterInterface        0
        bSlaveInterface         1 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval              16
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass        10 CDC Data
      bInterfaceSubClass      0 
      bInterfaceProtocol      0 
      iInterface              0 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        2
      bAlternateSetting       0
      bNumEndpoints           0
      bInterfaceClass       254 Application Specific Interface
      bInterfaceSubClass      1 Device Firmware Update
      bInterfaceProtocol      1 
      iInterface              5 DFU-RT Port
      Device Firmware Upgrade Interface Descriptor:
        bLength                             9
        bDescriptorType                    33
        bmAttributes                       13
          Will Detach
          Manifestation Tolerant
          Upload Unsupported
          Download Supported
        wDetachTimeout                   1000 milliseconds
        wTransferSize                    4096 bytes
        bcdDFUVersion                   1.01
Device Status:     0x0001
  Self Powered
1 Like

see my comment earlier

I haven't been very successful in following the project, but I can take a wild guess that you can try changing this line in your boards.txt:

unor4bypass.upload.wait_for_upload_port=false

to this:

unor4bypass.upload.wait_for_upload_port=true

That is what I suspected would happen. With Arduino.h we have:

#ifndef NO_USB
#define Serial  SerialUSB
#define Serial1 _UART1_
#define Serial2 _UART2_
#define Serial3 _UART3_
#define Serial4 _UART4_
#define Serial5 _UART5_
#else
#define Serial _UART1_
#define Serial1 _UART2_
#define Serial2 _UART3_
#define Serial3 _UART4_
#define Serial4 _UART5_
#endif

So Serial1 uses different UARTn object.

So suspected when then need to change the defines in the variant pins_arduino.h

/****** UART CORE DEFINES ******/

#define SERIAL_HOWMANY		3
#define UART1_TX_PIN        22
#define UART1_RX_PIN        23
#define UART2_TX_PIN        1
#define UART2_RX_PIN        0
#define UART3_TX_PIN        24
#define UART3_RX_PIN        25

Not sure of best changes here. Maybe simply:

/****** UART CORE DEFINES ******/

#define SERIAL_HOWMANY		2
#define UART1_TX_PIN        1
#define UART1_RX_PIN        0
#define UART2_TX_PIN        24
#define UART2_RX_PIN        25

Probably need/want Serial2 to still work as Serial2, as to hopefully keep the communications between main processor and ESP32 for WIFI/BT.

Potentially could define Serial3 to be the Normal Serial1, as you have access to those pins (maybe) through ESP32 header pins


But these pins are 3.3v as they are on the other side of the level converter.

Quick FYI - I duplicated the new variant and was able to duplicate the issue, that when the new upload worked, it usually took two attempts.

So tried the above, which appears like it does not work for this:

Performing 1200-bps touch reset on serial port COM13
Waiting for upload port...
No upload port found, using COM13 as fallback
"C:\Users\kurte\AppData\Local\Arduino15\packages\arduino\tools\bossac\1.9.1-arduino5/bossac" -d --port=COM13 -U -e -w "C:\Users\kurte\AppData\Local\Temp\arduino\sketches\0F4C4313695EC159640F4DD3E32C1750/unowifi_esp32_bypass.ino.bin" -R
No device found on COM13
Set binary mode
Send auto-baud
Set binary mode
Failed uploading: uploading error: exit status 1

Although second time it worked and that was without ever jumpering pin 7.

Now try again with 7  
Note on my machine, when you switch to not use ESP32 (jumper 7 to gnd), the Serial port number changes:
![image|690x90](upload://iRkduppTE9f7iliazLPzhmFTPpX.png)

And I have to reset for the Serial monitor to show stuff. Ditto when I remove the jumper.
Note in some cases here, needed to reset the board after removing the jumper for it to switch back

As far as I can tell the ESP32-S3 bridge talks DAP over USB then bit bangs SWD to burn the RA4M1 Flash. The ESP32-S3 does not appear to need the RA4M1 bootloader to burn flash. See freedap.c in the UNOR4USBridge and search for SWD.

I also have had no success switching back to the ESP32-S3. The USB mux switches but the PC USB host never enumerates the ESP32-S3. May do a USB bus reset just before switching the mux back to the ESP32-S3. Just a wild guess.

1 Like

It's for selecting the operation mode.
From the online tutorial I previously referenced...

Every RA MCU has a pin which is called “MD”...merged with P201 (in the case of the the RA4M1).
Depending on the state of this pin while resetting the device, the MCU can run either in the normal mode, which is called “Single-Chip Mode” in the User’s manual, if this pin is high, or in bootloader mode (“SCI / USB Boot Mode”), if this pin is low.

Normally, this pin is pulled up, so the MCU runs in normal mode. Which is: the program runs from the code area of the flash memory implementing the user’s code.

To run the bootloader you need to pull the MD pin low, then pull the RES pin low before setting it high again.
After that, the MCU will start in boot mode.
The bootloader code is located in the read-only memory, and can’t be changed by the user.
In this mode the user’s code is not implemented until the next MCU reset (under the condition that MD pin is high).

I think we are talking about 2 different things.
Does this link work...

MD P201 is for the Native Bootloader as described in Part 4...

On the R4 Minima P201 is always pulled high unless you short BOOT

On the R4 WiFi the ESP32 is controlling the pin.
I personally did not understand why, which is the reason I am following your thread!

Sorry I don't read all your conversation above.

The RA4M1 has a ROM bootloader. A DFU and UART one. They are activated by a 'boot' pin. These are in Arduino used only to burn the Arduino bootloader.

The board platform can't have Arduino.h. That must be in the core platform.

The "libraries" mentioned in the platform specification are the platform bundled libraries under the libraries subfolder of the platform. Arduino.h is part of the core, not of the platform bundled libraries.

You might look into whether you can make your desired modifications from the code of your platform's core variant. The purpose of the core variant is to contain board-specific so it is definitely the appropriate place to do so if technically feasible.

Something to note is that we often see the term "core" used incorrectly/ambiguously (including throughout the official Arduino documentation) to refer to the platform as a whole. The "core" is actually only one of several components that make up a platform.

Sorry, I should have written "components" instead of "files". In the case of multi-file components such as a core or core variant, you must either use the entire component from the referenced platform or the entire component in the referencing platform. You can't mix and match between the two at a file level granularity.

That statement is specific to platform bundled libraries. It is not applicable to cores. Even in the case of platform bundled libraries, you can't override the contents of the referenced platform's libraries at a per-file granularity, only at a per-library granularity.

1 Like

maybe experiment that way and once the variant works, then we can separate it and if required, propose some PR for some ifdefs in core

1 Like

I believe the answer from @ptillisch is the short answer is you cannot change it directly.

But, I think we may have a few options we can try. including:

a) if there is something wrong with their abstraction for the different variants, than try to change it and issue a Pull Request back to the core, to resolve it.

b) You can define stuff in the variant.h file which comes from your variant that hopefully can help control things. note this may still need to be used in conjunction with a)

c) Your boards.txt entry for the variant can add additional defines to the command line.
like: -DDISABLE_USB_SERIAL or the like... again may need a) and/or b) changes.

In some of the cases we may need to ask additional questions, as to try to understand why some things are abstracted in the way that they are.

For example: I am not sure if they really need the abstractions for Serial object in Arduino.h? That is why?

#ifndef NO_USB
#define Serial  SerialUSB
#define Serial1 _UART1_
#define Serial2 _UART2_
#define Serial3 _UART3_
#define Serial4 _UART4_
#define Serial5 _UART5_
#else
#define Serial _UART1_
#define Serial1 _UART2_
#define Serial2 _UART3_
#define Serial3 _UART4_
#define Serial4 _UART5_

#endif

Which then uses the defines out of the different variants file pins_arduino.h

/****** UART CORE DEFINES ******/

#define SERIAL_HOWMANY		3
#define UART1_TX_PIN        22
#define UART1_RX_PIN        23
#define UART2_TX_PIN        1
#define UART2_RX_PIN        0
#define UART3_TX_PIN        24
#define UART3_RX_PIN        25

I know they are used, in the files likse SerialObj2.cpp that has:

#if SERIAL_HOWMANY > 1
UART _UART2_(UART2_TX_PIN, UART2_RX_PIN);
#endif

But you could have just as easily had in it something like:

#if SERIAL_HOWMANY > 1
UART Serial2(SERIAL2_TX_PIN, SERIAL2_RX_PIN);
#endif

And yes you would have to put in some mechanism for the Serial object when it is actually only a UART...

But back on main subject, I think our best bet is to try to find ways to work around the quirks in the current setup.

As for wasting time.... Hard to say. I started off with a fork, as I already did it awhile ago to allow me to make changes and issue Pull requests and the like.

This may be more along the lines of what I mentioned, as maybe need to ask Arduino developers more their intentions and why things are implemented the way they are.
The answer in some cases was, they were getting things up and running as fast as they could, and some things just did not get done.

This may be one of those cases. That is, if I build with the define NO_USB, why is USB still being built and included into the hex file. Why?
This looks like it still has everyting out of the USB subdirectory built into the sketch binary.

Not sure which thread? @ptillisch is something to discuss on different thread? Or Issue or???

As I expected the WIFI has the full USB and USB Serial code still in it.
The only thing that NO_USB does, is to change which UARTn object is associated with which Serial object and to actually start up USB (and USB Serial).

@Delta_G Here is a modified version of your test sketch that works:

bool native_usb = false;
void setup() {
  Serial.begin(115200);
  Serial1.begin(115200);
  Serial2.begin(115200);

  Serial.println("Hello World");
  pinMode(7, INPUT_PULLUP);

  pinMode(21, OUTPUT);

  pinMode(13, OUTPUT);

}

void loop() {

  if(digitalRead(7) == LOW){
    digitalWrite(21, HIGH);
    native_usb = true;
#ifdef ARDUINO_UNOR4_WIFI
   __USBStart();
   SerialUSB.begin(115200);
#endif

  }
  else{
    native_usb = false;
#ifdef ARDUINO_UNOR4_WIFI
   SerialUSB.end();
#endif
    
    digitalWrite(21, LOW);
  }

  static uint32_t pm = millis();
  uint32_t cm = millis();
  if(cm-pm>500){
    #ifdef ARDUINO_UNOR4_WIFI
    if (native_usb)
      SerialUSB.println("SerialUSB - ");
    else
      Serial.println("Serial - ");
    #else
    Serial.println("Serial - ");
    #endif
    Serial1.println("Serial1 - ");
    Serial2.println("Serial2 -");
    digitalWrite(13, !digitalRead(13));
    pm = cm;
  }
}

When built with the standard WIFI board variant.

Edit: Note I personally believe that in majority of cases (probably 95%+ cases), the user is not intending to do something like this, and probably rather have the storage and data space freed up.