Software Debounce for ADuCM3029

Hello guys , i need your help . I have code of interruptions for ADuCM3029 via GPIO ports. However, the interruptions are not regular. so there is the problem of Software debounce. Is there any code of software debouncing ? 

  • 0
    •  Analog Employees 
    on Jun 12, 2019 11:02 AM over 1 year ago

    Hello,

    I don't think there is any code for debouncing available, but I can suggest two methods to do software debouncing:

    1. This one is easier, but a bit sloppy. If you don't care to know exactly how much time you debounce you can set up an approximately 1 ms time with a variable going up to 26000 in a 'for' loop. That is, in the interrupt routine for the pin do:

    gpio_isr() {
        int i;
    
        for(i = 0; i < 26000; i++);
        read_gpio();
        if(!gpio_still_asserted)
            return;
        do_gpio_interrupt_routine();
    }

    Just do multiples of this number if you need more miliseconds.

    2. If you need a finer control over the debouncing period you have to set up a timer to interrupt at the specific time interval you want to debounce. After that just start the timer in the GPIO ISR and do the second GPIO read and GPIO routine in the timer ISR:

    gpio_isr() {
        start_timer();
    }
    
    timer_isr() {
        read_gpio();
        if(!gpio_still_asserted)
            return;
        do_gpio_interrupt_routine();
    }
    

    I explained the solutions in pseudocode because there are more constraints to take into account to write a complete solution like if you are using the DFP drivers or not, and which timers you have available. Let me know if you need any more help.

    Regards,

    Andrei

  • I tried to implement ur methods in my code but it didn't work . Here's my code i couldn't find how to implement the timer exactly 

    #include <stdio.h>
    #include <stdint.h>
    #include <common.h>
    
    #include <adi_processor.h>
    #include <adi_pwr.h>
    #include <adi_gpio.h>
    #include <ADUCM3029.h>
    
    #define SYSTICK_MAXCOUNT ((1L<<24)-1) /* we use Systick to complete function Delay10uS(). This value only applies to ADICUP3029 board. */
    #define SYSTICK_CLKFREQ   26000000L   /* Systick clock frequency in Hz. This only appies to ADICUP3029 board */
    
    ADI_GPIO_RESULT eGpioResult;
    uint8_t gpioMemory[ADI_GPIO_MEMORY_SIZE] = {0};
    static void pinIntCallbackA(void* pCBParam, uint32_t Port,  void* PinIntData);
    static void pinIntCallbackB(void* pCBParam, uint32_t Port,  void* PinIntData);
    int UrtCfg(int iBaud);
    
    
    
    void AD5940_Delay10us(uint32_t time)
    {
      if(time==0)return;
      if(time*10<SYSTICK_MAXCOUNT/(SYSTICK_CLKFREQ/1000000)){
        SysTick->LOAD = time*10*(SYSTICK_CLKFREQ/1000000);
        SysTick->CTRL = (1 << 2) | (1<<0);    /* Enable SysTick Timer, using core clock */
        while(!((SysTick->CTRL)&(1<<16)));    /* Wait until count to zero */
        SysTick->CTRL = 0;                    /* Disable SysTick Timer */
      }
      else {
        AD5940_Delay10us(time/2);
        AD5940_Delay10us(time/2 + (time&1));
      }
    }
    
    /* GPIO2_03 configured as set out */
    /* GPIO2_04 configured as input */
    /* GPIO2_05 configured as output */
    /* GPIO1_01 configured function 1 button */ 
    /* GPIO1_15 configured function 0 led 1  */
    /* GPIO2_00 configured function 0 led 2  */
    void initplatform()
    {
         eGpioResult= adi_gpio_Init(gpioMemory, ADI_GPIO_MEMORY_SIZE);
         UrtCfg(9600);
         
         /* Step1, enable pull resistors */
         pADI_GPIO0->PE = 0xFFFF;
         pADI_GPIO1->PE = 0xFFFF;
         pADI_GPIO2->PE = 0xFFFF;
        
         /* configure pins */
         pADI_GPIO1->CFG = 1<<2; /* GPIO1_01 to function 1 */
         /*GPIO1_15 & GPIO2_0 by default are 0*/
        
         /* Pin output_input mode enable*/
         pADI_GPIO1->IEN |= 1<<1;  //configure pin 1_01 as input
         pADI_GPIO1->OEN |= 1<<15; //configure pin 1_15 as output
         pADI_GPIO2->OEN |= 1<<0;  //configure pin 2_00 as output
         pADI_GPIO2->OEN |= 1<<3;  //configure pin 2_03 as output
         pADI_GPIO2->IEN |= 1<<4;  //configure pin 2_04 as input
         //pADI_GPIO2->OEN |= 1<<5;  //configure pin 2_05 as output
        
        
         /* activate interruption on pin GPIO1_01 */
         pADI_GPIO1->POL |= 1<<1; //latched passing from rising edge
         pADI_GPIO1->IENA |= 1<<1;
         
         /* activate interruption on pin GPIO2_03 */
         pADI_GPIO2->POL |= 0<<4; //latched passing from falling edge
         pADI_GPIO2->IENB |= 1<<4;
        
         /* initialisation */
         pADI_GPIO1->CLR = 1<<15;  //Clear pin 1_15 initially
         pADI_GPIO2->CLR = 1<<0;   //Clear pin 2_00 initially
         pADI_GPIO2->SET = 1<<3;   //Set pin 2_03 initially
         printf("GPIO1_15:%02x\n",pADI_GPIO1->OUT);
         printf("GPIO2_03:%02x\n",pADI_GPIO2->OUT);
         printf("GPIO2_04:%02x\n",pADI_GPIO2->IN);
         
         
         adi_gpio_RegisterCallback(ADI_GPIO_INTA_IRQ, pinIntCallbackA,NULL);
         adi_gpio_RegisterCallback(ADI_GPIO_INTB_IRQ, pinIntCallbackB,NULL);
    }
    
    int main()
    {
         initplatform();
         while(1)
         {
         }
    }
    
    static void pinIntCallbackA(void* pCBParam, uint32_t Port,  void* PinIntData)
    {
        /* button */
        if((Port == (uint32_t)ADI_GPIO_PORT1) && (*(uint32_t*)PinIntData & ADI_GPIO_PIN_1))
        {
            pADI_GPIO1->TGL = 1<<15;
            pADI_GPIO2->TGL = 1<<0;
            pADI_GPIO1->INT|=1<<1;
        }
    }
    
    static void pinIntCallbackB(void* pCBParam, uint32_t Port,  void* PinIntData)
    {
        /* button */
        if((Port == (uint32_t)ADI_GPIO_PORT2) && (*(uint32_t*)PinIntData & ADI_GPIO_PIN_4))
        {
            pADI_GPIO1->TGL = 1<<15;
            pADI_GPIO2->TGL = 1<<0;
            pADI_GPIO2->INT|=1<<4;
        }
    }
    
    int UrtCfg(int iBaud)
    {
      int iBits = 3;//8bits, 
      int iFormat = 0;//, int iBits, int iFormat
      int i1;
      int iDiv;
      int iRtC;
      int iOSR;
      int iPllMulValue;
      unsigned long long ullRtClk = 16000000;                // The root clock speed
    
    
      /*Setup P0[11:10] as UART pins*/
      pADI_GPIO0->CFG = (1<<22)|(1<<20)|(pADI_GPIO0->CFG&(~((3<<22)|(3<<20))));
    
      iDiv = (pADI_CLKG0_CLK->CTL1& BITM_CLKG_CLK_CTL1_PCLKDIVCNT);                 // Read UART clock as set by CLKCON1[10:8]
      iDiv = iDiv>>8;
      if (iDiv == 0)
        iDiv = 1;
      iRtC = (pADI_CLKG0_CLK->CTL0& BITM_CLKG_CLK_CTL0_CLKMUX); // Check what is the root clock
    
      switch (iRtC)
      {
      case 0:                                               // HFOSC selected
        ullRtClk = 26000000;
        break;
    
      case 1:                                               // HFXTAL selected
        if ((pADI_CLKG0_CLK->CTL0 & 0x200)==0x200)           // 26Mhz XTAL used
            ullRtClk = 26000000;
        else
            ullRtClk = 16000000;                              // Assume 16MHz XTAL
        break;
    
      case 2:                                               // SPLL output
        iPllMulValue = (pADI_CLKG0_CLK->CTL3 &             // Check muliplication factor in PLL settings
                        BITM_CLKG_CLK_CTL3_SPLLNSEL);      // bits[4:0]. Assume div value of 0xD in bits [14:11]
        ullRtClk = (iPllMulValue *1000000);                // Assume straight multiplication by pADI_CLKG0_CLK->CTL3[4:0]
        break;
    
      case 3:
        ullRtClk = 26000000;                                //External clock is assumed to be 26MhZ, if different
        break;                                             //clock speed is used, this should be changed
    
      default:
        break;
      }
      //   iOSR = (pADI_UART0->COMLCR2 & 0x3);
      //   iOSR = 2^(2+iOSR);
      pADI_UART0->COMLCR2 = 0x3;
      iOSR = 32;
      //i1 = (ullRtClk/(iOSR*iDiv))/iBaud;	              // UART baud rate clock source is PCLK divided by OSR
      i1 = (ullRtClk/(iOSR*iDiv))/iBaud-1;   //for bigger M and N value
      pADI_UART0->COMDIV = i1;
    
      pADI_UART0->COMFBR = 0x8800|(((((2048/(iOSR*iDiv))*ullRtClk)/i1)/iBaud)-2048);
      pADI_UART0->COMIEN = 0;
      pADI_UART0->COMLCR = (iFormat&0x3c)|(iBits&3);
    
    
      pADI_UART0->COMFCR = (BITM_UART_COMFCR_RFTRIG & 0x40/*RX_FIFO_4BYTE*/ ) |BITM_UART_COMFCR_FIFOEN;
      pADI_UART0->COMFCR |= BITM_UART_COMFCR_RFCLR|BITM_UART_COMFCR_TFCLR;                                   // Clear the UART FIFOs
      pADI_UART0->COMFCR &= ~(BITM_UART_COMFCR_RFCLR|BITM_UART_COMFCR_TFCLR);                                // Disable clearing mechanism
    
      NVIC_EnableIRQ(UART_EVT_IRQn);              // Enable UART interrupt source in NVIC
      pADI_UART0->COMIEN = BITM_UART_COMIEN_ERBFI|BITM_UART_COMIEN_ELSI; /* Rx Interrupt */
      return pADI_UART0->COMLSR;
    }
    #include "stdio.h"
    #ifdef __ICCARM__
    int putchar(int c)
    #else
    int fputc(int c, FILE *f)
    #endif
    {
      pADI_UART0->COMTX = c;
      while((pADI_UART0->COMLSR&0x20) == 0);// tx fifo empty
      return c;
    }
  • +1
    •  Analog Employees 
    on Jun 13, 2019 7:58 AM over 1 year ago in reply to medksiksi

    Hello,

    I tried implementing the simple version of the debounce on the button. The only thing I have changed is the callback function for the GPIO group A interrupt:

    static void pinIntCallbackA(void* pCBParam, uint32_t Port,  void* PinIntData)
    {
    	volatile int32_t i;
        /* button */
        if((Port == (uint32_t)ADI_GPIO_PORT1) && (*(uint32_t*)PinIntData & ADI_GPIO_PIN_1))
        {
        	for(i = 0; i < (int32_t)(2.7*26000.0); i++);
        	if((*(uint32_t*)PinIntData & ADI_GPIO_PIN_1)) {
    			pADI_GPIO1->TGL |= 1<<15;
    			pADI_GPIO2->TGL |= 1<<0;
    			pADI_GPIO1->INT|=1<<1;
        	}
        }
    }

    The debounce period is just empirical on what seemed to work best for the Release version (-O2 compiler optimisation, without debugging symbols) without connection to the debugger, which seems to be the most unstable. It worked pretty well.

    We have a number of examples on how to configure a timer:

    Let me know if this helps.

    Regards,

    Andrei.

  • Hi Andreid, 

    I tried to connect a 5236WW switch with the adicup3029 via pins 2_03,2_04 and ground . and try to do interupts with latching passing from falling edge (as you can see in the main code ). 

    i try to modify the id pinIntCallbackB function like u did in id pinIntCallbackA but it didn't work. Could you help me with switch interruption and debouncing in the second function ?

  • Here's the main code again with the two functions 

    
    

    #include <stdio.h>
    #include <stdint.h>
    #include <common.h>
    
    #include <adi_processor.h>
    #include <adi_pwr.h>
    #include <adi_gpio.h>
    #include <ADUCM3029.h>
    
    #define SYSTICK_MAXCOUNT ((1L<<24)-1) /* we use Systick to complete function Delay10uS(). This value only applies to ADICUP3029 board. */
    #define SYSTICK_CLKFREQ   26000000L   /* Systick clock frequency in Hz. This only appies to ADICUP3029 board */
    
    ADI_GPIO_RESULT eGpioResult;
    uint8_t gpioMemory[ADI_GPIO_MEMORY_SIZE] = {0};
    static void pinIntCallbackA(void* pCBParam, uint32_t Port,  void* PinIntData);
    static void pinIntCallbackB(void* pCBParam, uint32_t Port,  void* PinIntData);
    int UrtCfg(int iBaud);
    
    
    
    void AD5940_Delay10us(uint32_t time)
    {
      if(time==0)return;
      if(time*10<SYSTICK_MAXCOUNT/(SYSTICK_CLKFREQ/1000000)){
        SysTick->LOAD = time*10*(SYSTICK_CLKFREQ/1000000);
        SysTick->CTRL = (1 << 2) | (1<<0);    /* Enable SysTick Timer, using core clock */
        while(!((SysTick->CTRL)&(1<<16)));    /* Wait until count to zero */
        SysTick->CTRL = 0;                    /* Disable SysTick Timer */
      }
      else {
        AD5940_Delay10us(time/2);
        AD5940_Delay10us(time/2 + (time&1));
      }
    }
    
    /* GPIO2_03 configured as set out */
    /* GPIO2_04 configured as input */
    /* GPIO2_05 configured as output */
    /* GPIO1_01 configured function 1 button */ 
    /* GPIO1_15 configured function 0 led 1  */
    /* GPIO2_00 configured function 0 led 2  */
    void initplatform()
    {
         eGpioResult= adi_gpio_Init(gpioMemory, ADI_GPIO_MEMORY_SIZE);
         UrtCfg(9600);
         
         /* Step1, enable pull resistors */
         pADI_GPIO0->PE = 0xFFFF;
         pADI_GPIO1->PE = 0xFFFF;
         pADI_GPIO2->PE = 0xFFFF;
        
         /* configure pins */
         pADI_GPIO1->CFG = 1<<2; /* GPIO1_01 to function 1 */
         /*GPIO1_15 & GPIO2_0 by default are 0*/
        
         /* Pin output_input mode enable*/
         pADI_GPIO1->IEN |= 1<<1;  //configure pin 1_01 as input
         pADI_GPIO1->OEN |= 1<<15; //configure pin 1_15 as output
         pADI_GPIO2->OEN |= 1<<0;  //configure pin 2_00 as output
         pADI_GPIO2->OEN |= 1<<3;  //configure pin 2_03 as output
         pADI_GPIO2->IEN |= 1<<4;  //configure pin 2_04 as input
         //pADI_GPIO2->OEN |= 1<<5;  //configure pin 2_05 as output
        
        
         /* activate interruption on pin GPIO1_01 */
         pADI_GPIO1->POL |= 1<<1; //latched passing from rising edge
         pADI_GPIO1->IENA |= 1<<1;
         
         /* activate interruption on pin GPIO2_03 */
         pADI_GPIO2->POL |= 0<<4; //latched passing from falling edge
         pADI_GPIO2->IENB |= 1<<4;
        
         /* initialisation */
         pADI_GPIO1->CLR = 1<<15;  //Clear pin 1_15 initially
         pADI_GPIO2->CLR = 1<<0;   //Clear pin 2_00 initially
         pADI_GPIO2->SET = 1<<3;   //Set pin 2_03 initially
         printf("GPIO1_15:%02x\n",pADI_GPIO1->OUT);
         printf("GPIO2_03:%02x\n",pADI_GPIO2->OUT);
         printf("GPIO2_04:%02x\n",pADI_GPIO2->IN);
         
         
         adi_gpio_RegisterCallback(ADI_GPIO_INTA_IRQ, pinIntCallbackA,NULL);
         adi_gpio_RegisterCallback(ADI_GPIO_INTB_IRQ, pinIntCallbackB,NULL);
    }
    
    int main()
    {
         initplatform();
         while(1)
         {
         }
    }
    
    static void pinIntCallbackA(void* pCBParam, uint32_t Port,  void* PinIntData)
    {
        /* button */
        if((Port == (uint32_t)ADI_GPIO_PORT1) && (*(uint32_t*)PinIntData & ADI_GPIO_PIN_1))
        {
            pADI_GPIO1->TGL = 1<<15;
            pADI_GPIO2->TGL = 1<<0;
            pADI_GPIO1->INT|=1<<1;
        }
    }
    
    static void pinIntCallbackB(void* pCBParam, uint32_t Port,  void* PinIntData)
    {
        /* button */
        if((Port == (uint32_t)ADI_GPIO_PORT2) && (*(uint32_t*)PinIntData & ADI_GPIO_PIN_4))
        {
            pADI_GPIO1->TGL = 1<<15;
            pADI_GPIO2->TGL = 1<<0;
            pADI_GPIO2->INT|=1<<4;
        }
    }
    
    int UrtCfg(int iBaud)
    {
      int iBits = 3;//8bits, 
      int iFormat = 0;//, int iBits, int iFormat
      int i1;
      int iDiv;
      int iRtC;
      int iOSR;
      int iPllMulValue;
      unsigned long long ullRtClk = 16000000;                // The root clock speed
    
    
      /*Setup P0[11:10] as UART pins*/
      pADI_GPIO0->CFG = (1<<22)|(1<<20)|(pADI_GPIO0->CFG&(~((3<<22)|(3<<20))));
    
      iDiv = (pADI_CLKG0_CLK->CTL1& BITM_CLKG_CLK_CTL1_PCLKDIVCNT);                 // Read UART clock as set by CLKCON1[10:8]
      iDiv = iDiv>>8;
      if (iDiv == 0)
        iDiv = 1;
      iRtC = (pADI_CLKG0_CLK->CTL0& BITM_CLKG_CLK_CTL0_CLKMUX); // Check what is the root clock
    
      switch (iRtC)
      {
      case 0:                                               // HFOSC selected
        ullRtClk = 26000000;
        break;
    
      case 1:                                               // HFXTAL selected
        if ((pADI_CLKG0_CLK->CTL0 & 0x200)==0x200)           // 26Mhz XTAL used
            ullRtClk = 26000000;
        else
            ullRtClk = 16000000;                              // Assume 16MHz XTAL
        break;
    
      case 2:                                               // SPLL output
        iPllMulValue = (pADI_CLKG0_CLK->CTL3 &             // Check muliplication factor in PLL settings
                        BITM_CLKG_CLK_CTL3_SPLLNSEL);      // bits[4:0]. Assume div value of 0xD in bits [14:11]
        ullRtClk = (iPllMulValue *1000000);                // Assume straight multiplication by pADI_CLKG0_CLK->CTL3[4:0]
        break;
    
      case 3:
        ullRtClk = 26000000;                                //External clock is assumed to be 26MhZ, if different
        break;                                             //clock speed is used, this should be changed
    
      default:
        break;
      }
      //   iOSR = (pADI_UART0->COMLCR2 & 0x3);
      //   iOSR = 2^(2+iOSR);
      pADI_UART0->COMLCR2 = 0x3;
      iOSR = 32;
      //i1 = (ullRtClk/(iOSR*iDiv))/iBaud;	              // UART baud rate clock source is PCLK divided by OSR
      i1 = (ullRtClk/(iOSR*iDiv))/iBaud-1;   //for bigger M and N value
      pADI_UART0->COMDIV = i1;
    
      pADI_UART0->COMFBR = 0x8800|(((((2048/(iOSR*iDiv))*ullRtClk)/i1)/iBaud)-2048);
      pADI_UART0->COMIEN = 0;
      pADI_UART0->COMLCR = (iFormat&0x3c)|(iBits&3);
    
    
      pADI_UART0->COMFCR = (BITM_UART_COMFCR_RFTRIG & 0x40/*RX_FIFO_4BYTE*/ ) |BITM_UART_COMFCR_FIFOEN;
      pADI_UART0->COMFCR |= BITM_UART_COMFCR_RFCLR|BITM_UART_COMFCR_TFCLR;                                   // Clear the UART FIFOs
      pADI_UART0->COMFCR &= ~(BITM_UART_COMFCR_RFCLR|BITM_UART_COMFCR_TFCLR);                                // Disable clearing mechanism
    
      NVIC_EnableIRQ(UART_EVT_IRQn);              // Enable UART interrupt source in NVIC
      pADI_UART0->COMIEN = BITM_UART_COMIEN_ERBFI|BITM_UART_COMIEN_ELSI; /* Rx Interrupt */
      return pADI_UART0->COMLSR;
    }
    #include "stdio.h"
    #ifdef __ICCARM__
    int putchar(int c)
    #else
    int fputc(int c, FILE *f)
    #endif
    {
      pADI_UART0->COMTX = c;
      while((pADI_UART0->COMLSR&0x20) == 0);// tx fifo empty
      return c;
    }