2018-05-25 06:57 AM
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
2018-05-25 08:24 AM
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
2018-05-25 10:50 AM
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
2018-05-25 01:05 PM
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;
2018-05-25 01:43 PM
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.
2018-05-25 02:46 PM
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.
2018-05-25 03:46 PM
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
2018-05-25 03:56 PM
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.
2018-05-25 06:01 PM
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
2018-05-27 11:20 PM
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