Is it possible to sleep when you need to be on your toes? [XMEGA32C4]

Go To Last Post
15 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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 :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Firstly, can the hardware (apart from the xmega) be put into a low power mode?
The xmega sleeping would be relatively easy - if you get an interrupt from a can controller- that will wake the xmega.

I suspect the other hardware is going to be the main stumbling block.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Why isn't it simply powered by the ignition switched 12V circuit. So it simply isn't powered when the ignition is off?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

The term ‘ignition’ seems strange when talking about an electric car!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
Firstly, can the hardware (apart from the xmega) be put into a low power mode? The xmega sleeping would be relatively easy - if you get an interrupt from a can controller- that will wake the xmega. I suspect the other hardware is going to be the main stumbling block.

Yes, there are three interrupts coming from the CAN interfaces,
ISR(PORTD_INT0_vect)
ISR(PORTD_INT1_vect)
ISR(PORTC_INT0_vect)

clawson wrote:

Why isn't it simply powered by the ignition switched 12V circuit. So it simply isn't powered when the ignition is off?


We tried this, but it misses the critical wake up CAN messages that are sent first and only once. So the startup of the chip is too long for this. Also, some CAN messages are sent even though the car is not on (like request heating start via smartphone app), so this strategy is not viable

Kartman wrote:
The term ‘ignition’ seems strange when talking about an electric car!

Yeah, but it still applies :D

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Startup is ‘too long’ - how much is ‘too long’?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So as soon as +12V reaches the vehicle control module, it spits out a 0x603 wake-up CAN message to all other modules on the bus. If the MITM device was also actuated by the +12V, it misses this first critical message, and this sets multiple TDCs along with a car that won't boot until the codes are cleared.

 

It wouldn't even help if it would boot faster, since there are also wake-up messages coming via 4G connection to the car, that doesn't set the +12V high.

 

So this leaves me with the sleep idle command. I experimented with throwing it in the main loop, and it lowered the power consiumption to 28.8mA (Starting point was 34.2mA). Still would have hoped for a bit more...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How are you sure the bulk of the power consumption is the xmega and not the CAN controller and transceiver chips?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dalathegreat wrote:

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.

 

35 milli ampere * 7 day in (ampere hour) = 5.88 (ampere hour)

 

Well that's a mickey mouse sized battery for an electric car. My calculation is correct so what have we missed.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

35 milli ampere * 7 day

Been there.

 

When I was prototyping a GPS tracker the board kept the GPS powered up so that it would do a warm start, (very fast boot up), instead of a cold start, (download satellite database, find sats, finally lock on), and miss the first part of the vehicle's trip.

It drew about the same current as above, (35mA or so, perhaps a little bit more), and like the OP, it would kill the battery if the car sat for a few days.

 

The siren on my car also draws a standby current, even when "Off".  It can easily kill the battery if the car isn't used for a few days.

Whenever I travel for vacation, or a conference, I always have to unplug the wiring harness for the siren.

When installed in a usual emergency vehicle (Fire and EMS) the vehicle has a "shoreline", to plug the vehicle into a Mains power supply and trickle charge the battery, and power the various devices and equipment chargers installed in the vehicle.

Police cars don't have shorelines as the cars are usually in use, and don't sit for days on end.

 

I recall looking into this issue, (years ago).

One of the car dealers tracked down a spec for me about the baseline current that the car's systems were allowed to draw when the vehicle was off.

IIRC it was only a couple of mA !

 

JC 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For example, the Prius (hybrid I know..) has a 12V battery in addition to the main storage battery. Not sure what pure electric vehicles use - maybe they too have a 12V battery for accessories?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
For example, the Prius (hybrid I know..) has a 12V battery in addition to the main storage battery. Not sure what pure electric vehicles use - maybe they too have a 12V battery for accessories?

All Tesla models do.  They are recharged from the main battery, and if the main battery goes too low, the 12V battery will soon be discharged thereafter.

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

Last Edited: Tue. Apr 14, 2020 - 02:22 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are correct, but: Problem is that the early Leaf models have a bug in the 12V lead acid charging algorithm, that makes them susceptible to parasitic drains. It simply won't turn on the charging long enough, and there is a time delay that is too big inbetween the periodic charging events. So I need lower power consumption.

 

This bug only affects my customer cars, (2011-2013). My personal car is a 2015 model that turns on the charging properly, so I'm not so affected by this.

 

I don't know if it is even possible to get it much lower than 28mA with the sleep, but I will continue to experiment. If I kill the CAN chips (by disabling the output from xmega) consumption drops to 24mA, but then it will be impossible to recover from sleep.

Last Edited: Tue. Apr 14, 2020 - 10:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dalathegreat wrote:
early Leaf models have a bug in the 12V lead acid charging algorithm

I would have expected Nissan to have released a software update to fix that. Early adopters of new tech should receive a great deal of support while the inevitable problems are sorted out.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Solution: use a microcontroller that wakes up faster and has 2+ CAN controllers on chip.

 

Back to your original problem - surely the can controller will buffer incoming CAN messages and give the xmega an interrupt. Surely the xmega can wake up in sufficient time to read the message and do whatever necessary? I'd expect the xmega to wake up in microseconds especially if no crystal is required (I gather the CAN controllers have their own oscillator).