Pages: [1]   Go Down
Author Topic: hardware debounce filter tutorial  (Read 2333 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 1
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi everyone

I just tested the hardware based debounce filter that is provided by the SAM3X8E. I found out it is quite easy to set up and I thought I would share my results with you. It is usually used to debounce mechanical shutters and things like that.

All you need to activate it, are the following 3 lines of code:
Code:

  // activate input filters
  REG_PIOx_IFER = yourPinMask;
  // choose debounce filter as input filter type
  REG_PIOx_DIFSR = yourPinMask;
  // set clock divider for slow clock -> rejects pulses shorter than (DIV+1)*31µs and accepts pulses longer than 2*(DIV+1)*31µs
  REG_PIOx_SCDR = DIV;
}

replace "yourPinMask" by the bitmask of your input pin, the "x" in REG_PIOx_... by the corresponding PORT of your pin (A,B,C or D to be looked up in the due pinout diagramm http://arduino.cc/forum/index.php/topic,132130.0.html) and the slow clock divider DIV according to the pulse length you'd like to reject. DIV is a 14bit value, allowing for rejection times between 60µs and 500s.

For people who this code looks cryptic to, here an easy example how to use it:
Code:
// input pin to debounce, pin 24 is on PORT A
int pin1 = 24; 
// get bitmask for register manipulation
int mask_1 = digitalPinToBitMask(pin1);

void setup() {
  pinMode(pin1, INPUT);
 
  // activate input filters for pin 24
  REG_PIOA_IFER = mask_1;
  // choose debounce filter as input filter for pin 24
  REG_PIOA_DIFSR = mask_1;
  // set clock divider for slow clock -> rejects pulses shorter than (DIV+1)*31µs and accepts pulses longer than 2*(DIV+1)*31µs
  REG_PIOA_SCDR = 10;
}

void loop() {
 // do whatever you like to ;)
}

This code sets up a debounce filter for pin 24 (on PORT A) with a clock divider of DIV = 10, which means that pulses shorter than 341µs are rejected and pulses longer than 682µs are accepted (inbetween it might or might not be accepted, more or less randomly).


According to the SAM3X8E datasheet, the debounce filter influences the values read by REG_PIOx_PDSR (or digitalRead()) and the input CHANGE interrupt detection. Nothing else.. all peripheral functions (peripheral A or B), if used, are not affected.

Please mind that the activation of the debounce filter adds latencies to your digital input signals on this pin. The delays are on the order of the acceptance time set by DIV, since this is basically the time the SAM needs to check if your pulse exceeds the acceptance time.

I hope this might help someone someday smiley-wink


Logged

Offline Offline
God Member
*****
Karma: 32
Posts: 507
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks, that's really useful. I've had a go at coding it into a function using the g_APinDescription table:
Code:
void setDebounce(int pin, int usecs){  // reject spikes shorter than usecs on pin
  if(usecs){
    g_APinDescription[pin].pPort -> PIO_IFER = g_APinDescription[pin].ulPin;
    g_APinDescription[pin].pPort -> PIO_DIFSR |= g_APinDescription[pin].ulPin;
  }
  else {
    g_APinDescription[pin].pPort -> PIO_IFDR = g_APinDescription[pin].ulPin;
    g_APinDescription[pin].pPort -> PIO_DIFSR &=~ g_APinDescription[pin].ulPin;
    return;
  }


 int div=(usecs/31)-1; if(div<0)div=0; if(div > 16383) div=16383;
 g_APinDescription[pin].pPort -> PIO_SCDR = div;
  
}

void setup() {
  pinMode(2, INPUT_PULLUP);
  pinMode(13,OUTPUT);
  setDebounce(2,200000);
}

void loop() {
  digitalWrite(13,digitalRead(2));
}

Given that the slow clock defaults to an RC oscillator the timings won't be exact unless the crystal oscillator has been enabled.

I think you meant rejection time between 30us and 500ms smiley

« Last Edit: March 26, 2013, 09:21:40 am by stimmer » Logged


nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 129
Posts: 8530
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Working with uS is pretty short, what is the longest time you can set?

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Offline Offline
God Member
*****
Karma: 32
Posts: 507
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Longest would be 500000 us. I imagine most people would either be debouncing switches (about 20000us) or filtering spikes on signals in a 'noisy' circuit (100us or less).
Logged


nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 129
Posts: 8530
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks, that sounds nice. I had to write a custom debounce handler for the LPC, this is a lot simpler so I won't have to port that across; pity it's quite a clever algorithm smiley.

_____
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Offline Offline
Newbie
*
Karma: 1
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks stimmer for correcting my little mistake with ms and s  smiley-red and for coding this nice function.. its very handy to use smiley-wink

As a comment to users of your function I would like to point out that the rejection time is set for the whole port, so if you want to use different rejection times, your pins have to be on different ports.
Logged

White River Junction, Vermont USA
Offline Offline
Full Member
***
Karma: 5
Posts: 106
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Considering the number of push-buttons and encoders that are unceremoniously tacked onto hardware, and the angst that non-debounced inputs can impart on a poor DUE, I humbly suggest that this thread get pinned.

Neat-tricks / feature utilization...
Logged

Offline Offline
God Member
*****
Karma: 32
Posts: 507
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks stimmer for correcting my little mistake with ms and s  smiley-red and for coding this nice function.. its very handy to use smiley-wink

As a comment to users of your function I would like to point out that the rejection time is set for the whole port, so if you want to use different rejection times, your pins have to be on different ports.

Thanks. I've modified the function so now if you use setDebounce(pin,0); to cancel the filter it doesn't affect the timing of the rest of the port.
Logged


Pages: [1]   Go Up
Jump to: