TIM2 TIM5 Gated mode

The official pyboard running MicroPython.
This is the reference design and main target board for MicroPython.
You can buy one at the store.
Target audience: Users with a pyboard.
Post Reply
klik
Posts: 5
Joined: Thu Jan 08, 2015 8:37 am

TIM2 TIM5 Gated mode

Post by klik » Tue Jan 13, 2015 9:02 am

Hi everyone,

first of all I have to say I like the pyboard. It is tiny and you can develop software really fast for it. But at the moment I'm stuck. I try to get the TIM2 and TIM5 (32 bit) working in the gated mode.

I want to start counting as long as a pin is high (or low).

TIM2 CH2 Pin.X2

I found the Timer Control Register 1 etc. http://wiki.micropython.org/platforms/b ... -const-tim

Enabling a counter is not the deal. But it does not work in the gated mode.

I hope someone here can help me.
Big thx

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

Re: TIM2 TIM5 Gated mode

Post by dhylands » Wed Jan 14, 2015 8:01 am

The timers (in micropython) don't directly support the gated mode, but input capture mode gets us most of the way there.

So I put together an example which i put in my github repository:
https://github.com/dhylands/upy-example ... r/gated.py

Code: Select all

import pyb
import stm

# For this example, we assume that there is a wire connected from X1 to Y1
#
# Y1 corresponds to Timer 8 channel 1, which we'll use as output
# X1 corresponds to Timer 2 channel 1, which we'll use an the input gate
#
# We'll confgure Y1 as a GPIO and initially drive it high (which corresponds
# to not counting). Then we'll toggle that pin when the user presses a key.

y1 = pyb.Pin('Y1', pyb.Pin.OUT_PP)
y1.high()

# tim2's source_freq is 84 MHz, so we'll set the prescalar to divide by
# 8399, which will drop the counter freq to 10 kHz, and we'll set the 
# period to be 50,000 clock ticks, so that it rolls over once every 5 seconds
#
# Note that the prescalar for tim2 is 16-bit but the period is 32-bit.

tim2 = pyb.Timer(2, prescaler=8399, period=49999)

# We're following the example on page 603 of the RM0090 document (STM32F405
# datasheet) (I copied the pertinent section below for reference):
#
#   Slave mode: Gated mode
#
#   The counter can be enabled depending on the level of a selected input.
#   In the following example, the upcounter counts only when TI1 input is low:
#
#       - Configure the channel 1 to detect low levels on TI1. Configure the
#         input filter duration (in this example, we don't need any filter, so
#         we keep IC1F=0000). The capture prescaler is not used for triggering,
#         so you don't need to configure it. The CC1S bits select the input
#         capture source only, CC1S=01 in TIMx_CCMR1 register. Write CC1P=1
#         and CC1NP=0 in TIMx_CCER register to validate the polarity (and
#         detect low level only).
#
#       - Configure the timer in gated mode by writing SMS=101 in TIMx_SMCR
#         register. Select TI1 as the input source by writing TS=101 in
#         TIMx_SMCR register.
#
#       - Enable the counter by writing CEN=1 in the TIMx_CR1 register (in
#         gated mode, the counter doesn't start if CEN=0, whatever is the
#         trigger input level). 
#
#   The counter starts counting on the internal clock as long as TI1 is low
#   and stops as soon as TI1 becomes high. The TIF flag in the TIMx_SR register
#   is set both when the counter starts or stops.
#
# If we set the channel up for input capture, then it will set CC1S to 01
# Setting the polarity to FALLING will set CC1P=1 and CC1NP=0

ch1 = tim2.channel(1, pyb.Timer.IC, pin=pyb.Pin.board.X1, polarity=pyb.Timer.FALLING)

# We'll need to set the SMS=101 and TS=101 in the SMCR register ourselves,
# since none of the exposed APIs manipulate that register.
#
# SMS is bits 2:0 and TS is bits 6:4

