From 2e93ba4a2010da9796acfea38544e7384faaf9f7 Mon Sep 17 00:00:00 2001 From: Bart Massey Date: Tue, 19 Nov 2024 10:33:14 -0800 Subject: [PATCH] started on interrupts and debouncing --- mdbook/src/14-interrupts/debouncing.md | 28 +++++++++++++++++++ .../sharing-data-with-globals.md | 11 +++++++- mdbook/src/SUMMARY.md | 4 +-- 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 mdbook/src/14-interrupts/debouncing.md diff --git a/mdbook/src/14-interrupts/debouncing.md b/mdbook/src/14-interrupts/debouncing.md new file mode 100644 index 0000000..b7624d9 --- /dev/null +++ b/mdbook/src/14-interrupts/debouncing.md @@ -0,0 +1,28 @@ +## Debouncing + +As I mentioned in the last section, hardware can be a littleā€¦ special. This is definitely the case +for the buttons on the MB2, and really for almost any pushbutton or switch in almost any system. If +you are seeing several interrupts for a single keypress, it is probably the result of what is known +as switch "bouncing". This is literally what the name implies: as the electrical contacts of the +switch come together, they may bounce apart and then recontact several times rather quickly before +establishing a solid connection. Unfortunately, our microprocessor is *very* fast by mechanical +standards: each one of these bounces makes a new interrupt. + +To "debounce" the switch, you need to *not* process button press interrupts for a short time after +you receive one. 50-100ms is typically a good debounce interval. Debounce timing seems hard: you +definitely don't want to spin in an interrupt handler, and yet it would be hard to deal with this in +the main program. + +The solution comes through another form of hardware concurrency: the `TIMER` peripheral we have used +a bunch already. You can set the timer when a "good" button interrupt is received, and not respond +to further interrupts until the timer peripheral has counted enough time off. The timers in +`nrf-hal` come configured with a 32-bit count value and a "tick rate" of 1 MHz: a million ticks per +second. For a 100ms debounce, just let the timer count off 100,000 ticks. Anytime the button +interrupt handler sees that the timer is running, it can just do nothing. + +The implementation of all this can be seen in the next example (`examples/count-debounce.rs`). When +you run the example you should see one count per button press. + +> **NOTE** The buttons on the MB2 are a little fiddly: it's pretty easy to push one down enough to +feel a "click" but not enough to actually make contact with the switch. I recommend using a +fingernail to press the button when testing. diff --git a/mdbook/src/14-interrupts/sharing-data-with-globals.md b/mdbook/src/14-interrupts/sharing-data-with-globals.md index a4b65be..31c905a 100644 --- a/mdbook/src/14-interrupts/sharing-data-with-globals.md +++ b/mdbook/src/14-interrupts/sharing-data-with-globals.md @@ -1,6 +1,6 @@ ## Sharing Data With Globals -> **NOTE:** This content is partially taken with permission from the blog post +> **NOTE** This content is partially taken with permission from the blog post > *[Interrupts Is Threads]* by James Munns, which contains more discussion about this > topic. @@ -266,6 +266,15 @@ and the rest of the program. Give this example (`examples/count.rs`) a run and note that the count is bumped up 1 on every push of the MB2 A button. +> **NOTE** It is always a good idea to compile examples involving interrupt handling with +> `--release`. Long interrupt handlers can lead to a lot of confusion. + +Really, though, that `rprintln!()` in the interrupt handler is bad practice: while the interrupt +handler is running the printing code, nothing else can move forward. Let's move the reporting to the +main loop, just after the `wfi()` "wait for interrupt". The count will then be reported every time +an interrupt handler finishes (`examples/count-bounce.rs`). Again, the count is bumped up 1 on every +push of the MB2 A button. + Maybe. Especially if your MB2 is old, you may see a single press bump the counter by several. *This is not a software bug.* Mostly. In the next section, I'll talk about what might be going on and how we should deal with it. diff --git a/mdbook/src/SUMMARY.md b/mdbook/src/SUMMARY.md index f72d949..1af9584 100644 --- a/mdbook/src/SUMMARY.md +++ b/mdbook/src/SUMMARY.md @@ -58,8 +58,8 @@ - [The challenge](13-punch-o-meter/the-challenge.md) - [My solution](13-punch-o-meter/my-solution.md) - [Interrupts](14-interrupts/README.md) - - [Sharing data wit globals](14-interrupts/sharing-data-with-globals.md) - - [Debouncing with interrupts](14-interrupts/debouncing-with-interrupts.md) + - [Sharing data with globals](14-interrupts/sharing-data-with-globals.md) + - [Debouncing](14-interrupts/debouncing.md) - [Under the hood](14-interrupts/under-the-hood.md) - [Snake game](14-snake-game/README.md) - [Game logic](14-snake-game/game-logic.md)