AnsweredAssumed Answered

STM32F103 - Trying to measure Duty Cycle on 20Khz signal

Question asked by ricker.d on Feb 21, 2014
Latest reply on Feb 27, 2014 by ricker.d
Hello,
I am trying to use a STM32F103 (8Mhz external clock) to get the duty cycle of a 20 Khz PWM signal.  I am using Timer2 and trying to look at the rising edge using channel 1 and pointing channel 2 at channel 1 input to capture the falling edge.  To help me visualize what is going on, I am toggling one output for a rising edge and another for a falling.  What I see on the oscilliscope compared to the incoming signal (using a Pulse generator around 1kHz at 50% DC) is that the rising edge output comes about 40 uS after the input rising edge and the falling edge output toggles about 6 uS after the input's falling edge.  I think I have all sampling turned off on these channels.  Why the large delay? Needless to say, with these kinds of delays getting to the interrupt, I won't be able to handle the 20kHz pwm coming in.  Do I have a setting wrong that is delaying my interrupt?  40uS is a long time considering my program isn't really doing anything else.  Any help would be greatly appreciated.
Code is attached below
Thanks!


//################### Includes ######################
#include "stm32f10x.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_exti.h"
#include "misc.h"
#include "stdio.h"
 
//################ Private Variables ##################
 
#define output1     GPIO_Pin_6
#define output2     GPIO_Pin_7
 
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; //Initialize variables to set up Timers
TIM_OCInitTypeDef  TIM_OCInitStructure;
TIM_ICInitTypeDef  TIM_ICInitStructure;
int16_t reg_h=0;                        // High Register for T2
uint16_t reg_l=0;                       // Low Regiser for T2 (For Input Capture)
uint16_t T2_DC  =0;                 // Timer Two Duty Cycle
unsigned char update_per=0;         // Flag to update period, set by T2 Input Capture
unsigned char T2_Overrun=0;         // Timer 2 overrun count
unsigned char temp=0,temp1=0;
 
 
//########################## Private Function Prototypes ##########################
 
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void Timer_Configuration(void);
void TIM2_IRQHandler(void);
 
//########################## Main Program #########################################
int main(void)
{
    GPIO_ResetBits(GPIOB,GPIO_Pin_0);
    /* System Clocks Config */
    RCC_Configuration();
    /* GPIO Config */
    GPIO_Configuration();
    /* Interrupt Config */
    NVIC_Configuration();
    /* Timer Config */
    Timer_Configuration();
 
    while (1)
    {
        GPIO_ResetBits(GPIOB,GPIO_Pin_0);
 
        if(update_per)
        {
                T2_DC = (reg_h*100/(reg_l+reg_h));
                reg_h=0;
                reg_l=0;                                // Clear variables
                update_per=0;                           // Reset update period flag
        }
 
    }
}
 
//#################### Timer 2 Interrupt Handler ################
void TIM2_IRQHandler(void)
{
 
    if(TIM_GetITStatus(TIM2, TIM_IT_CC1) == SET)            // If compare capture has occured
    {
        TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
        reg_l = TIM_GetCapture1(TIM2);                      // Get timer counts for Period
                        // Get timer counts during wave high
        GPIOA->ODR ^= output2;
 
        update_per=1;                                       // Set Flag to update period
 
    }
    if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == SET)            // If compare capture has occured
    {
        TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
        reg_h= TIM_GetCapture2(TIM2);
        GPIOA->ODR ^= output1;
    }
 
    if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
    {
         TIM_ClearITPendingBit(TIM2, TIM_IT_Update);    // Counter overflow, reset interrupt
         if(T2_Overrun<127){T2_Overrun++;}
    }
 
}
 
//##################### RCC Configuration Routine ####################
 
   void RCC_Configuration(void)
   {
 
       /* TIM2 clock enable*/
       RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
       RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM2, DISABLE);
 
       /* GPIOA GPIOB and GPIOC clock enable */
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_AFIO, ENABLE);
 
 
   }
 
//################### GPIO Configuration Routine ########################
 
   void GPIO_Configuration(void)
   {
       GPIO_InitTypeDef GPIO_InitStructure;
 
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOA, &GPIO_InitStructure);
 
      GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOA, &GPIO_InitStructure);
 
      /* GPIOB Config */
      GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_InitStructure);
 
   }
 
//################## Interrupt Configuration Routine #########################
   void NVIC_Configuration(void)
   {
        NVIC_InitTypeDef NVIC_InitStructure;
 
       //enable tim2 irq
        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
 
   }
 
   void Timer_Configuration(void){
 
        //********************************************************************
        //******** Set Timer 2 Interrupt (Input Pulse Capture) ***********
        //********************************************************************
 
           /* Time base configuration */
 
        TIM_TimeBaseStructure.TIM_Prescaler = 2;
        TIM_TimeBaseStructure.TIM_Period = 60000;
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
 
        TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
        TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
        TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
        TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
        TIM_ICInitStructure.TIM_ICFilter = 0x00;
        TIM_ICInit(TIM2, &TIM_ICInitStructure);
 
           /* Channel 2 Config*/
        TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
        TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
        TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;
        TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
        TIM_ICInitStructure.TIM_ICFilter = 0x00;
        TIM_ICInit(TIM2, &TIM_ICInitStructure);
 
        TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
        TIM_ITConfig(TIM2, TIM_IT_CC2, ENABLE);
        TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
 
        /*More*/
        TIM_SelectInputTrigger(TIM2,TIM_TS_TI1FP1);
        TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);
 
        /* TIM2 enable counter */
        TIM_Cmd(TIM2, ENABLE);
   }
 
#ifdef  USE_FULL_ASSERT
 
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
 
  while (1)
  {}
}
#endif

Outcomes