smcr = stm.mem16[stm.TIM2 + stm.TIM_SMCR]
smcr &= 0b1111111110001000
smcr |= 0b0000000001010101
stm.mem16[stm.TIM2 + stm.TIM_SMCR] = smcr

usb_vcp = pyb.USB_VCP()

while True:
    if usb_vcp.any():
        ch = usb_vcp.read()
        if y1.value():
            print("Counter enabled")
            y1.low()
        else:
            y1.high()
            print("Counter disabled")
    pyb.delay(100)
    cnt = tim2.counter()
    print('cnt = %d' % cnt)
This example requires a jumper wire from X1 to Y1. Some sample output looks like this:

Code: Select all

>>> import gated
cnt = 0
cnt = 0
Counter enabled
cnt = 997
cnt = 1997
cnt = 2997
cnt = 3997
cnt = 4997
cnt = 5997
cnt = 6997
cnt = 7997
cnt = 8997
cnt = 9997
cnt = 10997
cnt = 11997
cnt = 12997
cnt = 13997
Counter disabled
cnt = 13999
cnt = 13999
...
cnt = 13999
cnt = 13999
Counter enabled
cnt = 14997
cnt = 15997
cnt = 16997
cnt = 17997
cnt = 18997
cnt = 19997
cnt = 20997
cnt = 21997
cnt = 22997
cnt = 23997
cnt = 24997
cnt = 25997
cnt = 26997
cnt = 27997
cnt = 28997
cnt = 29997
cnt = 30997
cnt = 31997
cnt = 32997
cnt = 33997
Counter disabled
cnt = 33999
cnt = 33999
...
\cnt = 33999
cnt = 33999
Counter enabled
cnt = 34996
cnt = 35996
cnt = 36996
cnt = 37996
cnt = 38996
cnt = 39996
cnt = 40996
cnt = 41996
cnt = 42996
cnt = 43996
cnt = 44996
cnt = 45996
cnt = 46996
cnt = 47996
cnt = 48996
cnt = 49996
cnt = 996
cnt = 1996
cnt = 2996
Counter disabled
cnt = 2999
cnt = 2999
...
cnt = 2999
cnt = 2999
Counter enabled
cnt = 3996
cnt = 4996
cnt = 5996
cnt = 6996
cnt = 7996
cnt = 8996
cnt = 9996
cnt = 10996
cnt = 11996
cnt = 12996
cnt = 13996
cnt = 14996
cnt = 15996
Counter disabled
cnt = 15999
cnt = 15999
cnt = 15999

Damien
Site Admin
Posts: 647
Joined: Mon Dec 09, 2013 5:02 pm

Re: TIM2 TIM5 Gated mode

Post by Damien » Wed Jan 14, 2015 10:12 pm

Nice work @dhylands! Do you think it's worth adding a proper gated mode to the timers to make this easier to do?

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

Re: TIM2 TIM5 Gated mode

Post by dhylands » Thu Jan 15, 2015 7:26 am

Damien wrote:Nice work @dhylands! Do you think it's worth adding a proper gated mode to the timers to make this easier to do?
Probably. I dug through the hal, and it looks like ther is support for slave mode configuration via HAL_TIM_SlaveConfigSynchronization

Right now my thinking is that this would be easiest to add as an extra mode (like IC, PWM) probably called SLAVE.

klik
Posts: 5
Joined: Thu Jan 08, 2015 8:37 am

Re: TIM2 TIM5 Gated mode

Post by klik » Fri Jan 16, 2015 4:48 pm

