AnsweredAssumed Answered

STM32F4 timer in input capture mode failing to detect falling edge

Question asked by Mike Thompson on Dec 13, 2017
Latest reply on Dec 14, 2017 by waclawek.jan

On an STM32F407 device I'm configuring a timer TIM4 in input capture mode to measure the input duration of a PWM signal on the Channel 3 input.  The signal comes for a US Digital absolute encoder where the duty cycle of the 4ms PWM signal indicates the encoder position.


The problem I'm having is that when I swap the capture/compare 3 polarity (CC3P) bit in the timer capture/compare enable register (CCER) register,  the timer continues to only detect the rising edge of the PWM signal.  Code similar to that shown below works for advanced control timers TIM1 and TIM8 on all four channels, but it won't work for general purpose TIM4 on channel 3. Is the ability to detect a falling edge a known issue with general purpose timers?


My interrupt handler where I swap the polarity bit is shown below.


volatile uint16_t rise_time = 0;

void TIM4_IRQHandler(void)
  uint16_t ccer;
  uint16_t capture;
  uint16_t duration;

  // TMR4 Channel 3 steering position capture processing.
  if ((TIM4->SR & TIM_IT_CC3) && (TIM4->DIER & TIM_IT_CC3))
    // Get the input capture value. This clears the interrupt.
    capture = (uint16_t) TIM4->CCR3;

    // Get the timer capture compare enable register (CCER).
    ccer = TIM4->CCER;

    // Did we detect the rising or falling edge?
    if (ccer & 0x20)
      // Falling edge so determine the pulse duration.
      duration = capture - rise_time;

      // Process the duration.
      pwm_process_duration(PWM_CHANNEL_STEER, duration);
      // Rising edge so we save the capture value.
      rise_time = capture;

    // Invert the capture polarity bit.
    ccer ^= 0x20;

    // Make sure capture is enabled.
    ccer |= 0x10;

    // Write back the CCER register.
    TIM4->CCER = ccer;


My GPIO and timer initialization code is here:


  GPIO_InitTypeDef gpio_init;
  TIM_ICInitTypeDef tim_ic_init;
  TIM_TimeBaseInitTypeDef tim_timebase_init;

  // Alternate functions for TIM4 channel 3 and 4 pins.
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_TIM4);

  // Configure GPIOB pins for alternate functions.
  gpio_init.GPIO_Pin = GPIO_Pin_8;
  gpio_init.GPIO_Mode = GPIO_Mode_AF;
  gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
  gpio_init.GPIO_OType = GPIO_OType_PP;
  gpio_init.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOB, &gpio_init);

  // Timer configuration.
  // APB1 clock is 84MHz so a prescaler of 84000000 / 1000000 - 1 = 83
  tim_timebase_init.TIM_Period = 0xffff;
  tim_timebase_init.TIM_Prescaler = 83;
  tim_timebase_init.TIM_ClockDivision = TIM_CKD_DIV1;
  tim_timebase_init.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM4, &tim_timebase_init);

  // TIM4 channel 3 configuration.
  tim_ic_init.TIM_Channel = TIM_Channel_3;
  tim_ic_init.TIM_ICPolarity = TIM_ICPolarity_Rising;
  tim_ic_init.TIM_ICSelection = TIM_ICSelection_DirectTI;
  tim_ic_init.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  tim_ic_init.TIM_ICFilter = 0x0;
  TIM_ICInit(TIM4, &tim_ic_init);

  // Clear the interrupt pending bits.
  TIM_ClearITPendingBit(TIM4, TIM_IT_CC4);

  // Enable the TIM4 CC4 interrupt request.

  // Enable TIM4.