PWM input/Timer.IC question

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
mwm
Posts: 36
Joined: Wed Aug 09, 2017 3:52 pm

PWM input/Timer.IC question

Post by mwm » Tue Oct 17, 2017 7:39 am

The STM32F4 timers are a lot more capable than the typical ATMEGA timers, so I was sort of surprised when all the examples I could find of doing PWM input or input capture - either in MicroPython or Arduino - fell back on the typical ATMEGA thing of taking interrupts on value change, and then figuring out the pulse width based on the values and a timer. Especially when the reference manual provides pretty explicit instructions on how to get the hardware to do it for you.

I translated that to Python, and got this:

Code: Select all

from pyb import Timer
from stm import mem16, TIM2, TIM_SMCR, TIM_CCER

# Configure timer2 as a microsecond counter.
tim = Timer(2, prescaler=84, period=0x3fffffff)

# Configure channel1 on PA0 for timer IC.
ch = tim.channel(1, Timer.IC, pin=pyb.Pin('PA0'), polarity=Timer.FALLING)

# Reset the timer counter on rising edge.
mem16[TIM2 + TIM_SMCR] = (5 << 4) + 4

# Capture counter on falling edge.
mem16[TIM2 + TIM_CCER] = 11
Seems to work fine - calling ch.capture() returns the width of the last pulse in microseconds, which is exactly what I want. All the work is done by the timer hardware - I don't need any code in my main or an interrupt handler, I just need to configure the timer and then read the values.

That I couldn't find examples of this worries me - is there something I overlooked that makes this expensive/painful/bad compared to using the ATMEGA interrupt handler style?

I'd also like to know if there are values somewhere for the TIM_SMCR & TIM_CCER field positions I'm using, so I can replace the constants with names?

Thanks,
Mike

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: PWM input/Timer.IC question

Post by dhylands » Tue Oct 17, 2017 7:25 pm

I've written examples. They were posted on the user wiki here:
http://wiki.micropython.org/platforms/b ... r-Examples
accompanied by some logic analyzer captures.

The input capture does use an interrupt, but only to figure out if it was a rising or falling edge that's being captured. The actual width of the pulse comes from the timer hardware.

The stm module only provides constants for the registers themselves. There isn't anything for fields within the registers.
So I tend to use binary numbers, like this example:
https://github.com/dhylands/upy-example ... py#L61-L64

You can create your own constants as well. I find it depends on whether I'm going to use the constant more than once.

mwm
Posts: 36
Joined: Wed Aug 09, 2017 3:52 pm

Re: PWM input/Timer.IC question

Post by mwm » Tue Oct 17, 2017 11:14 pm

I saw that. From what I can tell, it's not using the reference manual recipe, which uses the timer hardware to calculate the pulse width. Is there a reason not to follow the recipe in the reference manual?

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: PWM input/Timer.IC question

Post by dhylands » Wed Oct 18, 2017 12:14 am

Can you point me to the "Reference Manual Recipie" that you're referring to? Are you referring to the STM32 Reference Manual? If so, then the document number and section reference is fine.

My example sets the timer up to capture the rising or falling edge. The capture() method is used to retrieve the hardware counter of the edge. So I guess I'm not sure how this is "not using the timer hardware". I use a continuously running counter that wraps around, and this means I get as accurate a time difference as possible between the 2 edges.

mwm
Posts: 36
Joined: Wed Aug 09, 2017 3:52 pm

Re: PWM input/Timer.IC question

Post by mwm » Wed Oct 18, 2017 7:50 am

RM0090, 18.3.6. They actually get both the width and period using the same technic with a second channel on the timer.

Using the capture register in an IRQ that runs on both edges is essentially the same method as most people user on old 8-bit ATMEGAs, made more accurate by using the capture register.

The method from the PWM input section - as I did it in the OP - uses the automatic counter reset facility to reset the counter on the rising edge. This means the value captured on the falling edge is the pulse width in microseconds. If all you want is the width of the most recent pulse, you're done. Just read it from the capture register when you want it, no IRQ needed. Well, there's a minor issue that needs looking into, but I wanted to find out if there was something bad about this I was overlooking before doing that.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: PWM input/Timer.IC question

Post by dhylands » Thu Oct 19, 2017 4:08 pm

Thanks for the reference. I'll take a look into it, and create a new example.

I wrote the original C code for the stm32 and teensy timer classes, and was just learning about the STM32 family at the time, so its entirely possible I missed something useful like what your example sounds like.

It may be a few weeks before I get my example updated. I've just purchased a new house (took possession yesterday) and I'm about to head to London England for a week. I'll be at MozFest (for work).

Post Reply