Electronic – How to use a STM32F030F4’s timer 3 in input capture mode to measure pulse width

measurementpulsestm32stm32f0timer

Update

I checked the block diagram of the timer 3 again

block diagram

It looks like there's no connection between channel 4 and the trigger input TRGI. Is this correct?

Can I use channel 4 for gated mode?

original question

I have the following signal with varying pulse width. (high)

pulses

I want to measure the pulse width with an STM32F030F4 (link removed due to reputation limit).

The signal is connected to Pin 14, PB1. I verified that the signal can be scoped directly at the pin of the µC, so it should be there.
I want to use timer 3 because its channel 4 is connected to that pin.

Chapter 13.3.19 TIMx and external trigger synchronization of the reference manual describes a mode that's exactly what I'm looking for.

Slave mode: Gated mode

The counter can be enabled depending on the level of a selected input.

There's also an example for that:

A.8.13 Gated mode code example

/* (1) Configure channel 1 to detect low level on the TI1 input       
by writing CC1S = ‘01’,       
and configure the input filter duration by writing the IC1F[3:0]       
bits in the TIMx_CCMR1 register (if no filter is needed,       
keep IC1F=0000). */ 

/* (2) Select polarity by writing CC1P=1 in the TIMx_CCER register */ 

/* (3) Configure the timer in gated mode by writing SMS=101       
Select TI1 as the trigger input source by writing TS=101       
in the TIMx_SMCR register. */ 

/* (4) Set prescaler to 12000-1 in order to get an increment each 250us */ 

/* (5) Enable the counter by writing CEN=1 in the TIMx_CR1 register. */ 

TIMx->CCMR1 |= TIM_CCMR1_CC1S_0; /* (1)*/ 
TIMx->CCER |= TIM_CCER_CC1P; /* (2) */ 
TIMx->SMCR |= TIM_SMCR_SMS_2 | TIM_SMCR_SMS_0 | TIM_SMCR_TS_2 | TIM_SMCR_TS_0; /* (3) */ 
TIMx->PSC = 11999; /* (4) */ 
TIMx->CR1 |= TIM_CR1_CEN; /* (5) */

I tried to modify the example to my needs and it looks like that:

// based on example A.8.13

/* (1) Configure channel 4 to detect low level on the TI4 input
 * by writing CC4S = ‘01’,
 * and configure the input filter duration by writing the IC1F[3:0]
 * bits in the TIMx_CCMR1 register (if no filter is needed,
 * keep IC1F=0000). */

/* (2) Select polarity by writing CC4P=1 in the TIMx_CCER register */

/* (3) Configure the timer in gated mode by writing SMS=101
 * Select TI1 as the trigger input source by writing TS=101
 * in the TIMx_SMCR register. */

/* (4) Set prescaler to 12000-1 in order to get an increment each 250us */

/* (5) Enable the counter by writing CEN=1 in the TIMx_CR1 register. */

TIM3->CCMR2 |= TIM_CCMR2_CC4S_0; /* (1) */
TIM3->CCER |= TIM_CCER_CC4P; /* (2) */
TIM3->SMCR |= TIM_SMCR_SMS_2 | TIM_SMCR_SMS_0 | TIM_SMCR_TS_2 | TIM_SMCR_TS_0; /* (3) */
TIM3->PSC = 11999; /* (4) */
TIM3->CR1 |= TIM_CR1_CEN; /* (5) */

I would expect that the counter register of timer 3 TIM3->CNT changes over time as the pulses tickle in.

However, TIM3->CNT does not change at all.

Here's the configuration that I suspect to be erroneous

GPIO

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(tim_baseHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspInit 0 */

  /* USER CODE END TIM3_MspInit 0 */
    /* Peripheral clock enable */
      __TIM3_CLK_ENABLE();

    /**TIM3 GPIO Configuration
    PB1     ------> TIM3_CH4
    */
    GPIO_InitStruct.Pin = GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM3;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM3_MspInit 1 */

  /* USER CODE END TIM3_MspInit 1 */
  }
}

timer

/* TIM3 init function */
void MX_TIM3_Init(void)
{

  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_SlaveConfigTypeDef sSlaveConfig;
  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_IC_InitTypeDef sConfigIC;

  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 0;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 0;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }

  if (HAL_TIM_IC_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }

  sSlaveConfig.SlaveMode = TIM_SLAVEMODE_GATED;
  sSlaveConfig.InputTrigger = TIM_TS_ITR0;
  if (HAL_TIM_SlaveConfigSynchronization(&htim3, &sSlaveConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
  sConfigIC.ICFilter = 0;
  if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_4) != HAL_OK)
  {
    Error_Handler();
  }

}

When debugging, I can see the configuration registers change and read/write their values, but the counter register is not increasing.

Best Answer

Looks like using the input capture mode is not possible, because channel 4 cannot be used as trigger.

I give up. Too many different examples on the web using too many different configuration tools, tool chains, etc.