Clive One

L4 Input Capture oddness

Discussion created by Clive One on Nov 15, 2017
Latest reply on Nov 16, 2017 by Clive One

Doing some testing here with PWM Input Mode where TIM2 CH1/CH2 are measuring a 1PPS (1Hz, 10% duty) signal in units of the the system clock. Here nominally 30.72 MHz, but synchronous to the 1PPS source, and good to ppb.

 

In PWM Input Mode the period is consistently measured 2 cycles shorter than the same configuration using Input Capture Mode and subtracting timestamps for 2 consecutive rising edges.

 

Thus the count for period in PWM Input reads 30,719,998 whereas Input Capture results in 30,720,000 which is the correct result. Get similar off-by-two numbers at 96 MHz via PLL. ie 95,999,998 vs 96,000,000

 

 

Configuration for TIM[2/5]_CH2 looks as follows

 

/* Set TIMx instance */
TimHandle.Instance = TIMx;

/* Initialize TIMx peripheral as follows:
+ Period = 0xFFFFFFFF
+ Prescaler = 0
+ ClockDivision = 0
+ Counter direction = Up
*/
TimHandle.Init.Period = 0xFFFFFFFF;
TimHandle.Init.Prescaler = 0;
TimHandle.Init.ClockDivision = 0;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.RepetitionCounter = 0;
TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_IC_Init(&TimHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}

/*##-2- Configure the Input Capture channels ###############################*/
/* Common configuration */
sConfig.ICPrescaler = TIM_ICPSC_DIV1;
sConfig.ICFilter = 0;

/* Configure the Input Capture of channel 1 */
sConfig.ICPolarity = TIM_ICPOLARITY_FALLING;
sConfig.ICSelection = TIM_ICSELECTION_INDIRECTTI;
if (HAL_TIM_IC_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_1) != HAL_OK)
{
/* Configuration Error */
Error_Handler();
}

/* Configure the Input Capture of channel 2 */
sConfig.ICPolarity = TIM_ICPOLARITY_RISING;
sConfig.ICSelection = TIM_ICSELECTION_DIRECTTI;
if (HAL_TIM_IC_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_2) != HAL_OK)
{
/* Configuration Error */
Error_Handler();
}
/*##-3- Configure the slave mode ###########################################*/
/* Select the slave Mode: Reset Mode */
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_RESET;
sSlaveConfig.InputTrigger = TIM_TS_TI2FP2;
sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_NONINVERTED;
sSlaveConfig.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1;
sSlaveConfig.TriggerFilter = 0;

if (HAL_TIM_SlaveConfigSynchronization(&TimHandle, &sSlaveConfig) != HAL_OK)
{
/* Configuration Error */
Error_Handler();
}

/*##-4- Start the Input Capture in interrupt mode ##########################*/
if (HAL_TIM_IC_Start_IT(&TimHandle, TIM_CHANNEL_2) != HAL_OK)
{
/* Starting Error */
Error_Handler();
}

/*##-5- Start the Input Capture in interrupt mode ##########################*/
if (HAL_TIM_IC_Start_IT(&TimHandle, TIM_CHANNEL_1) != HAL_OK)
{
/* Starting Error */
Error_Handler();
}

 

Now re-reading the docs, off-by-one seems to be how this works, but it isn't reflected in the example code

 

 

/**
* @brief Input Capture callback in non blocking mode
* @param htim : TIM IC handle
* @retval None
*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
/* Get the Input Capture value */
uwIC2Value = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);

if (uwIC2Value != 0)
{
/* Duty cycle computation */
uwDutyCycle = ((HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1)) * 100) / uwIC2Value;

/* uwFrequency computation
TIM3 counter clock = (RCC_Clocks.HCLK_Frequency) */
uwFrequency = (HAL_RCC_GetHCLKFreq()) / (uwIC2Value * 2);
}
else
{
uwDutyCycle = 0;
uwFrequency = 0;
}
}
}

 

In my case I'm looking at HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2) directly so the broken math doesn't explain the off-by-two issue, neither should the input resynchronizer.

Outcomes