int main(void) { wdt_enable(WDTO_1S); /* enable 1s watchdog */ WDTCSR &= ~(1 << WDE); /* don't reset on watchdog */ sei(); /* enable global interrupts */ set_sleep_mode(SLEEP_MODE_PWR_DOWN); /* deepest sleep mode */ power_all_disable(); /* disable all peripherals. */ /* only matters during brief awake periods, */ /* but we're saving power here. */ #if DEBUG_LED LED_DDR |= (1 << LED); /* enable LED output */ #endif while (1) { WDTCSR |= (1 << WDIE); /* re-enable watchdog interrupt */ /* (it's disabled each time it wakes up) */ sleep_mode(); /* then to go sleep */ #if DEBUG_LED LED_PORT ^= (1 << LED); /* enable LED output for diagnosis */ #endif if (days == 30) { // execute something 30 days after this started running. } } /* End event loop */ return (0); }
void Pendant::sleepNow() { disableLEDs(); PCMSK0 |= _BV(PCINT0); // Watch pin PB1 GIFR |= _BV(PCIE0); // clear any outstanding interrupts set_sleep_mode(SLEEP_MODE_PWR_DOWN); power_all_disable(); // power off ADC, Timer 0 and 1, serial interface sleep_enable(); sleep_cpu(); // // ... SLEEPING ... // // resumes here on wake sleep_disable(); power_all_enable(); // power everything back on PCMSK0 &= ~_BV(PCINT0); // Turn off PB1 as interrupt pin sleepOnRelease = false; changeModeOnRelease = false; digitalWrite(PENDANT_LED_PWR_PIN, HIGH); }
int main (void) { //we re not in a power critical environment //but nevertheless switch off everything power_all_disable(); //reset ports & pins DDRB = 0; PORTB = 0; DDRA = 0; PORTB = 0; //Start everything led_init(); led_on(); uint8_t result = accelerator_init(); if (result==0) { led_off(); led_start(); //and let the games begin sei(); } while (1) { led_calculate(); } }
// enable low-power detection and disables microcontroller modules void system_init(void) { system.initial_mcusr = MCUSR; // save MCUSR MCUSR = 0; // clear any watchdog timer flags wdt_enable(WDTO_8S); // enable eight-second watchdog timer system.status &= ~SYSTEM_SLEEP; // enable pull-up resistors on unused pins to ensure a defined value #ifndef VFD_ANODE_GRID_TO_SPEC PORTB |= _BV(PB4); #endif // ~VFD_ANODE_GRID_TO_SPEC // leave PC1 tri-stated in case clock is wired // for the depricated exteneded battery hack #ifndef VFD_CATHODE_TO_SPEC PORTC |= _BV(PC2); #endif // ~VFD_CATHODE_TO_SPEC // use internal bandgap as reference for analog comparator // and enable analog comparator interrupt on falling edge // of AIN1 (interrupt triggers when adaptor power fails) ACSR = _BV(ACBG) | _BV(ACIE) | _BV(ACI); // disable digital input on analog comparator input, AIN1 DIDR1 = _BV(AIN1D); // disable all features for power savings; individual features are enabled // one-by-one in appropriate submodules power_all_disable(); }
static inline void init(void) { power_all_disable(); debug_led_init(); clock_prescale_set(clock_div_1); spi_io_init(); adc_init(); motor_init(); sei(); }
/*function to turn off all periferlas of the radian as well as to send uC into low power mode in the event of a low battery condition */ void Radian_power_saver::EnterDeepSleepMode(){ POWER_OFF; if(DEBUG) Serial.println("Entering Deep Sleep Mode"); //Disable ADC and internal Vref digitalWrite(BOOST_EN, LOW); POWER_OFF; ADMUX &= ~( (1<<REFS1) | (1<<REFS0) ); ADCSRA &= ~( (1<<ADEN) ); //Disable AnalogComparator ACSR |= (1<<ACD); DIDR0 = 0xFF; // DIDR1 = 0xFF; DIDR2 = 0xFF; //disable watchdog timer cli(); wdt_reset(); // Clear WDRF in MCUSR MCUSR &= ~(1<<WDRF); MCUCR |= (1<<JTD);//disable on chip debug system by writing 1 to JTD bit in MCUCR // Write logical one to WDCE and WDE // Keep old prescaler setting to prevent unintentional time-out WDTCSR |= (1<<WDCE) | (1<<WDE); // Turn off WDT WDTCSR = 0x00; //disable port pins by writing to digital input disable register DIDR1 //disable USB PRR0 = 0xFF; //turn off all periferals in the power reduction registers PRR1 = 0xFF; wdt_disable(); //bod_disable(); power_usart0_disable(); power_usart1_disable(); power_spi_disable(); power_adc_disable(); power_all_disable(); POWER_OFF; cli(); //disable all interrupts SMCR = B00000101; //enable sleep mode (bit0 set) and set to POWER DOWN mode (lowest consumption) sleep_mode(); //go into sleep }
/* Configure the pins on the ATmega328p */ void InitDevice() { /* Disable all possible devices on the board */ power_all_disable(); /* LCD setup */ /* All PORTB pins are data pins for the LCD screen */ DDRB = (uint8_t)(-1); /* PDO, PD1, and PD3 are all used as control pins for the LCD screen. * PD0 is used as the R/S pin, which determines whether the LCD is getting a * command or a character * PD1 is the Enable pin, which signals the LCD to read the data pins * PD3 is the R/W Pin which is used to activate the Busy flag on the LCD and * is used for timing */ DDRD |= (_BV(PD0) | _BV(PD1) | _BV(PD3)); LcdInit(); /* Display title screen */ LcdWriteString(TITLE, LCD_LINE_ONE); LcdWriteString(NAME, LCD_LINE_TWO); _delay_ms(STARTUP_DELAY); LcdWriteString(BOOTUP, LCD_LINE_TWO); /* Calibration circuit */ /* PD4 is used to determine if the calibration circuit is active or not */ DDRD &= ~_BV(PD4); /* Configure PD4 as an input */ PORTD |= _BV(PD4); /* Pullup PD4 */ /* Configure the ADC */ //Currently not implemented //power_adc_enable(); /* Magnetometer set up */ /* INT0 is attached to the DataReady pin on the magnometer, and will be used * to signal that data is ready to be read (obviously). INT0 is set to go * off on a rising edge. */ EIMSK |= _BV(INT0); EICRA |= _BV(ISC01) | _BV(ISC00); /* Configure TWI */ power_twi_enable(); TWCR = _BV(TWEN); /* Enable TWI */ //May not be needed here, but definitely elsewhere //Check to see if the magnetometer needs initialization from the ATmega //will need init //Display "Waiting on data" on line 2 }
/******************************************************************************* * Power down processor * Don't forget to switch off the LED and the RF module for lowest consumption. * Board quiescent current budget: * charge circuit = 180 nA * ATmega328P deep sleep = 120 nA * regulators quiescent currents = 30 nA *******************************************************************************/ void TheAirBoard::powerDown() { byte br_high = UBRR0H, br_low = UBRR0L; // save baudrate register Serial.end(); digitalWrite(RX, LOW); // reset internal pull-up serial link ADCSRA &= B01111111; // disable ADC power_all_disable(); /****************DON'T CHANGE************************************************/ MCUCR = B01100000; // BOD disable timed sequence MCUCR = B01000000; SMCR = B00000101; // power down mode + sleep enable asm("sleep\n"); sleep_disable(); // first thing after wake up /****************************************************************************/ power_all_enable(); ADCSRA |= B10000000; // enable ADC UBRR0H = br_high; // set baud rate MSB UBRR0L = br_low; // set baud rate LSB UCSR0B |= (1<<RXCIE0)|(1<<UDRIE0)|(1<<RXEN0)|(1<<TXEN0); // enable uart }
void sleep() { LINCR = 0; // stop the LIN block ms_delay(20); // wait for any frame to complete (seems necessary to avoid hangs?) power_all_disable(); // turn off all of the peripherals we can // Put the board to sleep. // pinLINTX.set(); // make sure TX is 1 pinLINCS.clear(); // make sure CS is 0 pinLINCS.cfg_output(); // make sure CS is an output (will be low now) pinLINTX.cfg_output(); // make sure TX is an output (will be high now) pinLINTX.clear(); // drive TX low to turn off power for (;;) { // If we fail to power down, e.g. because LIN traffic causes the regulator to stay on, // the watchdog will pull us back out via the reset path after ~500ms. } }
int main(void) { // set clock prescaler for 8MHz CLKPR = 0x80; CLKPR = 0x01; cli(); power_all_disable(); power_spi_enable(); power_timer1_enable(); set_sleep_mode(SLEEP_MODE_IDLE); pins_init(); delay_ms(345); // arbitrary uint8_t dpi = 0x0f; // default to 800 if (!(PIND & (1<<0))) // if left is pressed at boot dpi = 0xff; // set to 12800 pmw3366_init(dpi); nrf24_init(); // button stuff // previous debounced state uint8_t btn_prev = ~(PIND); // time (in 125us) button has been unpressed. // consider button to be released if this time exceeds DEBOUNCE_TIME. uint8_t btn_time[3] = {0, 0, 0}; // absolute positions. relies on integer overflow union motion_data x = {0}, y = {0}; // wheel stuff uint8_t whl_prev_same = 0; // what A was the last time A == B uint8_t whl_prev_diff = 0; // what A was the last time A != B // absolute scroll position. relies on integer overflow int8_t whl = 0; // begin burst mode for 3366 spi_set3366mode(); SS_3366_LOW; spi_3366_write(0x50, 0x00); SS_3366_HIGH; // set up timer1 to set OCF0A in TIFR0 every 1ms TCCR1A = 0x00; TCCR1B = 0x09; // CTC, 8MHz OCR1A = 7999; // main loop nominal period (7999 + 1) / 8MHz = 1ms OCR1B = 320; // timing of when to read burst mode data from sensor OCR1C = 800; // timing of when to load nrf24l01+ with data // let receiver know if it's the first time sending data, so that it // can reset the reference for absolute position and that there's no // jump when rebooting the mouse // uint8_t first = 0x80; // transmitted as MSB with button data below. // when sync reaches 0, always send a packet with bit 6 in btn set, to // tell the receiver to calculate the timing offset. // when sync reaches 1, always send a packet requesting ACK to load the // timing offset // i.e. when it overflows, so 256ms periodicity. // when sync reaches 0, afk increments. // afk is cleared by any motion or button press. // when afk reaches AFK_TIMEOUT, go into powerdown mode. for (uint8_t first = 0x80, sync = 0, afk = 0; ; first = 0, sync++) { // sync to 1ms intervals using timer1 // if (TIFR1 & (1<<OCF1A)) PORTD |= (1<<6); TIMSK1 |= (1<<OCIE1A); sei(); sleep_mode(); cli(); TIMSK1 &= ~(1<<OCIE1A); TIFR1 |= (1<<OCF1A); TIFR1 |= (1<<OCF1B); TIFR1 |= (1<<OCF1C); // begin burst mode read spi_set3366mode(); SS_3366_LOW; spi_send(0x50); // do stuff here instead of busy waiting for 35us // read wheel int8_t dwhl = 0; const uint8_t whl_a = WHL_A_IS_HIGH; const uint8_t whl_b = WHL_B_IS_HIGH; // if (whl_a == whl_b) { // if (whl_a != whl_prev_same) { // dwhl = 2 * (whl_a ^ whl_prev_diff) - 1; // whl += dwhl; // whl_prev_same = whl_a; // } // } else // whl_prev_diff = whl_a; if (whl_a != whl_b) whl_prev_diff = whl_a; else if (whl_a != whl_prev_same) { dwhl = 2 * (whl_a ^ whl_prev_diff) - 1; whl += dwhl; whl_prev_same = whl_a; } // read buttons /* PIND 0 EIFR 0: low, no edges -> is low PIND 0 EIFR 1: low, edge -> is low PIND 1 EIFR 0: high, no edges -> always high during last 1ms PIND 1 EIFR 1: high, edge -> low at some point in the last 1ms */ const uint8_t btn_unpressed = PIND & ~(EIFR); EIFR = 0b00000111; // clear EIFR // manual loop debouncing for every button uint8_t btn_dbncd = 0x00; #define DEBOUNCE(index) \ if ((btn_prev & (1<<index)) && (btn_unpressed & (1<<index))) { \ btn_time[index]++; \ if (btn_time[index] < DEBOUNCE_TIME) \ btn_dbncd |= (1<<index); \ } else { \ btn_time[index] = 0; \ btn_dbncd |= (~btn_unpressed) & (1<<index); \ } DEBOUNCE(0); DEBOUNCE(1); DEBOUNCE(2); #undef DEBOUNCE // wait until 35us have elapsed since spi_send(0x50) // if (TIFR1 & (1<<OCF1B)) PORTD |= (1<<6); TIMSK1 |= (1<<OCIE1B); sei(); sleep_mode(); cli(); TIMSK1 &= ~(1<<OCIE1B); union motion_data dx, dy; spi_send(0x00); // motion, not used spi_send(0x00); // observation, not used dx.lo = spi_recv(); dx.hi = spi_recv(); dy.lo = spi_recv(); dy.hi = spi_recv(); SS_3366_HIGH; x.all += dx.all; y.all += dy.all; if (sync == 0) afk++; const uint8_t changed = (btn_dbncd != btn_prev) || dx.all || dy.all || dwhl; if (changed) afk = 0; if (changed || (sync <= 1)) { btn_prev = btn_dbncd; // W_TX_PAYLOAD if sync == 1, W_TX_PAYLOAD_NOACK otherwise const uint8_t mode = (sync == 1) ? 0b10100000 : 0b10110000; // send miscellaneous info using top bits of btn byte uint8_t btn_send = btn_dbncd | first; // first is either 0x80 or 0 if (sync == 0) btn_send |= 0x40; // try to transmit at the same time every frame // if (TIFR1 & (1<<OCF1C)) {PORTD |= (1<<6);} TIMSK1 |= (1<<OCIE1C); sei(); sleep_mode(); cli(); TIMSK1 &= ~(1<<OCIE1C); spi_setnrf24mode(); SS_NRF24_LOW; spi_send(0x20 | 0x07); // STATUS spi_send(0b01110000); // clear IRQ SS_NRF24_HIGH; SS_NRF24_LOW; spi_send(0b11100001); // flush tx SS_NRF24_HIGH; SS_NRF24_LOW; spi_send(0b11100010); // flush rx SS_NRF24_HIGH; SS_NRF24_LOW; spi_send(mode); spi_send(btn_send); spi_send(x.lo); spi_send(x.hi); spi_send(y.lo); spi_send(y.hi); spi_send(whl); SS_NRF24_HIGH; // pulse CE to transmit CE_HIGH; delay_us(12); CE_LOW; if (sync == 1) { // get ack payload of timing offset delay_us(400); if (IRQ_IS_LOW) { // recycle motion_data union for timing union motion_data offset; SS_NRF24_LOW; spi_send(0b01100001); offset.lo = spi_recv(); offset.hi = spi_recv(); SS_NRF24_HIGH; // shift TCNT1 by the offset, plus a // little more because of the time it // takes to add stuff to TCNT1. TCNT1 += offset.all + 11; } } } // power down if afk if (afk > AFK_TIMEOUT) { // enable external interrupts on INT0/1/2/3, PCINT0 EIMSK = 0b00000111; PCICR = 0x01; // go power down mode; wake up on interrupt set_sleep_mode(SLEEP_MODE_PWR_DOWN); sei(); sleep_mode(); cli(); // disable external interrupts PCICR = 0; EIMSK = 0; // restore state set_sleep_mode(SLEEP_MODE_IDLE); sync = 0; afk = 0; } } }