cancel
Showing results for 
Search instead for 
Did you mean: 

Reasons for TIM CCx ISR not firing on STM32L433

patrickschneider9
Associate III
Posted on May 25, 2018 at 15:57

Hi there,

I have a rather odd problem and am trying to find a solution or reason for it:

I am using 3 different timers on STM32L433 with 4 capture compare registers each to generate a total of 12 completely independant software PWM signals. Hardware layout is fixed, so no option to use hardware PWM.

I also tried only one of the timers with one capture compare register (with same behaviour), so for the sake of simplicity let's assume we are using TIM2 with CC1.

The initialization is:

CR1 = 0

CR2 = 0

SMCR = 0

DIER = DIER_CC1IE

EGR = EGR_UG

CCMR1 = 0

CCMR2 = 0

CCR1 = initial value

CCR2 = 0

CCR3 = 0

CCR4 = 0

CCER = 0

ARR = 0xFFFF

PSC = (Systemcoreclock / 1000000) - 1 //with ARR a base of 1µs  - this is validated and works

DCR = 0

DMAR = 0

After that I enable the timer and work in the interrupt.

The algorithm for the interrupt handler I am using to generate the PWM signal is as follows (pseudocode), registers are all TIM2 and CC1:

HandleIrq()

{

   if(isflgset(TIMTable[_TimNo]->SR, TIM_SR_UIF))

   {

      clrflg(TIMTable[_TimNo]->SR, TIM_SR_UIF);

   }

   if(isflgset(TIMTable[_TimNo]->SR, TIM_SR_CC1IF) &&

      isflgset(TIMTable[_TimNo]->DIER, TIM_DIER_CC1IE))

   {

      if(Toggle)

      {

          Toggle = 1 - Toggle;

          *(u16*)TIMCCRegTable[_TimIdx] = (u16)(TIM2->CNT + onTime);

          PINSET;

      }

      else

      {

          Toggle = 1 - Toggle;         

          *(u16*)TIMCCRegTable[_TimIdx] = (u16)(TIM2->CNT + offTime);

          PINRESET;

      }

      clrflg(TIMTable[_TimNo]->SR, TIM_SR_CC1IF);

   }

}

This has different implications:

I have a lot of Capture Compare interrupts between one timer overflow. 

The routine itself takes less time than onTime/offTime. (ISR takes 8µs, minimum onoffTime is 400µs)

Both are true (mostly)

My problem is, this all works MOST of the time perfectly with all timings, but once in a while ONE interrupt is not getting fired in the current timer overflow but in the next. Example:

CC1 ISR at Counter-Value: 0x5000

Next desired Value: 0x6000 (4096µs time)

CC1 ISR is triggered at 0x6000 but one COMPLETE timer overflow later (4096µs + 0xFFFFµs = 69631µs have passed)

This is perfectly accurate and measurable, so it's clear that it's exact one timer 'round'.

Question is why am I losing this interrupt, and just 'sometimes'. It just looks like sometimes someone would clear the interrupt before it gets fired OR the timer would just update the CCx register to its shadow register after the overflow event.

The effects are desastrous, I am using this to regulate output currents and when this is happening the output current clamps to Maximum or Zero for this period of time (65ms).

Could anybody think of anything causing my problem?

Thanks in advance for your help,

Pat

9 REPLIES 9
Jan Waclawek
Senior II
Posted on May 25, 2018 at 17:24

clrflg(TIMTable[_TimNo]->SR, TIM_SR_UIF);

My guess is that this is RMW (i.e. SR &= UIF). If so, that's the culprit, SR flags are to be cleared by direct write, read the description of SR in RM.

JW

patrickschneider9
Associate III
Posted on May 25, 2018 at 19:50

Hello Jan,

thank you for your answer! What exactly do you mean by RMW? I'm sorry I don't know that term. 

My clrflg makro is:

#define clrflg(x,y) ((x) &= ~(y))

Pat

Posted on May 25, 2018 at 20:05

RMW  Read Modify Write

For the SR register use SR= not SR&=,  the logic on the register does the clearing in a single cycle atomically, you don't need to read it, that creates a hazard as the TIM can out run the load/store you are attempting.

TIM->SR = ~TIM_SR_UIF;

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on May 25, 2018 at 20:43

Thanks for the clarification Clive.

I think I'm not understanding the SR register right. So basically with 

TIM->SR = ~TIM_SR_UIF I'm writing 1's to all other SR Flags, which can only be set by hardware. So this is not a problem?

So having more than one Capture Compare flag CC1IF, CC2IF at the same time is also no problem then? Can you clarify: if CC1 and CC2 for example happen to have the same Counter value and trigger 'simultaneous', will there be one ISR trigger with both flags rising or two consecutive ISRs?

Thanks to you two for pointing that out and I will definetly try that monday at the lab - but I can't possibly imagine that this has something todo with my problem: the minimum time I'm 'forwarding' the ISR is 400µs, the time between a read and write of the register should be way less, shouldn't it (running at 24MHz)?

Thanks again for alle the fast answers so far.

Posted on May 25, 2018 at 21:46

It's not memory, it is a register where the write is implicitly an AND operation

TIM->SR = ~TIM_SR_UIF;

Equivalent

SR := SR AND NOT(TIM_SR_UIF)

The problem with the method you're using is it effectively achieves SR=0 and has a window several cycles wide where and interrupt could assert and you clear it without ever seeing it being set.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on May 25, 2018 at 22:46

Okay, that sounds reasonable, I'll try it monday. Thanks for the help so far and have a nice weekend!

Is the behaviour you are describing true for every register write on a stm32, or just the ISR flags?

I shockingly didn't know that and the macro I posted is widely used here  O.o

Posted on May 25, 2018 at 22:56

It impacts a handful of registers, some have cases where you write ONE bits and others like this ZERO bits. The specific operation is described/noted in the Reference Manual.  Marked as rc_w0, read condition write zero, ie only zeros write thru, but remember TIM_SR_UIF AND ~TIM_SR_UIF is ZERO across the whole register.

Bits in the USART SR also change or clear depending on your interaction with the DR. This can cause problems if you use the debugger view over the registers, similarly FIFOs in USB or SDIO/SDMMC devices, etc.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on May 26, 2018 at 01:01

Registers which are changed from 'both sides', i.e. both by hardware and software, bitwise, must be treated in this way to achieve hardware atomicity. Most status registers are cleared by writing 1 (ie. rc_w1), as in that way you clear all triggered events at once by simply writing back the just read value; however, ST's own modules (including TIM) often bear the manuscript of relatively unexperienced authors.

If you are more inclined to understand hardware being drawn rather than written or described, 

https://community.st.com/0D70X000006SkeISAS

may help you.

JW

patrickschneider9
Associate III
Posted on May 28, 2018 at 08:20

Thank you Jan and Clive,

this seemed to do the trick. Output current is stable now!

Thank you so much for your help and fast answers!  Probably wouldn't have found it without you guys.

Cheers,

Pat