2010-11-10 12:58 AM
Timer One Pulse Mode issues
2011-05-17 05:14 AM
Hi TMecha,
What is the pulse width you want to have ? Herzlich, MCU LüfterI don't understand what is going with stm32 forum ??!!!!!!2011-05-17 05:14 AM
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.2011-05-17 05:14 AM
Hi TMecha,
I can send an example of such use case. Herzlich, MCU Lüfter2011-05-17 05:14 AM
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); }2011-05-17 05:14 AM
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
2011-05-17 05:14 AM
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 drivemultiple servos with different pulse widths
then you may have to do more processing in a faster interrupt.2011-05-17 05:14 AM
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
2011-05-17 05:14 AM
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üfter2011-05-17 05:14 AM
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); }