Port ATmega8 assembler code to Arduino

Post here about your Arduino projects, get help - for Adafruit customers!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
annesville
 
Posts: 3
Joined: Mon Mar 26, 2012 5:47 am

Port ATmega8 assembler code to Arduino

Post by annesville »

Hello,

I've been researching various switch debouncing methods... Suggested reading is http://www.ganssle.com/debouncing.htm and http://www.labbookpages.co.uk/electronics/debounce.html

There is a LOT of discussion and thumb-sucking guessing going in many other articles. Nevertheless, the general consensus seems to be that there is not much point in implementing debounce logic in hardware (unless for an interrupt input). All is does is add circuit complexity and cost. It is also less flexible. And of course there is a ready-made debounce library for Arduino: http://arduino.cc/playground/Code/Bounce

Apologies for the ramble, now to the point. I have read an interesting debounce theory from Elio Mazzocca (http://www.edn.com/article/469408-Conta ... rigger.php) but is it written in assembler for the ATmega8, i.e. the same chip used on earlier generation Arduino's. I unfortunately come from a high level programming background, so the best I can do is recognise that the code is indeed assembler! Is there someone here that knows assembler (and preferably Arduino) that can either port the code or at least explain the algorithm clearly? I'd love to see Elio's strategy, if only because he claims it is "The Ultimate Software Debouncer".

Thanks,
Nicolas
Attachments
debounce.txt
Elio's ASM code
(4.04 KiB) Downloaded 267 times

User avatar
westfw
 
Posts: 2010
Joined: Fri Apr 27, 2007 1:01 pm

Re: Port ATmega8 assembler code to Arduino

Post by westfw »

It's a standard digital filter applied to a one-bit input. You can probably find discussions of such algorithms for dealing with analogRead(); it's the same principle on an input value that can only be 0 or 1; you compute its "average" value, and assume the average value is the debounced value, which should be true if you've performed the averaging over a time longer than the switch bounce period.

For a switch read every t seconds, it's going to return a value that is a weighted average of the last N samples.

Code: Select all

 1/4*Sn + (3/4)*(1/4)* Sn-1 + (3/4)^2*(1/4)*(Sn-2) + ... + (3/4)^m*(1/4)*Sn-m
(or something approximately like that) Where S is the pin reading at time N.
If the last several readings from the switch are the same (it's done bouncing), the value of the "function" will tend toward that value.

I guess it's "ultimate" in that the parameters are controllable. Though if you change them too much, the code gets more complicated. It does seem pretty tied to having the switches sample during a conveniently-set timer interrupt, which is not very compatible with an Arduino-based environment. And it's using registers for the running value and the output, which is not very compatible with C. And it adds delay in between switch change and output change, which is less desirable than an "edge based" algorithm. And it's not particularly scalable to large numbers of switches. (If I understand it, "Vertical counters" can do debounce of 8 parallel switches in a similar number of instructions. http://www.dattalo.com/technical/softwa ... rtcnt.html I wonder if the two algorithms can be combined?)

User avatar
annesville
 
Posts: 3
Joined: Mon Mar 26, 2012 5:47 am

Re: Port ATmega8 assembler code to Arduino

Post by annesville »

Thanks westfw.

Thanks for your comments. Elio's algorithm is actually quite simple when you study it properly. It uses an 8-bit value for the pin state to simulate the analog properties of an RC filter, and then a simple software Schmitt trigger to generate the final binary value. The first stage is the "RC filter"

Code: Select all

Y = (1/4 * X) + (3/4 * Yold)
Y is the currently calculated pin state (which is the input value for the Schmitt trigger) and X is the actual raw input pin value. X is set as 0 for a low input and 63 for a high input. This keeps the result Y always below 256. The next stage is the Schmitt trigger which simply compares the valve of Y with a high threshold to set the input flag, and a low threshold to reset the flag. The entire algorithm is run at 4-5ms intervals from a timer interrupt.

I like the stability of this approach, as opposed to the "input hasn't changed for x reads" and "input hasn't changed for x milliseconds" approaches. These two more common approaches are too easily upset by individual transient changes in the input readings which could be due to dirty contacts, etc.

Regarding your concerns for porting to Arduino, the only one that worries me is your comment that timer interrupts are "not very compatible with an Arduino-based environment." I understand that timer interrupts are not native in the Arduino environment, but that doesn't mean they are not supported at all. The microcontroller certainly supports them. There are timer libraries, and for instance this article http://popdevelop.com/2010/04/mastering ... e-arduino/ Would you care to elaborate on your concerns regarding timer interrupts? I'm learning!

User avatar
westfw
 
Posts: 2010
Joined: Fri Apr 27, 2007 1:01 pm

Re: Port ATmega8 assembler code to Arduino

Post by westfw »

I understand that timer interrupts are not native in the Arduino environment, but that doesn't mean they are not supported at all.
The timers on Arduino are 100% in use for the PWM outputs (and for the millis() counter.) Using one of the timers for another purpose interferes with a feature that most arduino users take for granted. Worse, whenever you port the code to an AVR with more timers, they're immediately co-opted to implement additional PWM outputs.
(Hmm. Actually, the 2nd and 3rd timer in Arduino use only the output capture feature to generate PWM. I guess that at least theoretically, you could add an overflow interrupt without interfering with PWM, depending on the timer modes used.)
Now, PWM isn't used by everyone, and numerous libraries do grab one or more timers for their own purposes, so it's not impossible. But I'm pretty comfortable with the phrase "not very compatible with Arduino."

User avatar
annesville
 
Posts: 3
Joined: Mon Mar 26, 2012 5:47 am

Re: Port ATmega8 assembler code to Arduino

Post by annesville »

westfw wrote:Now, PWM isn't used by everyone, and numerous libraries do grab one or more timers for their own purposes, so it's not impossible. But I'm pretty comfortable with the phrase "not very compatible with Arduino."
Thanks. I think your reply about sums up the situation. Using custom timer interrupts interferes with the "out of the box" Arduino functionality, and hence would have to be used with discretion.

Any comments on running the same algorithm without a timer interrupt? Say for instance as a short routine once at the start of every program cycle with a milli check so as not to run the routine too frequently? 1) The "RC filter" properties wouldn't be as precise since your program loop time may vary 2) If your loop cycle time is more than about 2ms (the algorithm calls for a timer interrupt at 4-5ms) you're going to start getting more irregular results 3) You could refresh the algorithm at a couple of strategic points in the loop to reduce the interval, but that will increase the loop cycle time so it is somewhat of a catch 22.

Comments anyone?

User avatar
philba
 
Posts: 387
Joined: Mon Dec 19, 2011 6:59 pm

Re: Port ATmega8 assembler code to Arduino

Post by philba »

Well, I have to disagree about "taking" a timer. There are lots of libraries that do this. Yes, there should be a warning about losing specific PWM outputs but not every sketch needs every PWM output. Timers are a resource to be used. Nothing sacred about the PWM outputs. After all, this is for creating sketches (i.e. applications) not preserving the purity of the Arduino definition.

On the algorithm, I think it's interesting but perhaps a bit too much theory for a fairly simple problem. Switches bounce for some period of time so find a period that is longer than the bouncing and you are good. Personally, I use a very simple algorithm - use a timer tick to sample raw switch state; a single byte represents debounced switch state. On timer tick if raw state is closed, count up, if open, count down. Limit count up to CLOSEDMAX (something small, say 4), limit count down to 0. If switch is at CLOSEDMAX, it's closed, otherwise it's open. Play with timer tick period and CLOSEDMAX to tame the switches you are using. Generally, I use 10 mS and 4 to get get a 40 mS debounce latency max. I haven't found a switch that doesn't behave for this algorithm.

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino”