cancel
Showing results for 
Search instead for 
Did you mean: 

About the stability of PWM mode

YaoYaoLin
Associate
void init_servo_timer()
{
    u16 tmp_period = 0;
    u16 CCR1_Val = 0;
 
    pulse_num_1ms = 0;
    pulse_period = (1/((float)pulse_num_1ms));
    tmp_period = (u16)(pulse_period * 36000);
    CCR1_Val = (tmp_period / 2 );
 
    TIM_DeInit(TIM1);
    /* (TIM_Period = TIM1->ARR) = 72MHz / prescaler */
    TIM_TimeBaseStructure.TIM_Period = (tmp_period);        
    TIM_TimeBaseStructure.TIM_Prescaler = (2 - 1); /* prescaler = 2 */
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x00;
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
    TIM_ITConfig(TIM1,TIM_IT_CC1,ENABLE);
    TIM_Cmd(TIM1, ENABLE);
 
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    
    TIM_OCInitStructure.TIM_Pulse = CCR1_Val; /* TIM1-> CCR1 */
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
    TIM_OC1Init(TIM1, &TIM_OCInitStructure);
    TIM_CtrlPWMOutputs(TIM1, ENABLE);
    
}
 
void TIM1_CC_IRQHandler(void)
{    
        TEST_LED = ~TEST_LED;
    if ( TIM_GetITStatus(TIM1 , TIM_IT_CC1)) 
    {
        TIM_ClearITPendingBit(TIM1 , TIM_IT_CC1);
 
            pulse_cnt ++;
            if(am.dir)
                am.now_addr --;              
            else
                am.now_addr ++;
 
            if(pulse_cnt >= am.speed_cnt)
            {
                pulse_cnt = 0;
                if(am.now_addr == am.set_addr)
                {
                    am.run = 0;
                    am.speed_cnt = 0;
                }
            }
    }
        TEST_LED = ~TEST_LED;
    
}
// I put output_servo_am_pulse() function in 1ms loop 
void output_servo_am_pulse(void)
{    
    if((am.h_run | am.run))
    {
        if(am.speed_cnt)
        {
            pulse_cnt = 0;
            TIM1->CNT = 1;
            TIM1->ARR = (u16)((36000 / am.speed_cnt));
            TIM1->CCR1 = (TIM1->ARR >> 1 );
        }
    }
    else
    {
        TIM1->ARR = 0;
        TIM1->CCR1 = 0;
    }
  
}

I was confusing why the pulse sometimes ARR should be reload (pulse 5.5us)but it didn't, but from the picture of waveform , I can still see the compare interrupt(TEST_LED 2us) still work.

By the way, I am using stm32f103xxx.

0693W000006HUcXQAW.png 

Can anyone help me for this problem? Thanks a lot.

2 REPLIES 2

Is your logic analyzer fast enough to display a pulse 1 cycle long? And is the PWM output pin set fast enough in GPIO_CRx.MODEx to output a pulse 1 cycle long?

Btw. if you use only 50% duty cycle, it's more elegant to use Toggle mode of the timer.

JW

As you see the top of my logic analyzer its sample rate is 2MHz, that means it shows every 1/2MHz( = 500ns).

Do you mean this configuration?

GPIO_InitStructure.GPIO_Pin =   GPIO_Pin_8
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

Yeah, I know about Toggle mode. The important thing is I want the interrupt appears at negative edge trigger of the pulse. So that's why I pick PWM1 mode.

By the way, PWM mode is more alternative I thought.

The new things I found was, if I show TIM1(pulse generate) and TIM5(1ms loop) separately, then everything happened accurately. But when I put them together, then TIM1 and TIM5 affect each other, for instance, 1ms later become 1.001ms ~ 1.004ms, that would increase about 1~4us, 2us is large enough to make the interrupt of TIM1 delay.

Thanks for reply, WYL