X Timer EPIT - 2 keys to eliminate chattering

Posted by atdawgie on Thu, 13 Jan 2022 09:17:32 +0100

In the chapter on interrupts, we left a BUG: the interrupt service function should be fast in and fast out, and the use of timing functions is strictly prohibited in the middle, which will seriously waste CPU performance and can't do anything in delay. The mechanical key really needs to consider the effect of chattering elimination, so the timer is used to realize the function.  

Timer chattering elimination principle

The principle of key chattering elimination is a lot of search on the Internet. I won't say it here. In short, it doesn't respond when you press the button. Go to confirm the value of the key later. This "after a while" is refreshed through delay, so during the delay, the CPU is blocked and can't do anything. If you use a timer instead, you can set the timing and trigger the interrupt when the time comes. Then CPU resources are not required during the timer timing period. You only need to wait until the time comes to trigger the interrupt event.

 

Using the legend in the tutorial, the above level is similar to the level change effect of key jitter. We can define that the EPIT timer is started when the falling edge of the key is pressed. For example, t1 starts the timing of 10ms, but before 10ms, t2 resets the timer, while t3 resets the timer. There is no new falling edge reset timer after 10ms, Just trigger the timed interrupt and respond to the function we want to achieve in this interrupt event.

Process of using EPIT to eliminate key chattering

According to the anti chattering principle mentioned above, the whole process should be as follows:

  1. Initialization key interrupt and EPIT timer (EPIT only initializes and does not start)
  2. Press the key to trigger the key interrupt
  3. Press the key to interrupt the service, start the EPIT timer and clear the interrupt flag bit
  4. When the timer does not arrive, the key jitters and triggers the interrupt again, causing the timer to time again
  5. When the timer expires, EPIT timing interrupt is triggered to clear the interrupt flag bit
  6. The EPIT interrupt service function is called. It should be noted that the function that we need to respond to the key press function should be the corresponding EPIT interrupt service function. The key interrupt only causes the EPIT timer to start.

Code composition

This code has no details to say. It mainly starts another interrupt through one interrupt. And only one timing cycle is executed in the timing interrupt.

#include "bsp_keyfilter.h"
#include "bsp_int.h"
#include "bsp_beep.h"

/*
* @description            :   Key initialization with anti chattering
* @param                  :   None
* @return                 :   None
*/
void keyfilter_init(void)
{
    gpio_pin_config_t key_config;

    IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0);          //GPIO Reuse initialization
    IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0xF080);  //GPIO Electrical initialization

    key_config.direction = kGPIO_DigitalInput;                  //GPIO Set as input direction
    key_config.interruptMode = kGPIO_IntFallingEdge;            //GPIO The interrupt signal is triggered by the falling edge

    gpio_init(GPIO1,18,&key_config);                            //GPIO initialization

    GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);                   //GIC Enable GPIO1 interrupt
    system_register_irqHandler(GPIO1_Combined_16_31_IRQn,
                               gpio1_16_31_irqhandler,
                               NULL);                           //Register interrupt function
    
    gpio_intenable(GPIO1,18);                                   //GPIO Interrupt enable

    // filtertimer_init(66000000/100);                             //Key debounce timer initialization
    filtertimer_init();
}   


/*
* @description            :   Key debounce timer initialization
* @param-value            :   EPIT_LR Register set value
* @return                 :   None
*/
void filtertimer_init(void)
{
    EPIT1->CR = 0;                                              //eliminate EPIT1_CR
    EPIT1->CR |= (1<<1) |(1<<2) |(1<<3) |(1<<24);               //set up EPIT1_CR
    EPIT1->LR = 0;                                              //set up EPIT1_LR 
    EPIT1->CMPR = 0;                                            //set up EPIT1_CMPR

    GIC_EnableIRQ(EPIT1_IRQn);                                  //GIC Enable EPIT1

    system_register_irqHandler(EPIT1_IRQn,
                               filter_irqhandler,
                               NULL);                           //EPIT1 Interrupt service function registration
}


/*
* @description            :   GPIO1_IO16~31 Corresponding interrupt service
* @param                  :   None
* @return                 :   None
*/
void gpio1_16_31_irqhandler(int gicciar,void *param)
{
    /*Turn on the timer*/
    filtertimer_restart(66000000/100);                          //restart EPIT Timer, timing 10 ms
    gpio_clearIntFlags(GPIO1,18);                               //eliminate gpio Interrupt flag bit

}

/*
* @description            :   EPIT1 Timing stop
* @param                  :   None
* @return                 :   None
*/
void filtertimer_stop(void)
{
    EPIT1->CR &= ~(1<<0);
}

/*
* @description            :   EPIT1 Timed function restart
* @param-value            :   LR The value of the register
* @return                 :   None
*/
void filtertimer_restart(unsigned int value)
{
    EPIT1->CR &= ~(1<<0);
    EPIT1->LR = value;
    EPIT1->CR |= 1<<0;
}

/*
* @description            :   EPIT1 Interrupt service function
* @param                  :   None
* @return                 :   None
*/
void filter_irqhandler(int gicciar,void *param)
{
    static unsigned char state = OFF;
    
    if(EPIT1->SR &= (1<<0)) //EPIT timing 10msreach
    {   
        filtertimer_stop();
        if(gpio_pinread(GPIO1,18) == 0)
        {
            state = !state;
            beep_switch(state);
        }
    }
    EPIT1->SR |= (1<<0);        //eliminate EPIT1_SR Flag bit
}

In addition to the final function of controlling the buzzer, the remarks of the whole process are very clear. In main C can be directly referenced.

keyfilter_init();    //Use the key to eliminate chattering through interruption