Friday, August 17, 2012

Bug in STM32? TIM's One-pulse mode


Update: Apparently the issue was in how well I read documentation. Thanks to Foobear:
Hope you figured this out already, but TIM3 Doesn't have an RCR. You need to use TIM1 or maybe TIM12-17.


OLD text:

I just ran an experiment with an STM32F100RB6 and got a slightly discouraging result. Here's what I wanted - to have a timer to fire three times and stop automatically.
TIMs in STM32 have repetitions counters:

The time-base unit includes:

  • Counter register (TIMx_CNT)
  • Prescaler register (TIMx_PSC)
  • Auto-reload register (TIMx_ARR)
  • Repetition counter register (TIMx_RCR)
Repetition counter
Section 12.3.1: Time-base unit describes how the update event (UEV) is generated with respect to the counter overflows/underflows. It is actually generated only when the repetition counter has reached zero. This can be useful when generating PWM signals. This means that data are transferred from the preload registers to the shadow registers (TIMx_ARR auto-reload register, TIMx_PSC prescaler register, but also TIMx_CCRx capture/compare registers in compare mode) every N counter overflows or underflows, where N is the value in the TIMx_RCR repetition counter register.

Note the underlined. Then, there's a One-pulse mode.

One-pulse mode (OPM) ... allows the counter to be started in response to a stimulus and to generate a pulse with a programmable length after a programmable delay. You select One-pulse mode by setting the OPM bit in the TIMx_CR1 register. This makes the counter stop automatically at the next update event UEV.

So, if I read that correctly: if I setup an STM32 properly in One-pulse mode and set the TIM's repetition counter to N, I'll get N pulses. However this is not happening. Just one pulse - that's it. Exactly as the mode's name suggests.

Code to verify and/or try yourself:


#include "stm32f10x_gpio.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_rcc.h"


void tim3ch3onePulse()
{

    /*Please set RCC before to 24mhz (or calculate new prescalers for your
     * desired values)
     * */
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;

    //set clock to TIM3
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    //enable port B and alternate function
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_AFIO,ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;

    //init port B pin 0 = TIM3 channel 3 to alternate function push-pull

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    //timer basestructure 24mhz/(0+1)/(0+1) ~ 2,72mS (655353/24000000)s for full period
    TIM_TimeBaseStructure.TIM_Prescaler = 0 ;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 2;
    TIM_TimeBaseStructure.TIM_Period = 65535 ;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);


    /* TIM3 PWM2 Mode configuration: Channel1 */
    //for one pulse mode set PWM2, output enable, pulse (1/(t_wanted=TIM_period-TIM_Pulse)), set polarity high
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 48000;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

    TIM_OC3Init(TIM3, &TIM_OCInitStructure);

    TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Disable);

    /* OPM Bit -> Only one pulse */
    TIM_SelectOnePulseMode (TIM3, TIM_OPMode_Single);
    /* TIM3 enable counter */
    TIM_Cmd(TIM3, ENABLE);
}

I think I should post it to ST community forums...

Cheers!

P.S. Another not so great thing is that repetition counters are just 8 bits. That's so few...

2 comments:

Foobear said...

Hope you figured this out already, but TIM3 Doesn't have an RCR. You need to use TIM1 or maybe TIM12-17.

dccharacter said...

OMG, that's true. Thanks!