/* * mega32m1_sleep.c * * Created: 17/05/2018 14:01:51 * Author : Aner Torre * * Sleep modes test. The main purpose of this test is to demonstrate which sleep modes * can the CAN message RX interrupts wake the MCU from. Blinks a LED for 4 times * and enters sleep_mode until the MCU is waken by receiving CAN message RX interrupt * * The results show that CAN message received interrupts ( ISR(CAN_INT_vect) ) can ONLY * wake the MCU from SLEEP_MODE_IDLE. * Power consumptions (INCLUDING MCP2561 CAN transceiver): * - NORMAL FUNCTION: about 10 mA * - SLEEP_MODE_IDLE: about 9 mA * - SLEEP_MODE_PWR_DOWN: about 4.5 mA */ #ifndef F_CPU #define F_CPU 8000000UL #endif #include #include #include #include #include #include volatile bool msg_rcv = 0; volatile uint16_t id = 0; volatile uint8_t data[8]; ISR (CAN_INT_vect) { int8_t length, savecanpage; savecanpage = CANPAGE; // Save current MOB CANPAGE = CANHPMOB & 0xF0; // Selects MOB with highest priority interrupt if (CANSTMOB & (1 << RXOK)) { // Interrupt caused by receive finished id = ((uint16_t)CANIDT2 >> 5) | ((uint16_t)CANIDT1 << 3); // considering 11 bit ID (CAN v2.0A) length = (CANCDMOB & 0x0F); // DLC, number of bytes to be received for (int8_t i = 0; i < length; i++) data[i] = CANMSG; // Get data, INDX auto increments CANMSG CANCDMOB = ((1 << CONMOB1) | (0 << IDE) | (8 << DLC0)); // Enable Reception 11 bit IDE DLC8 msg_rcv = 1; } CANSTMOB = 0x00; // Reset reason on selected channel CANPAGE = savecanpage; // Restore original MOB } void chip_init(void) { // defining all pins as OUTPUT reduces power consumption DDRB = 0xFF; DDRC = 0xFF; DDRD = 0xFF; DDRE = 0xFF; PORTB = 0xFE; PORTC = 0x00; PORTD = 0x00; PORTE = 0x00; PRR = 0x00; // Individual peripheral clocks enabled } void can_init(void) { CANGCON = ( 1 << SWRES ); // Software reset CANTCON = 0x00; // CAN timing prescaler set to 0; // Set baud rate to 500 kbit/s (with 8Mhz internal osc) CANBT1 = 0x02; CANBT2 = 0x04; CANBT3 = 0x13; for (int8_t mob = 0; mob < 6; mob++) { CANPAGE = (mob << 4); // Selects Message Object 0-5 CANCDMOB = 0x00; // Disable mob CANSTMOB = 0x00; // Clear mob status register; } CANPAGE = ( 1 << MOBNB0 ); // Select MOB1 CANIE2 = ( 1 << IEMOB1 ); // Enable interrupts on MOB1 for reception and transmission CANGIE = ( 1 << ENIT ) | ( 1 << ENRX ) /*| ( 1 << ENTX )*/; // Enable interrupts ONLY on receive // Filter all IDs not matching (all except 0x201) CANIDT1 = (uint8_t) (0x201 >> 3); CANIDT2 = (uint8_t) (0x201 << 5); CANIDT3 = 0x00; CANIDT4 = 0x00; // mask = 0b11111111111 CANIDM1 = 0xFF >> 3; CANIDM2 = 0xFF << 5; CANIDM3 = 0x00; CANIDM4 = (1 << RTRMSK) | (1 << IDEMSK); //CANCDMOB = ( 1 << CONMOB1) | ( 1 << IDE ) | ( 8 << DLC0); // Use this to enable reception 29 bit IDE DLC8 (CAN v2.0B) CANCDMOB = ( 1 << CONMOB1) | ( 0 << IDE ) | ( 8 << DLC0); // Use this to enable reception 11 bit IDE DLC8 (CAN v2.0A) CANGCON |= (1 << LISTEN); // Put CAN in LISTEN mode (no ACK) CANGCON |= ( 1 << ENASTB ); // Enable mode. CAN channel enters in enable mode once 11 recessive bits have been read sei(); } int main(void) { chip_init(); can_init(); DDRB |= (1 << PB7); while (1) { // Test different sleep modes // set_sleep_mode(SLEEP_MODE_IDLE); // sleep_mode(); // interrupt_wait(); // // set_sleep_mode(SLEEP_MODE_STANDBY); // sleep_mode(); // interrupt_wait(); // // /* Three times power down to differentiate */ // set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep_mode(); // set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep_mode(); // set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep_mode(); // interrupt_wait(); // Blink LED for (3 + 1) times and enter SLEEP_MODE_IDLE until CAN RX interrupt. Then, continue... for (uint8_t i = 0; i < 6; i++) { PORTB &= ~(1 << PB7); _delay_ms(1000); PORTB |= (1 << PB7); _delay_ms(1000); if (i == 3) { set_sleep_mode(SLEEP_MODE_IDLE); sleep_mode(); } } _delay_ms(9); } return(0); }