cancel
Showing results for 
Search instead for 
Did you mean: 

Timer One Pulse Mode issues

toddberk
Associate II
Posted on November 10, 2010 at 09:58

Timer One Pulse Mode issues

11 REPLIES 11
lowpowermcu
Associate II
Posted on May 17, 2011 at 14:14

Hi TMecha,

What is the pulse width you want to have ?

Herzlich,

MCU Lüfter

I don't understand what is going with stm32 forum ??!!!!!!

John F.
Senior
Posted on May 17, 2011 at 14:14

Set up (for example) timer 1 and load the pulse width you want.

TIM1->ARR = PulseWidth;

but don't enable the timer yet.

Set up another timer for a 20ms periodic interrupt.

In that interrupt, start your pulse and enable timer 1.

    GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET); //pulse output high

    TIM_Cmd(TIM1, ENABLE);      //start timer 1

The timer 1 interrupt will interrupt after PulseWidth period.

In the timer 1 interrupt, disable and reload the timer and clear the pulse output low.

void TIM1_UP_IRQHandler(void)

{

  //Clear TIM1 update interrupt

  TIM_ClearITPendingBit(TIM1, TIM_IT_Update);

   

  //handle the pulse using timer 1

  TIM1->CR1 &= ((uint16_t)0x03FE);  //disable the TIM Counter

  TIM1->CNT  =  (uint16_t) 0;       //clear the counter

  TIM1->ARR = PulseWidth;

  GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET); //pulse output low

}

You can change the PulseWidth on the fly if you want for different widths every 20ms.

lowpowermcu
Associate II
Posted on May 17, 2011 at 14:14

Hi TMecha,

I can send an example of such use case.

Herzlich,

MCU Lüfter

Posted on May 17, 2011 at 14:14

If you are sending a single pulse every 20 ms, pretty soon you are just generating a frequency with multiple pulses?

If that is the case why not just have the hardware to generate the frequency, and control the pulse width?

On an STM32 running at 32 MHz, here is a 50 Hz signal (20 ms) with 1 ms pulse width.

int TIM4_Configuration(void)

{

    u16 period; // Period, interrupt periodicity in timer ticks

    u16 scale; // Prescale another clock divider (1-65536)

  u16 width; // Pulse width

    int TIM4_Frequency;

    int TIM4_Width;

    RCC_ClocksTypeDef RCC_ClockFreq;

    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

    TIM_OCInitTypeDef  TIM_OCInitStructure;

    GPIO_InitTypeDef GPIO_InitStructure;

  // 32 MHz Master Clock

    scale = 3200; // 32 MHz / 3200 = 10 KHz

  period = 200; // 10 KHz / 200 = 50 Hz (20 ms)

    width = 10;     // 10 KHz = 100 us * 10 = 1000 us (1 ms)

  // For 72 MHz use scale = 7200, at 36 MHz use scale = 3600

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

  /* Time base configuration */

  TIM_TimeBaseStructure.TIM_Period = (period - 1); // 1-65536

  TIM_TimeBaseStructure.TIM_Prescaler = (scale - 1); // 1-65536, Master Clock Divisor

  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 1,2 or 4 for tDTS

  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

   /* PWM1 Mode configuration: Channel1 on PB.06 */

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

  TIM_OCInitStructure.TIM_Pulse = width; // Pulse Width

  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OC1Init(TIM4, &TIM_OCInitStructure);

  TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);

  TIM_ARRPreloadConfig(TIM4, ENABLE);

  /* TIM4 enable counter */

  TIM_Cmd(TIM4, ENABLE);

  /* Configure TIM4_CH1 as alternate function push-pull */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;  // PB.06

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* Compute based on chip settings */

  RCC_GetClocksFreq(&RCC_ClockFreq);

  if (RCC_ClockFreq.HCLK_Frequency == RCC_ClockFreq.PCLK1_Frequency)

        TIM4_Frequency = RCC_ClockFreq.PCLK1_Frequency;

  else

        TIM4_Frequency = RCC_ClockFreq.PCLK1_Frequency * 2;

#ifdef DBG

  printf(''TIM4CLOCK %d Hz\n'',TIM4_Frequency);

#endif

  TIM4_Width            = (1000000 * width) / (TIM4_Frequency / scale);

  TIM4_Frequency    = (TIM4_Frequency / scale) / period; // APB1 (TIM4)

#ifdef DBG

  printf(''TIM4 rate %d Hz, width %s us\n'',TIM4_Frequency, TIM4_Width);

#endif

    return(TIM4_Frequency);

}

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
toddberk
Associate II
Posted on May 17, 2011 at 14:14

