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.