Arduino Zero USBDevice.attach() problem

Hello,

i have a strange problem with USB.
I have written a simple code to read and write data via USB on Arduino Console from/to Arduino Zero (powered by external battery).
When i use in the code the function USBDevice.detach() to disconnect Ardunino Zero from PC and subsequentely the function USBDevice.attach() to riconnect Arduino Zero to PC i can see the output on Arduino console of the SerialUSB.print command but i cannot send data via Arduino console to Arduino Zero.
SerialUSB don't receive characters sended via Arduino console.
If i reset the Arduino Zero and retry to send data via Arduino console i receive characters on Arduino Zero.
Attach or detach USB it's done thought an external push button connected to Arduino Zero.
There is some extra instruction for activation of USB input?
I also tried USBDevice.init() before USBDevice.attach() but without success.
Thank you in advance for reply.

#include <Arduino.h>

#define MULTI_FUNCTION_BUTTON_PIN A5
int buttonPushCounter = 0;
int buttonState;
int lastButtonState;
unsigned long buttonPushCounterLastRun = 0;

bool flipflop;

void setup()
{
  // initialize SerialUSB
  SerialUSB.begin(115200);
  // initialize MULTI_FUNCTION_BUTTON
  pinMode(MULTI_FUNCTION_BUTTON_PIN, INPUT_PULLUP);
}

void loop()
{
  loopMultiFunctionButton();
  readCommandSerialOut();
}

void loopMultiFunctionButton()
{
  buttonState = digitalRead(MULTI_FUNCTION_BUTTON_PIN);
  if (buttonState != lastButtonState)
  {
    if (buttonState == LOW)
    {
      // if the current state is HIGH then the button
      // wend from off to on:
      buttonPushCounter++;

      SerialUSB.println("MULTI_FUNCTION_BUTTON pressed");
    }
  }
  if (buttonPushCounter == 0)
    buttonPushCounterLastRun = millis();
  else if (millis() - buttonPushCounterLastRun > 5000)
  {
    switch (buttonPushCounter)
    {
    // 3 = enable/disable USB
    case 3:

      SerialUSB.println("MULTI_FUNCTION_BUTTON CASE 3");
      if (flipflop)
      {
        flipflop = false;
        //attach USB
        USBDevice.init();
        USBDevice.attach();
      }
      else
      {
        //detach USB
        USBDevice.detach();
        flipflop = true;
      }
      break;
    }
    buttonPushCounter = 0;
    buttonPushCounterLastRun = 0;
  }
  // save the current state as the last state,
  //for next time through the loop
  lastButtonState = buttonState;
}

#define SERIAL_OUT_INPUT_BUFFER_LENGTH 64
char inputBufferSerialOUT[SERIAL_OUT_INPUT_BUFFER_LENGTH];
int bufferPosSerialOUT = 0;

void readCommandSerialOut()
{
  if (SerialUSB.available())
  {
    bool foundNewline = false;
    uint8_t received = SerialUSB.read();
    if (received != '\0')
    {
      if (received == '\n')
      {
        // If we've found a line ending, we should plan to run
        // any registered hooks so they can check for unsolicited
        // data that might be useful.
        foundNewline = true;
        SerialUSB.println(inputBufferSerialOUT);
        // clear buffer
        inputBufferSerialOUT[0] = '\0';
        bufferPosSerialOUT = 0;
      }
      if (bufferPosSerialOUT + 1 == SERIAL_OUT_INPUT_BUFFER_LENGTH)
      {
        for (int32_t i = SERIAL_OUT_INPUT_BUFFER_LENGTH - 1; i > 0; i--)
        {
          inputBufferSerialOUT[i - 1] = inputBufferSerialOUT[i];
        }
        bufferPosSerialOUT--;
      }
      inputBufferSerialOUT[bufferPosSerialOUT++] = received;
      inputBufferSerialOUT[bufferPosSerialOUT] = '\0';
    }
  }
}



Hi @luk3luk3

Here's some code that puts the SAMD21 microcontroller into sleep mode, but whenever the button on analog pin A1 is pressed, it awakes and allows the user to enter code on the console for 10 seconds, before falling asleep oncemore. The entered code is echoed back to the console, to test that it's reading the characters correctly:

// Code to test attaching and detaching the SAMD21's native USB port

uint32_t currentTime, previousTime;               // Intialise the current time and previous time variables

void setup(void) {
  pinMode(A1, INPUT_PULLUP);                      // Intialise button input pin and activate internal pull-up resistor
  pinMode(LED_BUILTIN, OUTPUT);                   // Initialise the LED_BUILTIN output
  attachInterrupt(A1, dummyFunc, LOW);            // Activate a LOW level interrupt on the button pin
  NVMCTRL->CTRLB.bit.SLEEPPRM = NVMCTRL_CTRLB_SLEEPPRM_DISABLED_Val;    // Prevent the flash memory from powering down in sleep mode
  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;              // Select standby sleep mode
  SerialUSB.begin(115200);                        // Intialise the native USB port
  while (!SerialUSB);                             // Wait for the console to open
}

void loop() {
  digitalWrite(LED_BUILTIN, LOW);                 // Turn off the LED
  SerialUSB.println(F("Sleeping Zzzz...wait for button to wake"));  // Send sleep message to the console
  USBDevice.detach();                             // Detach the native USB port
  SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;     // Disable SysTick interrupts
  __DSB();                                        // Ensure remaining memory accesses are complete
  __WFI();                                        // Enter sleep mode and Wait For Interrupt (WFI)
  SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;      // Enable SysTick interrupts
  USBDevice.attach();                             // Re-attach the native USB port
  digitalWrite(LED_BUILTIN, HIGH);                // Turn on the LED
  delay(500);                                     // Wait for half a second (seems to be necessary to give time for the USB port to re-attach)
  while(!SerialUSB);                              // Wait for the console to re-open
  SerialUSB.println();                            // Add a newline
  SerialUSB.println(F("Button depress...waking up")); // Send a wake up message
  SerialUSB.println(F("Enter text in the console..."));
  currentTime = millis();                         // Initialise the current and previous times
  previousTime = currentTime;
  while (currentTime - previousTime < 10000)      // Echo back characters from the console for 10 seconds
  {
    if (SerialUSB.available())                    // Check if incoming data is available on A3
    {
      byte byteRead = SerialUSB.read();           // Read the most recent byte on A3
      SerialUSB.write(byteRead);                  // Echo the byte back out on A2
    } 
    currentTime = millis();                       // Update the current time
  }
  //delay(500);                                   // Wait half a second
}

void dummyFunc() {}

Hi Martin, thank you for reply.

I have founded the problem in the class USBCore.cpp method
void USBDeviceClass::initEP(uint32_t ep, uint32_t config) release date Jan 25, 2018.
I solved the problem updating the USBCore.cpp with a newest version.
The code of the broken version:

else if (config == (USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_OUT(0)))
	{
		if (epHandlers[ep] == NULL) {
			epHandlers[ep] = new DoubleBufferedEPOutHandler(usbd, ep, 256);
		}
	}

does not delete if exist the DoubleBufferedEPOutHandler's
The code of the working version:

else if (config == (USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_OUT(0)))
	{
		if (epHandlers[ep] != NULL)
		{
			delete (DoubleBufferedEPOutHandler *)epHandlers[ep];
		}
		epHandlers[ep] = new DoubleBufferedEPOutHandler(usbd, ep, 256);
	}