Page 1 of 1

Powersaving USB device

Posted: Fri Jan 01, 2010 10:52 pm
by qdot
Do you guys have any suggestions how to optimize power consumption of a device while it's not connected (and thus not charging) from the USB bus?

I'm running out of IO ports, so I'm thinking 1M pullup on D+, and? how can I tell from inside the main poll loop if we're connected to the USB master and should never enter sleep states above 'idle' (otherwise interrupt wakeup will take more than 25 cycles :(), and when we're on battery and should be going as low as power down?

Device: attiny84, external 16MHz oscillator.

Re: Powersaving USB device

Posted: Thu Jan 07, 2010 12:22 pm
by christian
I have a low power USB design which uses the following tricks to reduce battery consumption:
(1) The design uses a 32 kHz crystal and synchronizes the RC oscillator to it.
(2) When USB is connected, the main clock frequency is synchronized to 12.8 MHz, without USB, we use 1 MHz.
(3) Every 1 s interval we poll for USB connectivity:

Code: Select all

static void usbModeEnter(void)
{
static const prog_char usbText[16] =    "  USB   "
                                        "  MODE  ";
    powerWasOn = powerIsOn;
    if(!powerIsOn)
        powerOn();
    logSetRunning(0);
    powerRegulatorOff();                // ensure that voltage regulator is not operated at 12 Mhz
    usbDeviceDisconnect();
    dispFillConst(usbText);
    displaySendContent(displayRam[0]);
    _delay_ms(200);
    usbStoredOsccal = OSCCAL;
    OSCCAL = usbOsccal;
    clock_prescale_set(clock_div_1);    // turbo boost...
    usbInit();
    isUsbMode = 1;
    usbDeviceConnect();
}

static void usbModeLeave(void)
{
    USB_INTR_ENABLE &= ~M1(USB_INTR_ENABLE_BIT);
    clock_prescale_set(clock_div_8);    // back to normal speed
    usbOsccal = OSCCAL;
    OSCCAL = usbStoredOsccal;
    PORT_DDR_SET(PIN_USB_DMINUS);
    PORT_DDR_SET(PIN_USB_DPLUS);
    isUsbMode = 0;
    needUpdate = 1;
    powerRegulatorOn();
    if(!powerWasOn)
        powerOff();
    fifoFlush();
}

static void pollUsbMode(void)
{
    if(isUsbMode){
        uchar i;
        for(i = 0; i < 3; i++){
            uchar x = PORT_IN(PIN_USB_DMINUS);
            x &= M1(PORT_BIT(PIN_USB_DPLUS)) | M1(PORT_BIT(PIN_USB_DMINUS));
            if(x == M1(PORT_BIT(PIN_USB_DMINUS)))   // valid USB idle mode
                return;
        }
        // if we did not detect valid USB idle status 3 times in a row, leave USB mode
        usbModeLeave();
    }else{
        PORT_DDR_CLR(PIN_USB_DMINUS);
        _delay_us(5);
        if(PORT_PIN_VALUE(PIN_USB_DMINUS)){ // if we have a pull-up
            usbModeEnter();
        }else{
            PORT_DDR_SET(PIN_USB_DMINUS);
        }
    }
}

(4) The supply voltage is reduced to the battery voltage when possible. Otherwise we use a step-up converter.

The USB connectivity check works by sampling D-. Since the 1k5 pull-up is connected to USB supply, D- is low without USB connection. You must decouple the USB supply with a diode, though, so that the battery can't power the pull-up.