//----------------------------------------------------------------------------------------------------------------- // SPI als Master initialisieren //----------------------------------------------------------------------------------------------------------------- void spi_master_init(uint8_t freq_div, bool lsb_first, uint8_t spi_mode) { //Power einschalten für das SPI-Interface: //PRSPI-Bit im PRR0-Register auf 0 setzen // now use the avr-lib for this! // Not all Atmels support this! #ifdef PRSPI power_spi_enable(); #endif //Portpins des SPI initialisieren SPI_DDR |= _BV(SPI_CLK_PIN) | _BV(SPI_MOSI_PIN); SPI_DDR &= ~_BV(SPI_MISO_PIN); //SPI als Master SPCR = (1<<SPE)|(1<<MSTR); //Frequenzteiler einstellen SPCR |= freq_div; //Übertragungsmodus 0...3 SPCR |= spi_mode << 2; //LSB oder MSB first if(lsb_first) SPCR |= (1<<DORD); }
// Initialize SPI Slave Mode (polling) void init_spi_slave_polling (void) { // Set PB4(MISO) as output. PB3(MOSI), PB2(SS), and PB5(SCK) are input DDRB = (1<<DDB4); // Enable SPI in Slave Mode SPCR = (1<<SPE); power_spi_enable(); }
// SPI Interrupt Initialization for Slave Mode void init_spi_slave_int (void) { power_spi_enable(); // Set PB4(MISO) as output DDRB = (1<<DDB4); // Enable SPI Interrupt and SPI in Slave Mode SPCR = (1<<SPIE)|(1<<SPE); }
void Transceiver::Wakeup() { if (_inSleep){ _inSleep=false; power_spi_enable(); buffer->Wakeup(); DBGPINHIGH(); DBGINFO("wakeup"); } }
void cube_start(uint8_t unused) { // Set sleep mode to lighter mode = old_mode; power_adc_enable(); power_spi_enable(); power_timer0_enable(); power_timer1_enable(); // Enable BLANK timer interrupt (starts SPI) TIMSK0 |= (1 << OCIE0A); }
/********************************************************************************************************* ** Function name: wakeUp ** Descriptions: wakeUp *********************************************************************************************************/ void xadow::wakeUp() { #if defined(__AVR_ATmega32U4__) power_adc_enable(); power_usart0_enable(); power_spi_enable(); power_twi_enable(); power_timer1_enable(); power_timer2_enable(); power_timer3_enable(); power_usart1_enable(); power_usb_enable(); #endif }
void Low_Power::idle(Period_t period, ADC_t adc, Timer4_t timer4, Timer3_t timer3, Timer1_t timer1, Timer0_t timer0, SPI_t spi, USART1_t usart1, TWI_t twi, usb_t usb) { if (adc == ADC_OFF) { ADCSRA &= ~(1 << ADEN); power_adc_disable(); } if (timer4 == TIMER4_OFF) power_timer4_disable(); if (timer3 == TIMER3_OFF) power_timer3_disable(); if (timer1 == TIMER1_OFF) power_timer1_disable(); if (timer0 == TIMER0_OFF) power_timer0_disable(); if (spi == SPI_OFF) power_spi_disable(); if (usart1 == USART1_OFF) power_usart1_disable(); if (twi == TWI_OFF) power_twi_disable(); if (usb == USB_OFF) power_usb_disable(); if (period != SLEEP_FOREVER) { wdt_enable(period); WDTCSR |= (1 << WDIE); } lowPowerBodOn(SLEEP_MODE_IDLE); if (adc == ADC_OFF) { power_adc_enable(); ADCSRA |= (1 << ADEN); } if (timer4 == TIMER4_OFF) power_timer4_enable(); if (timer3 == TIMER3_OFF) power_timer3_enable(); if (timer1 == TIMER1_OFF) power_timer1_enable(); if (timer0 == TIMER0_OFF) power_timer0_enable(); if (spi == SPI_OFF) power_spi_enable(); if (usart1 == USART1_OFF) power_usart1_enable(); if (twi == TWI_OFF) power_twi_enable(); if (usb == USB_OFF) power_usb_enable(); }
// enable hardware SPI void spi_init(void) { DDR_SPI &= ~( DD_MOSI | DD_MISO | DD_SS | DD_SCK ); DDR_SPI |= (DD_MOSI | DD_SS | DD_SCK); // enable pull-ups since this is not done in hardware PORT_SPI |= (DD_MOSI | DD_SS | DD_MISO | DD_SCK); power_spi_enable(); SPCR = ((0 << SPIE) | // SPI interrupt enable (1 << SPE) | // SPI enable (0 << DORD) | // data order (0=MSB first, 1=LSB first) (1 << MSTR) | // 1=master 0=slave (0 << CPOL) | // clock polarity (0:SCK low / 1:SCK hi when idle) (0 << CPHA) | // clock phase (0:leading / 1:trailing edge sampling) (1 << SPR1) | // SPI clock rate (0 << SPR0) ); SPSR = (1 << SPI2X); // Double Clock Rate }
void Low_Power::idle(Period_t period, ADC_t adc, Timer5_t timer5, Timer4_t timer4, Timer3_t timer3, Timer2_t timer2, Timer1_t timer1, Timer0_t timer0, SPI_t spi, USART3_t usart3, USART2_t usart2, USART1_t usart1, USART0_t usart0, TWI_t twi) { // Temporary clock source variable unsigned char clockSource = 0; if (timer2 == TIMER2_OFF) { if (TCCR2B & CS22) clockSource |= (1 << CS22); if (TCCR2B & CS21) clockSource |= (1 << CS21); if (TCCR2B & CS20) clockSource |= (1 << CS20); // Remove the clock source to shutdown Timer2 TCCR2B &= ~(1 << CS22); TCCR2B &= ~(1 << CS21); TCCR2B &= ~(1 << CS20); power_timer2_disable(); } if (adc == ADC_OFF) { ADCSRA &= ~(1 << ADEN); power_adc_disable(); } if (timer5 == TIMER5_OFF) power_timer5_disable(); if (timer4 == TIMER4_OFF) power_timer4_disable(); if (timer3 == TIMER3_OFF) power_timer3_disable(); if (timer1 == TIMER1_OFF) power_timer1_disable(); if (timer0 == TIMER0_OFF) power_timer0_disable(); if (spi == SPI_OFF) power_spi_disable(); if (usart3 == USART3_OFF) power_usart3_disable(); if (usart2 == USART2_OFF) power_usart2_disable(); if (usart1 == USART1_OFF) power_usart1_disable(); if (usart0 == USART0_OFF) power_usart0_disable(); if (twi == TWI_OFF) power_twi_disable(); if (period != SLEEP_FOREVER) { wdt_enable(period); WDTCSR |= (1 << WDIE); } lowPowerBodOn(SLEEP_MODE_IDLE); if (adc == ADC_OFF) { power_adc_enable(); ADCSRA |= (1 << ADEN); } if (timer2 == TIMER2_OFF) { if (clockSource & CS22) TCCR2B |= (1 << CS22); if (clockSource & CS21) TCCR2B |= (1 << CS21); if (clockSource & CS20) TCCR2B |= (1 << CS20); power_timer2_enable(); } if (timer5 == TIMER5_OFF) power_timer5_enable(); if (timer4 == TIMER4_OFF) power_timer4_enable(); if (timer3 == TIMER3_OFF) power_timer3_enable(); if (timer1 == TIMER1_OFF) power_timer1_enable(); if (timer0 == TIMER0_OFF) power_timer0_enable(); if (spi == SPI_OFF) power_spi_enable(); if (usart3 == USART3_OFF) power_usart3_enable(); if (usart2 == USART2_OFF) power_usart2_enable(); if (usart1 == USART1_OFF) power_usart1_enable(); if (usart0 == USART0_OFF) power_usart0_enable(); if (twi == TWI_OFF) power_twi_enable(); }
/******************************************************************************* * Name: idle * Description: Putting microcontroller into idle state. Please make sure you * understand the implication and result of disabling module. * * Argument Description * ========= =========== * 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake * up resource: * (a) SLEEP_15MS - 15 ms sleep * (b) SLEEP_30MS - 30 ms sleep * (c) SLEEP_60MS - 60 ms sleep * (d) SLEEP_120MS - 120 ms sleep * (e) SLEEP_250MS - 250 ms sleep * (f) SLEEP_500MS - 500 ms sleep * (g) SLEEP_1S - 1 s sleep * (h) SLEEP_2S - 2 s sleep * (i) SLEEP_4S - 4 s sleep * (j) SLEEP_8S - 8 s sleep * (k) SLEEP_FOREVER - Sleep without waking up through WDT * * 2. adc ADC module disable control: * (a) ADC_OFF - Turn off ADC module * (b) ADC_ON - Leave ADC module in its default state * * 3. timer2 Timer 2 module disable control: * (a) TIMER2_OFF - Turn off Timer 2 module * (b) TIMER2_ON - Leave Timer 2 module in its default state * * 4. timer1 Timer 1 module disable control: * (a) TIMER1_OFF - Turn off Timer 1 module * (b) TIMER1_ON - Leave Timer 1 module in its default state * * 5. timer0 Timer 0 module disable control: * (a) TIMER0_OFF - Turn off Timer 0 module * (b) TIMER0_ON - Leave Timer 0 module in its default state * * 6. spi SPI module disable control: * (a) ADC_OFF - Turn off ADC module * (b) ADC_ON - Leave ADC module in its default state * * 7. usart0 USART0 module disable control: * (a) USART0_OFF - Turn off USART0 module * (b) USART0_ON - Leave USART0 module in its default state * * 8. twi TWI module disable control: * (a) TWI_OFF - Turn off TWI module * (b) TWI_ON - Leave TWI module in its default state * *******************************************************************************/ void LowPowerClass::idle(period_t period, adc_t adc, timer2_t timer2, timer1_t timer1, timer0_t timer0, spi_t spi, usart0_t usart0, twi_t twi) { // Temporary clock source variable unsigned char clockSource = 0; if (timer2 == TIMER2_OFF) { if (TCCR2B & CS22) clockSource |= (1 << CS22); if (TCCR2B & CS21) clockSource |= (1 << CS21); if (TCCR2B & CS20) clockSource |= (1 << CS20); // Remove the clock source to shutdown Timer2 TCCR2B &= ~(1 << CS22); TCCR2B &= ~(1 << CS21); TCCR2B &= ~(1 << CS20); power_timer2_disable(); } if (adc == ADC_OFF) { ADCSRA &= ~(1 << ADEN); power_adc_disable(); } if (timer1 == TIMER1_OFF) power_timer1_disable(); if (timer0 == TIMER0_OFF) power_timer0_disable(); if (spi == SPI_OFF) power_spi_disable(); if (usart0 == USART0_OFF) power_usart0_disable(); if (twi == TWI_OFF) power_twi_disable(); if (period != SLEEP_FOREVER) { wdt_enable(period); WDTCSR |= (1 << WDIE); } lowPowerBodOn(SLEEP_MODE_IDLE); if (adc == ADC_OFF) { power_adc_enable(); ADCSRA |= (1 << ADEN); } if (timer2 == TIMER2_OFF) { if (clockSource & CS22) TCCR2B |= (1 << CS22); if (clockSource & CS21) TCCR2B |= (1 << CS21); if (clockSource & CS20) TCCR2B |= (1 << CS20); power_timer2_enable(); } if (timer1 == TIMER1_OFF) power_timer1_enable(); if (timer0 == TIMER0_OFF) power_timer0_enable(); if (spi == SPI_OFF) power_spi_enable(); if (usart0 == USART0_OFF) power_usart0_enable(); if (twi == TWI_OFF) power_twi_enable(); }
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; } } }
// Shutdown void bg_pwr_down() { // execute sleep routine if (bg_pwr_exec_sleep_routine_flag) { if (bg_pwr_on_sleep != NULL) bg_pwr_on_sleep(); // the flag is needed because we want to execute sleep // routine only when we go from pwr up to pwr down bg_pwr_exec_sleep_routine_flag = 0; } //Shut off ADC, TWI, SPI, Timer0, Timer1, Timer2 ADCSRA &= ~(1<<ADEN); //Disable ADC ACSR |= (1<<ACD); //Disable the analog comparator DIDR0 = 0xFF; //Disable digital input buffers on all ADC0-ADC5 pins DIDR1 = (1<<AIN1D)|(1<<AIN0D); //Disable digital input buffer on AIN1/0 power_twi_disable(); power_spi_disable(); power_usart0_disable(); power_timer0_disable(); power_timer1_disable(); power_timer2_disable(); #if defined(__AVR_ATmega1284P__) power_timer3_disable(); #endif //Power down various bits of hardware to lower power usage set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_mode(); /*********/ /* SLEEP */ /*********/ // The processor wakes up back here after interrupt //Turn on ADC, TWI, SPI, Timer0, Timer1, Timer2 ADCSRA |= (1<<ADEN); // Enable ADC ACSR &= ~(1<<ACD); // Enable the analog comparator // this should be set to reflect real usage of analog pins DIDR0 = 0x00; // Enable digital input buffers on all ADC0-ADC5 pins DIDR1 &= ~(1<<AIN1D)|(1<<AIN0D); // Enable digital input buffer on AIN1/0 power_twi_enable(); power_spi_enable(); power_usart0_enable(); power_timer0_enable(); power_timer1_enable(); power_timer2_enable(); #if defined(__AVR_ATmega1284P__) power_timer3_enable(); #endif // check button press time and handle state unsigned long start = millis(); while ( (ellapsed_millis(start) < BG_PWR_BUTTON_TIME) && (digitalRead(bg_pwr_switch_pin) == HIGH) ); // if the button is pressed continuously for 2 seconds, swap to on state if (ellapsed_millis(start) >= BG_PWR_BUTTON_TIME) bg_pwr_state = BG_STATE_PWR_UP; // lower the button flag bg_pwr_button_pressed_flag = 0; // execute wake up routine only if we really woke up if (bg_pwr_state == BG_STATE_PWR_UP || sd_reader_interrupted) { // execute wake up routine if any is defined if (bg_pwr_on_wakeup != NULL) bg_pwr_on_wakeup(); // next time we sleep execute sleep routine bg_pwr_exec_sleep_routine_flag = 1; } }