This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Not remaining in sleep after servicing timer ISR

Other Parts Discussed in Thread: TM4C123GH6PM

I'm using a TM4C123GH6PM.

I'm trying to get a sleep mode working for my project. The idea is the MCU will go into sleep mode and wake up about 30 times a second to check various states and see if a power up is required.   I've managed to enter sleep mode and set up a timer, the problem is, as soon as my first timer interrupt arrives, the MCU wakes up again.

If I disable my timer, the MCU remains in sleep mode, but of course I can't do what I need to decide if the MCU should power up.

I've tried adding a SysCtlSleep() call to the end of my timer ISR - but this just results in the timer firing once then stopping... I think that an exception may be occurring but I'm not certain.

I've read up on SLEEPEXIT bit in the SYSCTRL register, however, short of writing the bit directly, which seems potentially unwise (without the API knowing it is set), I cannot find a way to control this. I'm not sure if this will help either, as the documentation seems to mention it applying only to exceptions rather than conventional interrupts.

Code for my Timer ISR and sleep routines below.

void Timer0BIntHandler(void)
{
	// clear IF flag
	TimerIntClear(TIMER0_BASE, TIMER_TIMB_TIMEOUT);
	// blink LED
	gpio_led_ctrl(0, 1);
	delay(200);
	gpio_led_ctrl(0, 0);
	delay(200);
	return;
}

void mcu_zzz()
{
	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
	TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PERIODIC);
	// Approx 30Hz heartbeat
	TimerPrescaleSet(TIMER0_BASE, TIMER_B, 170);
	TimerLoadSet(TIMER0_BASE, TIMER_B, SysCtlClockGet() / 1000);
	IntMasterEnable();
	TimerIntEnable(TIMER0_BASE, TIMER_TIMB_TIMEOUT);
	IntEnable(INT_TIMER0B);
	// Processor wakes up if this is enabled, remains in sleep if disabled but ISR will of course not fire
	TimerEnable(TIMER0_BASE, TIMER_B);
	SysCtlPeripheralClockGating(1);
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOA);
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_TIMER0);
	SysCtlSleep();
}

Any help appreciated.

  • Hello Tom,

    First of all Sleep Transition can occur only in thread mode and not when the code is in Interrupt mode.

    To handle the Sleep there are two methods

    1. Set the SLEEPEXIT mode and then ensure that all processing is done in the Interrupt routine. If any non-interrupt processing needs to be done then clear the SLEEPEXIT mode

    2. Run the SysCtlSleep in a while loop with SLEEPEXIT always cleared. This will ensure thread mode processing and subsequently an entry into Sleep Mode.

    Regards

    Amit

  • Amit, if I'm understanding you correctly, I'd have an infinite loop in my enter sleep routine (mcu_zzz), which would constantly be pushing the MCU back into sleep (after ISR wakes it up) until I'm ready to wake up again?  I could set a flag in my timer ISR indicating if I want to leave sleep mode or not. That makes some sense. I'll try that and report back.

  • Hello Tom,

    Yes. That is correct. In the timer ISR assess if the device needs to be in wake state or not. Something on the following lines would be useful (with the flag more_processing being set in the ISR if the system needs to be kept in wake state.

    while(1) {

    SysCtlSleep();

     if(more_processing) {

       do the processing or jump to another function.

       more_processing = 0;

      }

    }

    Regards

    Amit

  • That seems to have worked. Thanks!

    My Iq=34mA though. Need to figure out why this is. I guess I'm probably leaving some clocks on.

  • Hello Tom,

    Glad to have been of help.

    Iq=34mA in Sleep seems too high. Did you check the data sheet for Sleep currents?

    Make sure that you are not driving any LED's/external devices through the same power supply.

    Regards

    Amit

  • I got down to 25mA, but only by turning off all peripherals except GPIOE for power button and TIMER0. I am also clocking at 1MHz using the internal oscillator when in low power mode.

    My board has a Vbat -> 5V boost which is always active. The MCU then runs off an LDO which hangs off the 5V rail. The Iq of the boost with the MCU off is about 0.4mA. Vbat is a li-ion, 2.7~4.2V, 3.7V nominal.

    So I would expect for a Idd of about 3.5mA which should appear as a Vbat current around 8mA.

    I checked my crystal, and it's still oscillating? But I set the clock to 1MHz (1:16) from the int osc. I figure I still have to turn it off separately, going to check the docs and see if I'm missing something.

    Ideally, I'd target an Idd around 1mA, but it seems standard sleep mode is not capable of doing this and deep sleep mode does not support timer wakeup. I do have another option, to use the hiberate mode and wake up on the HIB# pin, which I did implement support for on this board. I'll investigate doing that later.

    You can tell it's my first time... too used to STM32s but am actually liking these Tiva MCU quite a lot, definitely easier to set up than STM32s.

  • Hello Tom,

    25mA with all peripherals OFF is way too high. As per the current consumption tables in the data sheet it should be no more than 10mA for Clock still running from MOSC+PLL. One important to know is that the debugger has to be disconnected for the device to go into Sleep mode.

    In CCS a simple disconnect would not help. A power cycle would do that.

    Regards

    Amit