MCU Lüfter,

Sorry I should have specified that - the application is to drive numerous RC Servos without much CPU overhead or wait loops. Therefore I would like to vary the Pulse signal from approximately 1ms to 2ms.

An example would be greatly appreciated. I am new to STM32 and so far this community has been great!

-Todd

John F.
Senior
Posted on May 17, 2011 at 14:14

If you understood my suggestion, you should find it works well for you for one servo. (I wrote it to drive a servo with software controlled pulse width.)

If you mean to drive

multiple servos with different pulse widths

then you may have to do more processing in a faster interrupt.

toddberk
Associate II
Posted on May 17, 2011 at 14:14

Thanks clive1,

I think this would probably work, thanks for your example. I will try it. I know I didn't specify the pulse should change in my original post, but in order to maximize resolution for adjusting the pulse width I believe I should adjust the scale so that period is close to 65536. Please confirm my calculations here:

SYSClock = 72Mhz

AHB prescalar = 1

APB1 prescalar = 2

PCLK1 = 36 Mhz

Scale = (36000000*.02)/65536 = 11 (3.272 Mhz)

Period = (36000000/11)*.02 = 65455

Width(1ms) = 3272

Width(2ms) = 6546

This effectively gives me a resolution of about 3273 between 1ms and 2ms, correct?

Thanks!

-Todd

lowpowermcu
Associate II
Posted on May 17, 2011 at 14:14

Hi TMecha,

There is an example in ST library for one pulse mode which helped me to understand

the one pulse mode for timers

Let's we use TIM2 and TIM4 timers: TIM2 will trigger TIM4 every 20 ms.

TIM2 must be configured in such way to generate update event every 20 ms

(APB frequency/ARR register = 50 Hz, I think you must use timer prescaler)

and select update event of TIM2 to trigger TIM4 using

TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update)

Now TIM4 must be configured in one pulse mode then select the input trigger

from TIM2 using TIM_SelectInputTrigger() (you must refer to your product reference

manual to know if you should select ITR0 , ITR1 or ITR2...)

Finally, select slave mode with trigger for TIM4 using TIM_SelectSlaveMode()

Now enable both timers TIM_Cmd(TIMx, ENABLE)

In this configuration, you don't need processing interrupts.

Do not hesitate if that stills not clear otherwise tell me how I can send you my source.

Herzlich,

MCU Lüfter

John F.
Senior
Posted on May 17, 2011 at 14:14

Or do this ... (without the remap if you want)

#include ''stm32f10x.h''

void RCC_Configuration(void);

void GPIO_Configuration(void);

void Timer1_Configuration(void);

//note with SYSCLK_FREQ_72MHz defined, PCLK1 = 36MHz and PCLK2 = 72MHz

uint16_t CCR1_Val = 1000; //1500 = 1.5ms (1000 = 1ms, 2000 = 2ms);

int main(void)

{

  RCC_Configuration();

  GPIO_Configuration();

  Timer1_Configuration();

  while(1)

  {

    ;

  }

}

void RCC_Configuration(void)

{

  //Setup the microcontroller system. Initialize the Embedded Flash Interface, 

  //initialize the PLL and update the SystemFrequency variable.

  SystemInit();

 

  // Enable GPIOB, AFIO and Timer1 clocks

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO | RCC_APB2Periph_TIM1, ENABLE);

}

void GPIO_Configuration(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

  //partial remap of Timer1

  GPIO_PinRemapConfig(GPIO_PartialRemap_TIM1, ENABLE);

  //GPIOB Configuration: TIM1 channel 2N as alternate function push-pull

  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(GPIOB, &GPIO_InitStructure);

}

void Timer1_Configuration(void)

{

  //Timer1 is clocked by PCLK2 = 72MHz

  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

  TIM_OCInitTypeDef  TIM_OCInitStructure;

  TIM_DeInit(TIM1);

  //Time base configuration

  TIM_TimeBaseStructure.TIM_Prescaler = 71; //clocked at 72MHz / 72 = 1MHz

  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseStructure.TIM_Period = 19999; //period = (72MHz / 72) / 20000 = 50Hz (20ms period)

  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;

  TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

  /* Channel 1 Configuration in PWM mode */

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

  TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;

  TIM_OCInitStructure.TIM_Pulse = CCR1_Val;

  TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;

  TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;

  TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;

 

  TIM_OC2Init(TIM1, &TIM_OCInitStructure);

  TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);

  TIM_CtrlPWMOutputs(TIM1, ENABLE);

  //TIM1 enable counter

  TIM_Cmd(TIM1, ENABLE);

}