Hello,
I am using IAR 6.60.1 and a custom control with a TM4C1231D5PZ revB1 (aka rev6).
In rare cases, a precise bus fault occurs when accessing peripheral registers after coming out of deep sleep. It occurs on the first peripheral that was not enabled during deep sleep, even with a fairly long delay beforehand (10ms). I have only seen this happen with Medium optimization, so it seems to be a timing issue.
Please help me understand what's happening.
This problem can be recreated using the code below (and sticking it in a TivaWare example project). Make sure to add wakeHandler to the interrupt vector and set optimization to medium. The fault should occur within several minutes.
#include <stdbool.h>
#include <stdint.h>
#include <driverlib/gpio.h>
#include <driverlib/interrupt.h>
#include <driverlib/sysctl.h>
#include <driverlib/timer.h>
#include <inc/hw_ints.h>
#include <inc/hw_memmap.h>
#include <inc/hw_nvic.h>
#include <inc/hw_sysctl.h>
#include <inc/hw_types.h>
void wakeHandler(void)
{
TimerIntClear(WTIMER5_BASE, TIMER_TIMA_TIMEOUT); /*Clear the timer interrupt */
}
void safeWFI(void)
{
__asm( "wfi\n"
"mov r0,#0\n"
"bx lr\n" );
}
void main(void)
{
uint32_t milliseconds = 10; /*Set sleep duration */
HWREG(SYSCTL_PBORCTL) = SYSCTL_BOR_RESET; /*Reset MCU during Vcc brownout events */
SysCtlClockSet( SYSCTL_OSC_MAIN | /*Configure system clock to 50MHz */
SYSCTL_USE_PLL | /* using 200 MHz PLL */
SYSCTL_SYSDIV_4 | /* divided by four */
SYSCTL_XTAL_16MHZ ); /* clocked from 16MHz external crystal */
IntEnable(FAULT_USAGE); /*Enable fault interrupts for debugging */
IntEnable(FAULT_BUS); /* (If these are not enabled, all of */
IntEnable(FAULT_MPU); /* these interrupts will will escalate */
IntEnable(FAULT_SYSTICK); /* to a hard fault and call the hard */
IntEnable(FAULT_PENDSV); /* fault interrupt handler instead of */
IntEnable(FAULT_SVCALL); /* the one assigned to it in the */
IntEnable(FAULT_NMI); /* interrupt vector) */
IntEnable(FAULT_DEBUG);
//
//Use PIOSC as a workaround for deep sleep errata
//
SysCtlDeepSleepClockSet(SYSCTL_DSLP_OSC_INT); /*Configure Deep Sleep Mode to use the */
/* Precision Internal Oscillator */
SysCtlPeripheralClockGating(true); /*Enable peripheral clock gating */
/* (halts peripheral clocking in sleep */
/* modes) */
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); /*Enable GPIO peripheral */
GPIOPinTypeGPIOInput(GPIO_PORTA_BASE, GPIO_PIN_0); /*Configure PA0 as an input */
for(;;)
{
//
//Call a peripheral-related command to randomly cause faults (there is nothing special about this
// particular function call)
GPIODirModeSet(GPIO_PORTA_BASE, GPIO_PIN_0, GPIO_DIR_MODE_IN); /*Set pin direction */
//
//Install wakeup timer
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER5); /*Enable timer peripheral */
SysCtlPeripheralDeepSleepEnable(SYSCTL_PERIPH_WTIMER5); /*Enable timer in sleep */
TimerConfigure( WTIMER5_BASE, TIMER_CFG_PERIODIC); /*Configure timer to auto-reload */
TimerLoadSet(WTIMER5_BASE, TIMER_A, 16000000 / 1000 * milliseconds); /*Set the load time to the specified */
/* number of milliseconds */
/* (clocked from PIOSC in deep sleep so*/
/* base timing on a 16MHz clock rate) */
IntEnable(INT_WTIMER5A); /*Enable the peripheral interrupt */
TimerIntEnable(WTIMER5_BASE, TIMER_TIMA_TIMEOUT); /*Enable the timer timeout interrupt */
TimerEnable(WTIMER5_BASE, TIMER_A); /*Enable the timer */
//
//Put to deep sleep (using erratum workaround)
//
HWREG(NVIC_SYS_CTRL) |= NVIC_SYS_CTRL_SLEEPDEEP; /*Enable deep sleep */
safeWFI(); /*Put MCU in a wait-for-interrupt state */
HWREG(NVIC_SYS_CTRL) &= ~(NVIC_SYS_CTRL_SLEEPDEEP); /*Disable deep sleep */
//
//(Same problem occurs with TivaWare call rather than workaround used above)
//
// SysCtlDeepSleep();
//
//Uninstall wakeup timer
//
TimerDisable(WTIMER5_BASE, TIMER_A); /*Disable the timer */
IntDisable(INT_WTIMER5A); /*Disable the peripheral interrupt */
TimerIntDisable(WTIMER5_BASE, TIMER_TIMA_TIMEOUT); /*Disable the timer timeout interrupt */
SysCtlPeripheralDisable(SYSCTL_PERIPH_WTIMER5); /*Disable the timer peripheral */
SysCtlDelay(166666); /*Delay for about 10 milliseconds */
}
}