2014-09-28 05:28 PM
Hello everyone:
Here is my problem.I am using the STM32L152. When I execute the WFI instruction, the processor goes to sleep just fine. However, when it wakes up from an external interrupt line, the processor immediately hardfaults. I have breakpoints set just before and after the WFI instruction. When the processor wakes, I should hit the second breakpoint, but instead it just hard faults. Here is some more information. All the registers (to my knowledge) are set correctly. I have looked at all the information I can find on the forum and have tried pretty much every suggestion. The flash is enabled (FLITF), the LPSDSR bit is cleared in the power register, etc.. All clocks are in their correct state. This is a textbook case of sleep mode: no disabling of flash, no low power sleep, just plain sleep mode. The manual says all that is needed is a WFI instruction. Now.. if I set the DEEPSLEEP bit in the cortex m3 SCR, the processor does 'not' hardfault and instead resumes execution where it is supposed to. All other settings being the same. Lastly, I have looked at the hard fault stacking of registers. It seems to be stacking things alright with an odd exception of the xPSR register. When I enter the hard fault, the stacked value for the xPSR register has the Thumb bit cleared. Inspecting the stack and state of the CPU (xPSR, NVIC, registers) at the instruction just before the WFI instruction reveals a proper CPU state as well as the Thumb bit set. I am also running an RTOS. I have tried to run the WFI code inside a task as well as outside a task. The stack being used (be it the process stack or the main stack) does not matter. Either stack hardfaults.Any help is greatly appreciated. I am hoping I am doing something stupid with just a bit being misplaced somewhere.2014-09-29 12:26 PM
Nobody has had this issue?
2014-09-29 12:43 PM
Nobody has had this issue?
Evidently not... You understand how forums work right?What does it do if you don't have it on the debugger? Try instrumenting it rather than using breakpoints.If it's hardware related I'd suspect the flash or prefetch mechanism, but no errata seemed to immediately suggest that was a known issue.2014-09-29 12:59 PM
2014-09-29 01:16 PM
It's odd that I get a response a mere few minutes after I push the thread to the top after not getting a peep for a day isn't it? :)
Not really, I read it when it first posted, I don't have any specific experience of the L152 behaving like this, so didn't respond then, and probably not any more helpful now.PRFTEN, FLASH_ACR
2014-09-29 03:50 PM
2014-09-29 11:38 PM
Could it be that you have a undefined interrupt handler that generates this hard fault ?
By the way, I will strongly advise you to trim down your case until to get the smallest code that reproduce this problem and post on the forum.2014-09-29 11:47 PM
Additionally, it could be useful to post here the state of NVIC at the moment you take the hard fault, just to check any pending interrupt/event.
Regarding the DEEPSLEEP configuration, the RM of L152 says that several conditions (on pending NIVC, RTC etc ....) must be met, otherwise the CPU won't enter STOP mode and continues to execute. It is possible that this explains why you are not hardfaulting when DEEPSLEEP is set.2014-09-30 04:53 AM
2014-09-30 05:25 AM
void main(void)
{
// Initialize clock
HAL_Clock_Init();
HAL_Clock_DeviceWake();
// Initialize device
HAL_Device_Init();
HAL_Device_SetVTOR(0x08000000);
// Initialize HAL layers
HAL_EXTI_Init();
// Configure EXTI interrupt
HAL_GPIO_Config(BUTTON1_GPIOOPTIONS);
HAL_EXTI_Config(BUTTON1_EXTIOPTIONS, BUTTON1_GPIOOPTIONS, Pin_Trigger);
HAL_EXTI_Enable(BUTTON1_PIN);
while(1)
{
HAL_Clock_DeviceSleep();
}
}
static void Pin_Trigger(uint8_t pin, uint8_t pinLevel)
{
__no_operation();
}
void HAL_Clock_Init(void)
{
// Switch to multispeed oscillator
RCC->CR |= RCC_CR_MSION_BIT;
while(~RCC->CR & RCC_CR_MSIRDY_BIT);
RCC->CFGR &= ~(RCC_CFGR_SW_BITS);
while((RCC->CFGR & RCC_CFGR_SWS_BITS) != RCC_CFGR_SW_MSI);
// Enable flash prefetch
FLASH->ACR |= (FLASH_ACR_ACC64_BIT);
while(~FLASH->ACR & FLASH_ACR_ACC64_BIT);
FLASH->ACR |= (FLASH_ACR_PRFTEN_BIT);
// Enable wait state since we are above 16MHz
FLASH->ACR |= (FLASH_ACR_LATENCY_BIT);
// Disable and configure the PLL
RCC->CR &= ~RCC_CR_PLLON_BIT;
while(RCC->CR & RCC_CR_PLLRDY_BIT);
RCC->CFGR = (RCC_CFGR_PLLSRC_BIT | (PLL_MUL <<
RCC_CFGR_PLLMUL_BIT_SHIFT
) | (PLL_DIV << RCC_CFGR_PLLDIV_BIT_SHIFT));
// Switch to PLL
SwitchToPLL();
// Clear peripheral clock count
periphClockCount
=
0
;
}
static void SwitchToPLL(void)
{
// Enable high speed external oscillator
RCC->CR |= RCC_CR_HSEON_BIT;
while(~RCC->CR & RCC_CR_HSEON_BIT);
// Enable and switch to PLL with high speed external oscillator input
RCC->CR |= RCC_CR_PLLON_BIT;
while(~RCC->CR & RCC_CR_PLLRDY_BIT);
RCC->CFGR |= (RCC_CFGR_SW_PLL);
while((RCC->CFGR & RCC_CFGR_SWS_BITS) != (RCC_CFGR_SWS_PLL <<
RCC_CFGR_SWS_BIT_SHIFT
));
// Turn off multispeed oscillator
RCC->CR &= ~RCC_CR_MSION_BIT;
while(RCC->CR & RCC_CR_MSIRDY_BIT);
}
void HAL_Clock_DeviceWake(void)
{
// Turn on GPIO clocks
HAL_GPIO_Enable();
}
void HAL_Clock_DeviceSleep(void)
{
// Disable GPIO clocks
HAL_GPIO_Disable();
// Determine what kind of sleep mode we can enter
if (periphClockCount == 0)
{
// Enter deep sleep
DeepSleep();
}
else
{
// Enter sleep
Sleep();
}
}
static void DeepSleep(void)
{
// Set deep sleep bit
//SCB->SCR |= SCB_SCR_SLEEPDEEP_BIT;
// Go to deep sleep
__DSB();
__ISB();
__WFI();
// Switch back to HSE / PLL
//SwitchToPLL();
// Clear deep sleep flag
//SCB->SCR &= ~SCB_SCR_SLEEPDEEP_BIT;
}
__weak void HardFaultHandler(void)
{
// Reset device
HAL_Device_Reset();
}
#pragma section = ''CSTACK''
#pragma location = ''.IntVector''
__root void* const intVector[] =
{
__section_end(''CSTACK''),
(void*)ResetHandler,
(void*)NULL, // (void*)NMIHandler,
(void*)HardFaultHandler,
(void*)NULL, // (void*)MemManageHandler,
(void*)NULL, // (void*)BusFaultHandler,
(void*)NULL, // (void*)UsageFaultHandler,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)SVCHandler,
(void*)NULL, // (void*)DebugMonHandler,
(void*)NULL, // (void*)0,
(void*)PendSVHandler,
(void*)SysTickHandler,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)RTCWakeupHandler,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)EXTI0Handler,
(void*)EXTI1Handler,
(void*)EXTI2Handler,
(void*)EXTI3Handler,
(void*)EXTI4Handler,
(void*)DMA1Channel1Handler,
(void*)DMA1Channel2Handler,
(void*)DMA1Channel3Handler,
(void*)DMA1Channel4Handler,
(void*)DMA1Channel5Handler,
(void*)DMA1Channel6Handler,
(void*)DMA1Channel7Handler,
(void*)NULL, // (void*)0,
(void*)USBHPHandler,
(void*)USBLPHandler,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)EXTI9_5Handler,
(void*)NULL, // (void*)0,
(void*)Timer9Handler, // (void*)0,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)Timer2Handler, // (void*)Timer2Handler,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)EXTI15_10Handler,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)Timer6Handler,
(void*)NULL,
(void*)NULL, // (void*)0,
(void*)NULL,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0,
(void*)DMA2Channel1Handler,
(void*)DMA2Channel2Handler,
(void*)DMA2Channel3Handler,
(void*)DMA2Channel4Handler,
(void*)DMA2Channel5Handler,
(void*)NULL, // (void*)0,
(void*)NULL, // (void*)0
};
Here is the simplest piece of code with the most important sections in it. I just pasted everything as one line stream of code. Keep in mind many of those blocks are in different files and or headers.
I first initialize the device by setting up the clock and calling the wake function. GPIO_Enable / disable functions simply turn on or off all GPIO clocks in the RCC clock enable registers. I wont go over the GPIO / EXTi configuration in detail (however I will if someone deems it absolute necessary); however the code essentially configures one of my GPIO pins as input with pull up and as an EXTI interrupt. If you comment out the code in the while loop, you can sit there for an hour, press the button, and the Pin_Trigger function will get called via EXTI interrupt. There is an EXTI layer that is not shown that essentially is the interrupt handler for all the EXTI interrupts. It essentially processes the EXTI interrupt line, clear the pending bits in the EXTI PR and then calls the callback (Pin_Trigger) with some parameters if a callback was defined for that line. The EXTI interrupt works fine.
The piece of code that is important is the sleep function in the while loop. When this code executes, it puts the chip to sleep via the DeepSleep function. Due to some code that I don't want to rewrite for this demonstration, all the DeepSleep function does is execute a WFI after DSB / ISB. The device goes to sleep as I can put a breakpoint in the while loop and see that the while loop is not executing the deep sleep function again.
If you press ''stop'' on the debugger, the chip starts executing code right after the WFI in the deep sleep function. If you press the button configured as an EXTI, the device hard faults. If you uncomment the lines in the DeepSleep function where I set / clear the DEEPSLEEP bit, the device executes code properly and my EXTI handler is executed, then the device goes back to sleep.
The hardfault handler is shown above. All it does is reset the device when a hard fault happens. I put a breakpoint on the reset function to determine if the hard fault handler gets executed.