Electronic – AVR (at90usb1286) sleep and USB

avrsleepusb

I am using an AVR at90usb1286-based Teensy++ 2.0 to periodically read data from a few sensors. In its final form, my project will act based on the sensor inputs. For now, I log the results to the USB port.

Because the measurement interval is relatively long I am placing the microcontroller in powersaving sleep between measurements and using the watchdog timer to wake up periodically. This works just fine, but after waking up the USB connection does not work anymore and I have found no way to get it back

I am using PJRCs Debug Only USB library together with their host-side component hid_listen.exe.

Because of its debug function, I would like the solution to impact as little as possible the structure of the code.

I have tried three strategies so far:

  1. Entering powersaving sleep (SLEEP_MODE_PWR_SAVE) without any special precautions. I get an "USB Device Not Recognized" error from windows7 and no additional communication is possible.
  2. Entering a sleep mode that keeps the USB active (SLEEP_MODE_IDLE). In this mode the USB keeps functioning, but the sleep is interrupted pretty much immediately.
  3. Entering powersaving sleep (SLEEP_MODE_PWR_SAVE) and trying to re-initialize the USB afterward by calling usb_init(). This does not seem to have any effect.

Here is a simplified application that shows the problem, adapted from this lesson 13

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <avr/power.h>
#include <avr/sleep.h>

#include "usb_debug_only.h"
#include "print.h"

ISR(WDT_vect, ISR_NAKED){
    _WD_CONTROL_REG = _BV(WDIE); // must reset interrupt after trigger
    /* do other work inside the watchdog interrupt? */
    PIND = _BV(PD6); /* toggle the pin */
    reti();
}

int main(void){
    DDRD = _BV(PD6);
    PORTD = _BV(PD6);
    /* watchdog setup goo */
    wdt_enable(WDTO_1S);
    _WD_CONTROL_REG = _BV(WDIE); /* generate watchdog interrupts */
    usb_init();

    sei(); /* enable interrupts */

    while(1){
        set_sleep_mode(SLEEP_MODE_PWR_SAVE);
        sleep_mode();
        print("a");
        usb_debug_flush_output();
        /* Do stuff after the watchdog wakes us up */
    }
}

Questions

Considering the given hardware, what are good strategies to put the controller into a sleep state while maintaining some form of debug output capability?

I am not concerned about power consumption, as the USB will be inactive in battery-powered production mode. However, I do wish to be able to get some debug output while I'm writing the program…

Best Answer

IIRC electrically you just have to toggle the pull-up resistor connected to D+ (or was it D-) so I would try manually setting and clearing (with a small delay in between) the DETACH bit in the UDCON register.

In both the LUFA and V-USB libraries there were no problems with disconnecting and reconnecting to USB from software. I guess USB_Init did this by itself in those.