2024-06-27 06:19 AM
Hello Community,
I have an incremental encoder with 30 detents interfaced on STM32H5562 where I have set my TIMER2 in Encoder mode and using interrupt as shown below:
static void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_Encoder_InitTypeDef sConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 4294967295;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
sConfig.EncoderMode = TIM_ENCODERMODE_TI12;
sConfig.IC1Polarity = TIM_ICPOLARITY_FALLING;
sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
sConfig.IC1Filter = 0;
sConfig.IC2Polarity = TIM_ICPOLARITY_FALLING;
sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
sConfig.IC2Filter = 0;
if (HAL_TIM_Encoder_Init(&htim2, &sConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
HAL_TIM_Encoder_Start_IT(&htim2,TIM_CHANNEL_ALL); //start the encoder timer 2
/* USER CODE END TIM2_Init 2 */
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim == &htim2)
{
counter1 = __HAL_TIM_GET_COUNTER(&htim2);
}
}
The problem I have is that HAL_TIM_IC_CaptureCallback is triggered every second step of the encoder.
I would like the HAL_TIM_IC_CaptureCallback to trigger on each turn(detent).
On the other hand, if I use the __HAL_TIM_GET_COUNTER(&htim2) inside the while loop the counter is updated on each turn.
Do you know how this can be achieved within the interrupt?
Following is a part of the encoder datasheet.
Thank you.
2024-07-02 02:36 AM
Hi @BarryWhit ,
Following is a bit more info on what is happening:
You can see below on the oscilloscope the capture of the two signals where Encoder_A is on CH1 and Encoder_B is on CH2.
When Encoder_B signal goes low first the two counters are not the same. I believe this happens because the polarity of the Encoder_B on the firmware is set to rising but the signal goes low instead therefore missing 1 count within the interrupt. In the while loop the counter is updates correctly though.
On the other hand, when Encoder goes high first the two counters (in the interrupt and while loop)are the same:
The same behaviour occurs on the opposite direction.
As a recap following is how the two signals are configured:
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 4294967295;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
sConfig.EncoderMode = TIM_ENCODERMODE_TI12;
sConfig.IC1Polarity = TIM_ICPOLARITY_FALLING;
sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
sConfig.IC1Filter = 0;
sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
sConfig.IC2Filter = 0;
2024-07-02 04:50 AM - edited 2024-07-02 06:24 AM
Right. So, you have two edges per counter tick.
Input Capture events normally (i.e. I expect that it does) triggers on a switch in logic level, not when the counter changes value. So, if a pin toggles, but (due to polarity, turn direction, whatever) this edge is not what triggers the change to the counter value, when you read the counter value in the callback, it hasn't yet seen the other edge. When the other edge occurs, the counter updates, but there's no callback, because the 2nd edge does not trigger an Input Capture event. Does that make sense?
2024-07-02 04:55 AM
Yes absolutely.
In my application I will be just reading the counter value lets say on a different timer interrupt and not within the HAL_TIM_IC_CaptureCallback.
Thanks for your help.
2024-07-02 06:19 AM - edited 2024-07-02 07:30 AM
Wait for JW to weight in though. He is as knowledgeable as could be and, re-reading his earlier comment, I (and AFAICT, the system's behavior) seem to be at odds with his description. Always risky that. Let's see what he says.
Also, quite possible, switching the polarity of the other line instead, might align the capture event with the counter change event. Though perhaps only in one direction (but then again-again, maybe your application has a direction you care more about). I've not looked at this too closely tbh.
You could also capture the edge on the second input (using another channel), and that way you can be sure you catch the change in a callback. I don't think turning a 30detent encoder would physically result in an interrupt storm, so this might be practical. But it might be even better, as you said, not to to have to rely on the callback at all. If you're concerned it's a bug or problem - I don't think it is. Just a nuance.