1

I've run into quite the problem with my 32u4, I can't get it to reconnect to the computer upon wakeup from a sleep mode!

So I have an Arduino Pro Micro featuring the 32u4, and I'm also designing a project with a standalone 32u4 (I'm using the Pro Micro as a test platform before I begin building my project). It is a battery operated device with a soft-start, so I need power consumption to be a miniscule as possible (hence the sleep modes).

After learning about the registers and brushing up on some binary, putting the chip to sleep was fairly straight forward, however, I cannot get the USB interface internal to the 32u4 to 'wake back up' or reconnect to the computer. I've attached my code below. I also tested this code on my Arduino Nano and it works just fine, however with added USB features of the 32u4, I cannot get it to reconnect to the computer, and I have to reset the chip a million times to get the IDE to finally recognise it and upload something else to it.

Here is my lovely code below. All it does it upon startup, go sleep, and when interrupt on pin 2 goes low, wake the chip back up and run the blink sketch. It goes to sleep, and wakes up and runs the sketch, it just won't ever reconnect to my computer, until I do a hardware reset.

int btn1Pin = 2;
int led1 = 9;

// these are the 'standard' register configurations 
byte _SMCR = 0; // disable sleep mode
byte _ADCSRA = 0b10000111; // re-enable ADC

int interval = 500;
int ledState = true;
unsigned long ct1 = 0;
unsigned long pt1 = 0;

void setup()
{
  pinMode(led1, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(btn1Pin), wakeUp, FALLING);  
  sleep();
}

void loop()
{
  ct1 = millis(); // blink something so I know you're working
  if (ct1 - pt1 >= interval)
   {
     digitalWrite(led1, ledState);
     ledState = !ledState;
     pt1 = ct1;
   }
}

void wakeUp()
{
  SMCR = _SMCR; // disable sleep mode
  ADCSRA = _ADCSRA; // re-enable ADC
}

void sleep()
{
  ADCSRA &= ~(1 << 7); // disable ADC
  SMCR |= ( 1<<2 );    // power down mode
  SMCR |= 1;           // enable sleep
  __asm__ __volatile__("sleep"); // hypnotist snaps fingers, chip is out cold!
}

Inside AJ's brain (more research): 32u4 Datasheet for quick reference

I added a quick led turn on in the wakeUp() ISR to ensure it was actually getting executed, and indeed it was.

The description of the USBCON register (Page 267 - 21.13.1) claims that clearing bit 7 disables and resets the USB controller. I tried another iteration of code where in sleep() I cleared bit 7, hoping that reset the controller, and in wakeUp() I set the bit to turn it back on after reset, but that didn't work. In fact, it gave me a really tough time when trying to reprogram (even though I KNOW that the wakeUp() ISR is executing and the bit had to have been reset).

After some more reading, I saw (Page 262 - 21.7.2) says that in power down mode (the sleep mode I'm using), "the oscillator is stopped and halts all the clocks (CPU and peripherals). The USB controller 'wakes up' when:

  • the WAKEUPI interrupt is triggered
  • the VBUSTI interrupt is triggered."

Okay so this makes sense, in power down mode the USB controller is stopped due to the lack of an oscillator, cool! I understand that to mean I need to trigger one of those interrupts to re-enable the USB controller. So I searched around for the first interrupt "WAKEUPI", and it appears this bit is set by hardware (Page 282), I'm guessing this means when you plug in the USB cable? I wrote a sketch to read that register, and it returned with 00010000, so I'm assumed the above statement is true. It also says setting it with software has no effect, so I left this one to explore the next interrupt, VBUSTI, which seems to be part of the automatic USB plug in detection based off of the VBUS pad. Maybe something here needs to be changed but I can't tell.

Page 266 - 21.12 talks about software USB operating modes, and the last one is "Resuming the USB interface." The 4 bullets provide to wake up are as such:

  • Enable PLL
  • Wait PLL lock
  • Unfreeze USB clock
  • Clear Resume information

I tried to do all of the above by adding this code to the wakeUp() ISR. It still didn't work :(. I know it's brutal and ISRs should be as short as possible but I gave it a go anyways.

  PLLCSR = _PLLCSR; // enable PLL clock
  var = bitRead(PLLCSR, 0);   
  while (var != 1) {} // wait for clock to lock

  USBCON = _USBCON; // unfreeze USB clock
  UDINT = 0; // clear resume flag

Maybe I'm making all of this more complicated than it needs to be, I don't know! I can't get this thing to reconnect.

3

You're making it too hard on yourself.

There is a method to re-start the USB, but it only works if the USB has been properly stopped - and the method that is supposed to do that is empty.

This is a little sketch that works on my Leonardo:

#include <LowPower.h>

void setup() {      
}

void loop() {
    USBCON = 0;
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);     

    USBDevice.attach();

    pinMode(13, OUTPUT);
    digitalWrite(13, HIGH);

    delay(10000);
    digitalWrite(13, LOW);
}

It disables the USB (USBCON = 0;), sleeps for 8 seconds, then starts the USB up again from scratch (USBDevice.attach();). 10 seconds later it sleeps again.

At the computer end, you get (on Linux):

[1242489.000014] usb 2-1.5.2: Product: USB IO Board
[1242489.000015] usb 2-1.5.2: Manufacturer: Arduino LLC
[1242489.000316] cdc_acm 2-1.5.2:1.0: ttyACM0: USB ACM device
[1242498.631563] usb 2-1.5.2: USB disconnect, device number 69
[1242507.068078] usb 2-1.5.2: new full-speed USB device number 70 using ehci-pci
[1242507.199628] usb 2-1.5.2: New USB device found, idVendor=2341, idProduct=0036
[1242507.199630] usb 2-1.5.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[1242507.199631] usb 2-1.5.2: Product: USB IO Board
[1242507.199633] usb 2-1.5.2: Manufacturer: Arduino LLC
[1242507.200256] cdc_acm 2-1.5.2:1.0: ttyACM0: USB ACM device
[1242517.063425] usb 2-1.5.2: USB disconnect, device number 70
[1242525.495729] usb 2-1.5.2: new full-speed USB device number 71 using ehci-pci
[1242525.627634] usb 2-1.5.2: New USB device found, idVendor=2341, idProduct=0036
.... etc ....
  • Initially I was trying not to use a library, but I forgot that I could check them to see what they did. I appreciate it very much, I'll definitely be spending some time studying this one. – HavocRC Feb 16 at 0:56
  • The USBdevice.attach is in the core, not a library. – Majenko Feb 16 at 0:59
  • I was talking about lowpower lol. And really? I did not realize that, I assumed it was part of lowpower. – HavocRC Feb 16 at 1:12
  • I simply put that [ USBDevice.attach(); ] into my original code in wakeUp ISR, USBCON = 0 in my sleep(), and it works perfectly! – HavocRC Feb 16 at 1:16
  • I only used lowpower for the sleeping cus it was convenient. – Majenko Feb 16 at 1:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.