So finally I have found some time to get a closer look at the code and the STM32F4 datasheet. :(

@dhylands
thank you for your help. But it seems to be merely a polling solution. The while: looks at the Port until it is set. I guess it would work. But not exactly what I was looking for.

But i think, I finally found a solution.

Code: Select all

import pyb
import stm

def initTIM2Gated():
    stm.mem32[stm.TIM2 + stm.TIM_SMCR] = 0x0000
    stm.mem32[stm.TIM2 + stm.TIM_SMCR] = 0x0070
    stm.mem32[stm.TIM2 + stm.TIM_SMCR] = 0x0075

def initTIM5Gated():
    stm.mem32[stm.TIM5 + stm.TIM_SMCR]  = 0x0000 
    stm.mem32[stm.TIM5 + stm.TIM_SMCR] |= 0x0055 

initTIM2Gated()
initTIM5Gated()

timer2 = pyb.Timer(2, prescaler=0, period=0x3FFFFFFF)
pin1 = pyb.Pin(pyb.Pin.board.X6, mode=pyb.Pin.AF_PP, af=pyb.Pin.AF1_TIM2)
timer2.counter(0)

timer5 = pyb.Timer(5, prescaler=0, period=0x3FFFFFFF)
pin5 = pyb.Pin(pyb.Pin.board.X1, mode=pyb.Pin.AF_PP, af=pyb.Pin.AF2_TIM5)
timer5.counter(0)

def c():
    global timer2, timer5
    timer2.counter(0)
    timer5.counter(0)

def r():
    while(1):
        pyb.delay(50)
        print("TIM2")
        print(timer2.counter())
        print(pin1.value())
        print("TIM5")
        print(timer5.counter())
        print(pin5.value())
        print("\n")

c()
r()

The code does the job. Hope I didn't set the self destruction register somewhere. Hope it will be available in a further release like PWM, GATED, ...

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

Re: TIM2 TIM5 Gated mode

Post by dhylands » Fri Jan 16, 2015 5:51 pm

klik wrote:So finally I have found some time to get a closer look at the code and the STM32F4 datasheet. :(

@dhylands
thank you for your help. But it seems to be merely a polling solution. The while: looks at the Port until it is set. I guess it would work. But not exactly what I was looking for.
The while loop was just for controlling the "gate". I'm assuming that you've got other HW for doing that.
klik wrote:But i think, I finally found a solution.

Code: Select all

import pyb
import stm

def initTIM2Gated():
    stm.mem32[stm.TIM2 + stm.TIM_SMCR] = 0x0000
    stm.mem32[stm.TIM2 + stm.TIM_SMCR] = 0x0070
    stm.mem32[stm.TIM2 + stm.TIM_SMCR] = 0x0075

def initTIM5Gated():
    stm.mem32[stm.TIM5 + stm.TIM_SMCR]  = 0x0000 
    stm.mem32[stm.TIM5 + stm.TIM_SMCR] |= 0x0055 

initTIM2Gated()
initTIM5Gated()

timer2 = pyb.Timer(2, prescaler=0, period=0x3FFFFFFF)
pin1 = pyb.Pin(pyb.Pin.board.X6, mode=pyb.Pin.AF_PP, af=pyb.Pin.AF1_TIM2)
timer2.counter(0)

timer5 = pyb.Timer(5, prescaler=0, period=0x3FFFFFFF)
pin5 = pyb.Pin(pyb.Pin.board.X1, mode=pyb.Pin.AF_PP, af=pyb.Pin.AF2_TIM5)
timer5.counter(0)

def c():
    global timer2, timer5
    timer2.counter(0)
    timer5.counter(0)

def r():
    while(1):
        pyb.delay(50)
        print("TIM2")
        print(timer2.counter())
        print(pin1.value())
        print("TIM5")
        print(timer5.counter())
        print(pin5.value())
        print("\n")

c()
r()

The code does the job. Hope I didn't set the self destruction register somewhere. Hope it will be available in a further release like PWM, GATED, ...
Just be careful. When you do stuff like: stm.mem32[stm.TIM2 + stm.TIM_SMCR] = 0x0000 you're zeroing ALL of the fields in the register.

Maybe I misunderstood what you were trying to do. It looks like you're trying to use one timer to gate another? If so, then I missed that detail.

Post Reply