cancel
Showing results for 
Search instead for 
Did you mean: 

Wrong PC (progam counter) when exiting ISR

Brigei
Associate II

Hi,

i'm using a STM32L031. In my code i first initialize the MCU (FLASH, CLOCK, INTERRUPTs, GPIOs), start the LPTIM (running on LSI), then slow down the MSI clock, start the timer22 for PWM and go into low-power sleep mode.  When i let the program run i experience an hard-fault after exiting the ISR (count = ccr) from the LPTIM because at the moment when r7 and PC gets popped from the stack PC gets a wrong value and suddenly points to RAM instead of FLASH. The strange thing for me is also, that when i don't use the LPTIM for waking up the MCU, but use a GPIO (EXTI) ist works fine. It also works fine when i don't go into low-power sleep mode but into stop-mode and then let the LPTIM wake up the MCU. In this case of course the PWM doesn't work while in stop-mode.

So can someone help me out an tell me why the pc gets a wrong value?

Here my example code:

#######################################################

int main(void){

// Initialize

FLASH->ACR |= FLASH_ACR_PRFTEN; // Enable Pre-Fetch

RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; // Clock für Systemconfig aktivieren

RCC->APB1ENR |= RCC_APB1ENR_PWREN;

 

// Clock setup

RCC->ICSCR &= ~(0b111 << 13);

RCC->ICSCR |= 0b101 << 13;

while(!(RCC->CR & RCC_CR_MSIRDY));

 

// GPIO setup

RCC->IOPENR |= RCC_IOPENR_GPIOAEN; // Aktivieren des Clock-Gates für GPIOA

GPIOA->MODER &= ~(0b11); // Pin PA0 als Input - BUTTON

GPIOA->PUPDR |= 0b10; // Pin PA0 Pull-down

EXTI->IMR |= 0b1; // Interrupt Maske für PA0

EXTI->RTSR |= EXTI_RTSR_RT0; // Konfigure Interrupt für Rising Edge für PA0

NVIC_SetPriority(EXTI0_1_IRQn, 1); // Priorität von PA0 Interrupt auf 0

NVIC_EnableIRQ(EXTI0_1_IRQn); // Interrupt von PA0 aktivieren

PWR->CSR |= PWR_CSR_EWUP1; // Enable PA0 als Wakeup Pin

GPIOA->MODER &= ~(0b11 << 30); // Pin PA15 als Input - DPS INTERRUPT

EXTI->IMR |= 0b1 << 15; // Interrupt Maske für PA15

EXTI->FTSR |= EXTI_RTSR_RT15; // Konfigure Interrupt für Falling Edge für PA15

NVIC_SetPriority(EXTI4_15_IRQn, 2); // Priorität von PA15 Interrupt auf 0

NVIC_EnableIRQ(EXTI4_15_IRQn); // Interrupt von PA15 aktivieren

GPIOA->MODER &= ~(0b11 << 14); // Pin PA7 auf Alternate Function Mode

GPIOA->MODER |= 0b10 << 14;

GPIOA->AFR[0] |= 0b0101 << 28; // Pin PA7 mit TIM22 CH2 verbinden

GPIOA->MODER &= ~(0b1111 << 6); // PA4 (EN1) - PA3 (EN2) - Konfiguration Verstärker

GPIOA->MODER |= (0b0101 << 6); // PA4 + PA3 auf Output Mode

GPIOA->MODER &= ~(1 << (9 * 2)); // PA9 auf Alternate function mode

GPIOA->MODER &= ~(1 << (10 * 2)); // PA10 auf Alternate function mode

GPIOA->OTYPER |= 1 << 9; // PA9 auf open-drain

GPIOA->OTYPER |= 1 << 10; // PA10 auf open-drain

GPIOA->OSPEEDR |= 0b11 << (9 * 2); // PA9 auf High-Speed

GPIOA->OSPEEDR |= 0b11 << (10 * 2); // PA10 auf High-Speed

GPIOA->PUPDR |= 1 << (9 * 2); // PA9 auf Pull-Up

GPIOA->PUPDR |= 1 << (10 * 2); // PA10 auf Pull-Up

GPIOA->AFR[1] |= 1 << 4; // PA9 mit I2C1_SCL verbinden

GPIOA->AFR[1] |= 1 << 8; // PA10 mit I2C1_SDA verbinden

GPIOA->MODER &= ~(1 << ((6 * 2) + 1)); // Default 11 -> 01 -> PA6 auf Output Mode

GPIOA->ODR |= (1 << 6); // PA6 auf HIGH

__enable_irq();

 

// LPTIM setup

piepsen = 1;

RCC->CSR |= RCC_CSR_LSION; // LSI aktivieren

while(!(RCC->CSR & RCC_CSR_LSIRDY)); // Warten bis LSI Ready

RCC->CCIPR |= RCC_CCIPR_LPTIM1SEL_0; // LSI als Clock Souce für LPTIM

RCC->APB1ENR |= RCC_APB1ENR_LPTIM1EN; // Aktivieren des Clock-Gates für LPTIM1

NVIC_EnableIRQ(LPTIM1_IRQn);

NVIC_SetPriority(EXTI0_1_IRQn, 3); // Priorität von PA0 Interrupt auf 0

LPTIM1->CFGR |= 0b101 << 9; // Prescaler auf 32 -> 37kHz -> 1156.25 Hz

LPTIM1->IER |= 0b11;

LPTIM1->CR |= LPTIM_CR_ENABLE; // LPTIM starten

LPTIM1->ARR = (1156.25 / 1000)*(200); // Auto Reload Register

LPTIM1->CMP = (1156.25 / 1000)*100; // Capture Compare

LPTIM1->CR |= LPTIM_CR_SNGSTRT; // Timer start in Single Shot mode

 

// Slow down clock

RCC->ICSCR &= ~(0b111 << 13);

RCC->ICSCR |= 0b001 << 13;

while(!(RCC->CR & RCC_CR_MSIRDY)); // Wait for MSI is ready

 

// Start TIMER 22

RCC->APB2ENR |= RCC_APB2ENR_TIM22EN;

TIM22->ARR = 131072/500; // Auto-reload value (period)

TIM22->CCR2 = 131072/500/2;

TIM22->CCMR1 |= 0b110 << 12; // PWM mode 1

TIM22->CCER |= TIM_CCER_CC2E; // Enable channel 2 output

TIM22->CR1 |= TIM_CR1_CEN; // Enable TIM22

 

// Enter LOW-POWER SLEEP MODE

while (FLASH->SR & FLASH_SR_BSY) {} // Auf Flash warten bis alles erledigt

FLASH->ACR |= FLASH_ACR_SLEEP_PD; // FLASH schlafen legen

PWR->CR |= PWR_CR_LPSDSR; // Volt Regulator in Low Power Mode --> einziger vorteil wäre sonst schnellerer wake-up

__WFI();

 

while(1);

}

