cancel
Showing results for 
Search instead for 
Did you mean: 

Timer pin output starts HI, after 1st pulsing, is LOW as supposed - why?

SKled.1
Senior II

Hello,

I configured TIM2CH4 on my Nucleo STM32F303RE board to PWM with the LL library, and added some extra code to actually enable the outputs, set compare to with 50:50 duty, enabled the UPDATE IRQ and implemented the ISR to count down from a value initialized to a wanted number of pulses, and if it is 0, I call LL_TIM_DisableIT_UPDATE and LL_TIM_DisableCounter, which in turn I enable in my "start pulses" routine.

Also, I configured the "CH Polarity" in Pinout & Configuration tab to LOW.

So far so good, the scope output, starting with the second run of the routine, looks exactly like I want: The idle signal is low, when I start the pulsing, I see e.g. 10 pulses, and the pin ends on an idle low level.

The problem is that the whole thing starts with the output pin being HI after "booting".

Only after the first pulsing it remains low.

I tried, in main.c in the generated TIM2 init routine, user code section, to add enabling the output already (as opposed to my later init routines), with TIM2->CCER |= TIM_CCER_CC4E.

But that didn't help.

How can I make the system start with a low idling pin before doing the first pulses?

(for now I'll just put in a hack of doing one pulse before configuring the connected device that acts on those pulses, but it's, well, a hack 😉 )

Edit: Added requested images

Register contents - if you'd like any of those dissected by bits I can screencap that, too.

(hope this becomes bigger in the real post, in the editor this is shrunk a lot, and I see no way to change that)

0693W000001qPM5QAM.png

This is that it looks like after booting - note the yellow line starting at a high level.

Then 10 pulses are made, well, 9.5 in this case, as the 1st one is missing the rising edge.

(ignore the cyan signal, it's just a pin toggling back and forth once per run)

0693W000001qPLlQAM.png

This is what it's supposed to look like: The line starts LOW, and therefore produces 10 instead of 9 rising edges.

0693W000001qPLWQA2.png

10 REPLIES 10
berendi
Principal

Please post the contents of the timer registers, and a timing diagram/scope screenshot of the required and the actual waveform.

Ok, see updated the post.

How comes your CCR4 is 0, yet the pulses appear to be 1:1 duty? At which point did you take this reading?

Any change if you set CCR4 to non-0?

JW

Ah, so what you see is configured in an init, and the sole purpose of the software module I wrote around that is then to have a function executed like

DoSteps(count, speed, dir) { ... }

Which is to enable the counting and ISR stuff.

In that function, duty is set to 1/2 of the reload value, yielding the pulses you see. Since the reload value is only known by the speed parameter, it is not done in the Init routine.

Nuts! I did try to set CCR4 to some value in the user code section *after* the timer init block of the MX generated code, and it had no effect.

But when initializing CCR4 in the user code section *before* the timer init code, it fixes the problem!

Thanks! That was easy. Albeit, on first sight, rather unintuitive.

If anyone knows where in the manual it explains why this is and can point me to it, I'd gladly want to read it :D

berendi
Principal

Reference manual, TIMx_CCMR1/2 register description

0110: PWM mode 1 - In upcounting, channel 1 is active as long as TIMx_CNT<TIMx_CCR1 else inactive.

If CCRx == 0, CNT < CCRx is never true because the values are unsigned, so the output is always at the inactive level.

Read 21.3.9 PWM mode for a more detailed description.

This kind of stuff is hard to get right with HAL/LL, because you always have to reverse engineer the library functions to be able to look up in the documentation what they really do. Save yourself the trouble and work directly with the registers.

You may want to read the whole TIM chapter, and experiment, maybe avoiding Cube/HAL.

0693W000001qQ5jQAE.png

So, while CNT==0 and CCRx==0, CNT<CCRx is false i.e. output is inactive; and as you've set CCER.CC4P=1, that's 1 on the pin.

> Nuts! I did try to set CCR4 to some value in the user code section *after* the timer init block of the MX generated code, and it had no effect.

As you've also set CCMR2.OC4PE=1 i.e. enabled preload, the CCRx value written after it did not get active as you've did not perform an Update.

JW

SKled.1
Senior II

Ah! Thanks!

I hear ya about avoiding the libraries. BUT. The "LL" is nicely tight around the registers, all (almost) one Ctrl+LeftLick away from the registers in Eclipse/CubeIDE. Almost to the point where you might wonder what the point is - but there is one - things are a bit more readably named, and the relevant stuff is all collected and presented - well again, almost. I have gotten quite far without problems with it, until this.

I did read sections of the manual for other peripherals that had step-by-step instruction lists for certain use cases, beyond the basic initialization of the hardware.

The thing is that the graphical depiction of assigned pins, and clock tree with bounds checks and all, is very useful.

And this LL stuff - as long as every single thing used is set to generate LL , not HAL -looks a lot less bad than the Frankenstein HAL I tried years back 😉

If that had no kinks anymore - and it has improved over the years, so maybe there is hope? - it would be quite neat.

It does seem to save a lot of time and some sources of errors that way. Until there's a scanario like this when it doesn't.

That's why I haven't ditched that yet. It does seem to make sense... but implementation is maybe not 100% on target...

berendi
Principal

> all (almost) one Ctrl+LeftLick away from the registers in Eclipse/CubeIDE

That's one click too many for me.

> things are a bit more readably named

The readable names can be misleading. What does LL_TIM_EnableAllOutputs() or LL_TIM_EnableMasterSlaveMode() convey to you?

If I read TIM_BDTR_MOE or TIM_SMCR_MSM instead, I am forced to look them up in the reference manual, where their semantics is described in detail.

> The thing is that the graphical depiction of assigned pins, and clock tree with bounds checks and all, is very useful.

Sure, I can't even imagine how could I handle the pinout of a 176 pin package without it.

> it has improved over the years, so maybe there is hope?

I try it about once every year. It hasn't.

SKled.1
Senior II

I guess what would be real neat would be a third CubeMX init code generator option to HAL and LL: "NRL" - the Naked Register Level, that you can directly check against the reference manual, but don't all need to write yourself =)

Hrm. Actually, I'd kinda like that. If done right. There could still be comments in the generated output that, on a slightly higher, block of code level, describes what the code is supposed to do & why.