Btw henrygab. i did successfully implement the Debounce function above and had it working great. I started having some weirdness when implementing the state machine and transitions, but now i am taking a step back, because we are discussing your other recommendation of not having the IRQ directly connected to button.
We are considering a hybrid approach. (Ian’s idea)
Button triggers IRQ, IRQ starts 1ms timer. The timer uses the debounce algo, and re-enables button IRQ when done.
he already wrote some pseudo-code i am reviewing, but will probably be a bit until i get to it fully.
bool debounce_switch() {
debounce_state_history =
(debounce_state_history << 1) | // make room in the history
!button_get(0) | // one bit, unless button is pressed
DEBOUNCE_STATE_MASK;
return (debounce_state_history == DEBOUNCE_STATE_MASK);
}
// timer callback function for button debouncing
// we're sampling the button pin. we're looking at 7 regions:
// XXXX->T1(H)->XXX->T2(L)->XXXX->T3(H)->XXX
// DEB HIGH DEB LOW DEB HIGH DEB
bool button_timer_callback(struct repeating_timer *t) {
static uint8_t current_state=0;
uint32_t t1,t2,t3;
//this is to demo without wrapping it up too much,
//but the statemachine is probably not needed
// if we use const array to store the states and the time
// const uint8_t t[3];
// const uint8_t states[]={1,0,1,0}; //for debounce switch, or just bool pin_state!=pin_state to flip 1 to 0
//const uint32_t timeouts[3]={MAX_BUTT_TIME,MAX_BETWEEN_BUTT_TIME,MAX_BUTT_TIME};
// ALSO: this is missing the ability to bail if we're happy we already know the press type
// ALSO: t2 is probably not needed, we can bail if we find press or error
switch(current_state){
case 0: //IDLE, debounce
if(debounce_switch(1)){
current_state++;//update debounce to look for 12 x LOW or 12 X HIGH
t1=t2=t3=0;
t1=12; //because we have 12 cycles?
}
break;
case 1: //HIGH, count how many ms
if(debounce_switch(0)){ //count until we debounce low
current_state++; //low, change state
}else{
t1++;
if(t1>MAX_BUTT_TIME) current_state=0; //timeout, button pressed too long. maybe there's something on top of it
}
break;
case 2: //LOW, count how many ms
if(debounce_switch(1)){ //now count wuntil button debounce high again
current_state++;
}else{
t2++;
//NOTE advance to state 4 on timeout
if(t2>MAX_BETWEEN_BUTT_TIME) current_state=4; //timeout, single press, process it
}
break;
case 3: //HIGH, count how many ms
if(debounce_switch(0)){ //now count until button debounce low again
current_state++; //state 4 is done
}else{
t3++;
if(t3>MAX_BUTT_TIME) current_state=0; //timeout, button pressed too long. maybe there's something on top of it
}
break;
}
//ok, now we have our timers
if(current_state==4){ //THIS COULD BE part of the switch, but I think the switch can be rolled into a loop
uint8_t press_type=BP_BUTT_NO_PRESS_MASK; //0b0;
//TODO: use masks for the push types
// none=0b00, short=0b01, long=0b10
if(t1> SHORT_PRESS_MIN && t1<SHORT_PRESS_MAX){ //or <LONG_PRESS_MIN? probaly good to have padding instead
press_type=BP_BUTT_SHORT_PRESS_MASK;
}else if(t1>LONG_PRESS_MIN && t1<LONG_PRESS_MAX){
press_type=BP_BUTT_LONG_PRESS_MASK;
}else{
//error??
}
//press_type = 0bxxxx3311 last four bits encode the press type
if(t3>SHORT_PRESS_MIN && t3<SHORT_PRESS_MAX){
press_type|=(BP_BUTT_SHORT_PRESS_MASK<<2);
}else if(t3>LONG_PRESS_MIN && t3<LONG_PRESS_MAX){
press_type|=(BP_BUTT_LONG_PRESS_MASK<<2);
}else{
//error??
}
current_state=0; //reset state
//disable timer
//set button press flag
//reenable the PIN IRQ
}
}
// example irq callback handler, copy for your own uses
void button_irq_callback(uint gpio, uint32_t events){
gpio_acknowledge_irq(gpio, events);
//disable pin IRQ
gpio_set_irq_enabled(gpio, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
//start 1ms timer
add_repeating_timer_ms(1, button_timer_callback, NULL, &button_timer);
}```
Bit of a mess.