The ISR looks like this:

void LPTIM1_IRQHandler(void) { // Überwachung Piepsdauer

if(LPTIM1->ISR & 0b1){ // Capture Compare Interrupt -> Piepsen AUS

status = 3;

LPTIM1->ICR |= 0b1;

TIM22_Stop(); // Abfrage damit nicht Gamification unterbrochen wird

}

else{ // Auto Reload Register Interrupt -> Pieps-Pause AUS

piepsen = 0;

LPTIM1->ICR |= 0b1 << 1;

LPTIM_Stop();

}

}

#####################################################################

Screenshots:

1. In screenshot "Beginning" you can see the system right after the ISR was triggered.

2. Screenshot "Before" was taken just before the hard-fault happens.

3. Screenshot "Hard-Fault" doesn't need an explanation 

Thanks in advance

Greetings from Salzburg, Austria

 

38 REPLIES 38
Sarra.S
ST Employee

Hello @Brigei 

any updates?

 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Unfortunately not. In fakt I‘m clueless where to look? Any suggestions?

Sarra.S
ST Employee

did you try disabling debug in lp mode as suggested? 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

yes. no difference

Hello @Brigei

What's the silicon rev of your STM32L031? 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Is this what you mean?

I believe so,  Cat 2, Rev 1 or X, should be able to see as a digit on the chip markings too. The markings could help confirm/establish the fab

You could use this chip info to check the errata documents.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Have you managed to pin down what piece of your code is trashing the stack / return address?

Something in the TIM22_Stop() or LPTIM_Stop() or other interrupt code running?

Other than the Flash wait states being sufficient, I'd suppose this wasn't the fault of the MCU or the STM32 peripherals, but something you're physically touching.

Look at all code called/touched by the IRQHandlers, callbacks, etc.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

I have used the *binary* (.elf) from the Project.rar you've posted above in an STM32L031F6P6 rev.X, using OpenOCD/gdb. It did *not* exhibit the issue you describe, i.e. upon reset and then the first stop at breakpoint in LPTIM ISR, registers were stacked properly, and subsequent run and exit from LPTIM ISR did not result in crash.

This IMO leaves, as potential sources of problems, only the option bytes (I have set them at factory default); and (much more likely) the particularities of actions of debugger used. @Sarra.S 's remark "probably due the desynchronization between core and its subsystem peripherals" may hint at the latter, too.

I am not knowledgeable enough to devise some comprehensive test to pinpoint the exact cause, nor am I invested in CubeIDE to do that (read, OpenOCD/gdb works for me, thank you very much; with CubeIDE issues you are left purely with ST's support).

JW