Hi AVR experts!
The setup:
I use a device that performs a man-in-the-middle attack on the CAN bus in my electric car. The board allow my car to use a newer battery that it came with. It is extremely vital for the function of the whole car, without it the car shuts off and goes into limp mode.
Here is the hardware: https://www.tindie.com/products/...
It is running an XMEGA32C4 along with some CAN controllers that interface to it via SPI
The issue:
The board uses a lot of power even when the car is off. It consumes ca 35mA. This kills the 12V battery if you don't drive the car for 5-7days.
My question. Is it possible to even use some sleep settings here to save power? The board need to be responsive and trigger immediately when a CAN message comes, since without the board, CAN messages wont be transmitted between the battery and the car.
Here is what the HW setup looks like, don't know if this helps.
void hw_init(void){ uint8_t caninit; /* Start the 32MHz internal RC oscillator and start the DFLL to increase it to 48MHz using the USB SOF as a reference */ XMEGACLK_StartInternalOscillator(CLOCK_SRC_INT_RC32MHZ); XMEGACLK_StartDFLL(CLOCK_SRC_INT_RC32MHZ, DFLL_REF_INT_USBSOF, 48000000); //turn off everything we don' t use PR.PRGEN = PR_AES_bm | PR_RTC_bm | PR_DMA_bm; PR.PRPA = PR_ADC_bm | PR_AC_bm; PR.PRPC = PR_TWI_bm | PR_USART0_bm | PR_HIRES_bm; PR.PRPD = PR_TWI_bm | PR_USART0_bm | PR_TC0_bm | PR_TC1_bm; PR.PRPE = PR_TWI_bm | PR_USART0_bm; //blink output PORTB.DIRSET = 3; //start 16MHz crystal and PLL it up to 48MHz OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | //16MHz crystal OSC_XOSCSEL_XTAL_16KCLK_gc; //16kclk startup OSC.CTRL |= OSC_XOSCEN_bm; //enable crystal while(!(OSC.STATUS & OSC_XOSCRDY_bm)); //wait until ready OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 2; //XTAL->PLL, 2x multiplier (32MHz) OSC.CTRL |= OSC_PLLEN_bm; //start PLL while (!(OSC.STATUS & OSC_PLLRDY_bm)); //wait until ready CCP = CCP_IOREG_gc; //allow changing CLK.CTRL CLK.CTRL = CLK_SCLKSEL_PLL_gc; //use PLL output as system clock //output 16MHz clock to MCP25625 chips (PE0) //next iteration: put this on some other port, pin 4 or 7, so we can use the event system TCE0.CTRLA = TC0_CLKSEL_DIV1_gc; //clkper/1 TCE0.CTRLB = TC0_CCAEN_bm | TC0_WGMODE_SINGLESLOPE_bm; //enable CCA, single-slope PWM TCE0.CCA = 1; //compare value TCE0.PER = 1; //period of 1, generates 24MHz output PORTE.DIRSET = PIN0_bm; //set CLKOUT pin to output //setup CAN pin interrupts PORTC.INTCTRL = PORT_INT0LVL_HI_gc; PORTD.INTCTRL = PORT_INT0LVL_HI_gc | PORT_INT1LVL_HI_gc; PORTD.INT0MASK = PIN0_bm; //PORTD0 has can1 interrupt PORTD.PIN0CTRL = PORT_OPC_PULLUP_gc | PORT_ISC_LEVEL_gc; PORTD.INT1MASK = PIN5_bm; //PORTD5 has can2 interrupt PORTD.PIN5CTRL = PORT_OPC_PULLUP_gc | PORT_ISC_LEVEL_gc; #ifndef DISABLE_CAN3 PORTC.INT0MASK = PIN2_bm; //PORTC2 has can3 interrupt PORTC.PIN0CTRL = PORT_OPC_PULLUP_gc | PORT_ISC_LEVEL_gc; #endif //buffer checking interrupt TCC1.CTRLA = TC0_CLKSEL_DIV1_gc; //48M/1/4800 ~ 100usec TCC1.PER = 4800; TCC1.INTCTRLA = TC0_OVFINTLVL_HI_gc; //same priority as can interrupts //we want to optimize performance, so we're going to time stuff //48MHz/48=1us timer, which we just freerun and reset whenever we want to start timing something //frame time timer TCC0.CTRLA = TC0_CLKSEL_DIV1_gc; TCC0.PER = 48000; //48MHz/48000=1ms TCC0.INTCTRLA = TC0_OVFINTLVL_HI_gc; //interrupt on overflow PORTB.OUTCLR = (1 << 0); can_system_init: //Init SPI and CAN interface: if(RST.STATUS & RST_WDRF_bm){ //if we come from a watchdog reset, we don't need to setup CAN caninit = can_init(MCP_OPMOD_NORMAL, 1); //on second thought, we do } else { caninit = can_init(MCP_OPMOD_NORMAL, 1); } if(caninit){ PORTB.OUTSET |= (1 << 0); //green LED } else { PORTB.OUTSET |= (1 << 1); //red LED _delay_ms(10); goto can_system_init; } //Set and enable interrupts with round-robin XMEGACLK_CCP_Write((void * ) &PMIC.CTRL, PMIC_RREN_bm | PMIC_LOLVLEN_bm | PMIC_HILVLEN_bm);//PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm| PMIC_HILVLEN_bm; USB_Init(USB_OPT_RC32MCLKSRC | USB_OPT_BUSEVENT_PRILOW); CDC_Device_CreateStream(&VirtualSerial_CDC_Interface, &USBSerialStream); wdt_enable(WDTO_15MS); sei(); }
Thank you for looking :)