Greetings,
We have a project where a board with a TM4C123 is permanently powered. To avoid draining the battery, the strategy is to put it down to DeepSleep (it won't really be doing ANYTHING, it just has to be awaken by a pulse in a specific GPIO). It is not HIBERNATE, because the wake up pulse was not routed to a convenient hibernate GPIO, so Deep Sleep was the best we could come up with. When system wakes up from hibernation, it simply resets so that we have a fully fresh state.
It works quite well, almost always... However, occasionally the board will not wake up, even though the pulse signal is confirmedly there.
We did look at some posts regarding errata HIB#01 and tried to add some code from those posts, but I honestly did not fully understand the proposed solution, the adequate code nor am I even sure that the cause is the said errata issue.
/* * Puts the system in DeepSleep mode * This function will only exit when an interrupt caused by EXP_GPIO_PIN is triggered */ void TaskSystemDeepSleep(void) { /* Now enable the interrupt for the wake up pin */ GPIOIntRegister(EXP_GPIO_BASE, TaskDeepSleepISR); GPIOIntTypeSet(EXP_GPIO_BASE, EXP_GPIO_PIN, GPIO_RISING_EDGE); IntEnable(EXP_GPIO_INT); GPIOIntClear(EXP_GPIO_BASE, 0xFF); GPIOIntEnable(EXP_GPIO_BASE, EXP_GPIO_PIN); /* Disabled Peripherals */ SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_ADC0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_ADC1); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_CAN0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_CAN1); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_COMP0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_EMAC0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_EPHY0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_EPI0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOA); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOB); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOC); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOD); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOE); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOF); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOG); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOH); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOJ); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_HIBERNATE); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_CCM0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_EEPROM0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_FAN0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_FAN1); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOK); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOL); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOM); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPION); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOP); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOQ); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOR); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOS); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_GPIOT); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_I2C0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_I2C1); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_I2C2); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_I2C3); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_I2C4); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_I2C5); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_I2C6); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_I2C7); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_I2C8); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_I2C9); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_LCD0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_ONEWIRE0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_PWM0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_PWM1); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_QEI0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_QEI1); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_SSI0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_SSI1); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_SSI2); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_SSI3); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_TIMER0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_TIMER1); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_TIMER2); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_TIMER3); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_TIMER4); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_TIMER5); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_TIMER6); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_TIMER7); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_UART0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_UART1); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_UART2); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_UART3); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_UART4); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_UART5); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_UART6); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_UART7); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_UDMA); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_USB0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_WDOG0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_WDOG1); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_WTIMER0); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_WTIMER1); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_WTIMER2); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_WTIMER3); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_WTIMER4); SysCtlPeripheralDeepSleepDisable(SYSCTL_PERIPH_WTIMER5); /* Enabled Peripherals */ SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOA); // Should not be needed but just in case... SysCtlPeripheralDeepSleepEnable(SYSCTL_PERIPH_GPIOA); /* * There is a HW bug regarding deep sleep. See these posts: * https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/606846/tm4c123ge6pm-tm4c123gxl-deep-sleep-mode-issue * https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/275336/rtc-will-sometimes-miss-waking-from-hibernate/964156#964156 */ /* DeepSleep configurations */ SysCtlPeripheralClockGating(true); /* Function below is for TM4C123 devices */ SysCtlDeepSleepClockSet(SYSCTL_DSLP_DIV_1 | SYSCTL_DSLP_OSC_INT30 | SYSCTL_DSLP_PIOSC_PD); /* Function below is for TM4C129 devices */ // SysCtlDeepSleepClockConfigSet(1, (SYSCTL_LDO_SLEEP|SYSCTL_TEMP_LOW_POWER|SYSCTL_FLASH_LOW_POWER|SYSCTL_SRAM_LOW_POWER)); SysCtlDeepSleepPowerSet(SYSCTL_LDO_SLEEP|SYSCTL_TEMP_LOW_POWER|SYSCTL_FLASH_LOW_POWER|SYSCTL_SRAM_LOW_POWER); SysCtlLDODeepSleepSet(SYSCTL_LDO_0_90V); // Select LDO to Scale to 0.9V in Deep Sleep while (!canWakeUp) { HWREG(HIB_CTL) |= HIB_CTL_CLK32EN | HIB_CTL_OSCDRV; SysCtlDelay(SYSTEM_CLOCK_HZ/2); // Wait for 1500 ms HibernateRTCSet (0); HibernateRTCTrimSet (0x7FFF); SysCtlDeepSleep(); } /* Code will never come here unless the interrupt was caused by EXP_GPIO_PIN */ HWREG(NVIC_APINT) = (NVIC_APINT_VECTKEY | NVIC_APINT_SYSRESETREQ); }
Above is the function that configures and initiates the DeepSleep.
/* * Specific ISR for deep sleep mode, makes sure that only the EXP_GPIO pin wakes the board up */ void TaskDeepSleepISR(void) { uint32_t intFlags; intFlags = GPIOIntStatus(EXP_GPIO_BASE, false); // false means we are concerned about unmasked interrupts GPIOIntClear(EXP_GPIO_BASE, intFlags); if (intFlags & EXP_GPIO_PIN) { canWakeUp = true; } }
Then we have the associated ISR. The idea is to have the GPIO trigger an interrupt, wake up the system into the ISR, check that the cause was the expected pin and set canWakeUp, which will the lead code to reset.
Any ideas of how to debug and solve this?
Cheers
Bruno