Using an encoder: Jitter Incorrectly Trigger Interrupts
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2024-09-19 12:42 AM - last edited on ‎2024-09-19 1:05 AM by mƎALLEm
Hello,
I‘m creating a counter that increments/decrements according to cw/ccw direction of an encoder.
An interrupt is triggered by the rising and falling edge on each channel.
Due to mechanical jitter, the interrupts are triggered (sometimes) simultaneously and will increment by values greater than 1. I was thinking of using a delay but how can I make my interrupt handlers more robust to prevent this occurring?
int main(){
  FLASH_Init();
  RCC_Init();
  GPIO_Init();
  USART2_Init();
  EXTI0_Init();
  EXTI1_Init();
  NVIC_Init();
  while(1){
   
  }
}
void EXTI0_IRQHandler(void){
  if (EXTI -> PR & (0x01U)){
    if (((GPIOA -> IDR & (0x1U)) && (GPIOA -> IDR & (0x2U))) || ((!(GPIOA -> IDR & (0x1U))) && (!(GPIOA -> IDR & (0x2U))))){
      STATE++;
      printf("Encoder counts = %d \n\r",STATE);
      //GPIOA -> ODR ^= (0x01U << 5);
    }
    if (((GPIOA -> IDR & (0x1U)) && (!(GPIOA -> IDR & (0x2U)))) || ((!(GPIOA -> IDR & (0x1U))) && (GPIOA -> IDR & (0x2U)))) {
      STATE --;
      printf("Encoder counts = %d \n\r",STATE);
    }
  }
  EXTI -> PR = (0xFFFFFU);
//  NVIC -> ICER[0] |= (0x1U << 6);
//  NVIC -> ISER[0] |= (0x1U << 7);
}
void EXTI1_IRQHandler(void){
  if (EXTI -> PR & (0x01U<<1)){
    if (((!(GPIOA -> IDR & (0x2U))) && (GPIOA -> IDR & (0x1U))) || ((GPIOA -> IDR & (0x2U)) && (!(GPIOA -> IDR & (0x1U))))) {
      STATE ++;
      printf("Encoder counts = %d \n\r",STATE);
      //GPIOA -> ODR ^= (0x01U << 5);
    }
    if (((GPIOA -> IDR & (0x2U)) && (GPIOA -> IDR & (0x1U))) || ((!(GPIOA -> IDR & (0x2U))) && (!(GPIOA -> IDR & (0x1U))))){
      STATE --;
      printf("Encoder counts = %d \n\r",STATE);
    }
  }
  EXTI -> PR = (0xFFFFFU);
//  NVIC -> ICER[0] |= (0x1U << 7);
//  NVIC -> ISER[0] |= (0x1U << 6);
}
Solved! Go to Solution.
- Labels:
-
ST boards
-
STM32F1 Series
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-02-05 8:59 AM
Thanks for the advice. It took a while, but I have 4 encoders running on my PCB now with no issues at all. Here are a few things I've done (which I understand may not be the best approach but have solved the issue):
- A debounce period that is flagged by the EXTI handler and cleared by a timer after a required period has elapsed
- The EXTI handler does as little logic processing as possible - it simply sets/clears flags
- Another timer is used as a 'heartbeat' signal and circular buffer
The printf statement was removed after all testing/development was finalised. This was a good (but troublesome) learning experience
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2024-09-19 1:17 AM
Hello @XPChi and welcome to the community,
First of all, remove all these printfs from the interrupt handlers. This blocks the execution for a considerable time.
See this link: https://developer.arm.com/documentation/ka002394/latest/
Second, I'm wondering why you are clearing all the EXTI flags for a specific EXTI interrupt. Also you need to clear the interrupt as soon as you get into the interrupt handler.
See for example how The EXTI interrupt handler is implemented in HAL:
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2024-09-19 5:58 AM
> EXTI -> PR = (0xFFFFFU);
Don't blindly clear all the flags. You may be clearing ones which haven't been processed yet. Only clear the flag you have handled.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2024-09-19 7:09 AM
Hi @mÆŽALLEm , thanks for the welcome. I'm avoiding using HAL as I would rather have full control of all the registers that I'm using and also for debugging purposes.
I'm aware of the interrupt clear, this due to the fact that only EXTI0 and EXTI1 are being used. I clear them after an interrupt has been triggered to prevent a jitter enabling an interrupt incorrectly.
I've cleared the interrupt in the beginning as you suggested, however, this doesn't seem to ignore any mechanical noise.
Thanks
XPChi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2024-09-19 7:17 AM
@XPChi wrote:
I'm aware of the interrupt clear, this due to the fact that only EXTI0 and EXTI1 are being used.
Better to clear them separately.
@XPChi wrote:
I'm avoiding using HAL as I would rather have full control of all the registers that I'm using and also for debugging purposes.
I'm not suggesting you to use HAL but inspiring from it.
Did you also remove all the printfs from the IRQ handlers?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2024-09-19 1:26 PM
Why are you using GPIO interrupts to read the encoder? You're like recreating the wheel.
Instead, use a Timer in encoder mode which does all the hard work for you.
Just create a new project in STM32CubeIDE in Timer Encoder mode and extract the parts you need from the HAL driver.
TimerCallback tutorial! | UART and DMA Idle tutorial!
If you find my solution useful, please click the Accept as Solution so others see the solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2024-09-20 8:32 AM
@Karl Yamashita wrote:
Why are you using GPIO interrupts to read the encoder? You're like recreating the wheel.
Indeed!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-02-05 8:59 AM
Thanks for the advice. It took a while, but I have 4 encoders running on my PCB now with no issues at all. Here are a few things I've done (which I understand may not be the best approach but have solved the issue):
- A debounce period that is flagged by the EXTI handler and cleared by a timer after a required period has elapsed
- The EXTI handler does as little logic processing as possible - it simply sets/clears flags
- Another timer is used as a 'heartbeat' signal and circular buffer
The printf statement was removed after all testing/development was finalised. This was a good (but troublesome) learning experience
