-
Notifications
You must be signed in to change notification settings - Fork 508
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
A set of examples that demonstrate basic use of timers, interrupts, and tasks. Based on and tested on the nRF52840, but also compiles on the nRF52832 -- although you'll need an external button there.
- Loading branch information
1 parent
290b3b7
commit 63b43fc
Showing
8 changed files
with
644 additions
and
0 deletions.
There are no files selected for viewing
60 changes: 60 additions & 0 deletions
60
libraries/Bluefruit52Lib/examples/LowPower/Blink2_loopless/Blink2_loopless.ino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* | ||
Blink_loopless | ||
Created 2019-05-03 | ||
by Pol Van Aubel | ||
Turns on an LED on for one second, then off for one second, repeatedly. | ||
This example is based on the original Blink sketch. The Adafruit nRF52* boards | ||
are more advanced than "normal" Arduinos, however, and come with freeRTOS | ||
and proper task management. This blink sketch demonstrates the use of two | ||
SoftwareTimers to perform two repetitive delayed tasks at different frequencies | ||
without using the energy that a continuously running loop() function has. | ||
AdaFruit's nRF-boards have multiple on-board LEDs you can control. These are | ||
addressable using the LED_RED, LED_BLUE, LED_BUILTIN and LED_CONN definitions. | ||
These take care to use the correct LED pin regardless of which board is used. | ||
If you want to know what pin the on-board LED is connected to on your model, | ||
check the Technical Specs of your board on https://www.adafruit.com/ or the | ||
board's variant.h at | ||
https://github.com/adafruit/Adafruit_nRF52_Arduino/tree/master/variants | ||
Based on the original Blink, the code of which is in the public domain. | ||
*/ | ||
|
||
#include <Arduino.h> | ||
|
||
// Create the two SoftwareTimers we're going to use. | ||
SoftwareTimer bluetimer, redtimer; | ||
|
||
void setup() | ||
{ | ||
// LED_RED & LED_BLUE are already initialized as outputs. | ||
|
||
// Initialize the timers at .75 seconds for blue, and 1 second for red. | ||
bluetimer.begin(750, bluetoggle); | ||
redtimer.begin(1000, redtoggle); | ||
bluetimer.start(); | ||
redtimer.start(); | ||
suspendLoop(); | ||
} | ||
|
||
void loop(void) { } | ||
|
||
/** | ||
* Toggle led1 every 1 second | ||
*/ | ||
void redtoggle(TimerHandle_t _handle) | ||
{ | ||
digitalToggle(LED_RED); // Toggle LED | ||
} | ||
|
||
/** | ||
* Toggle led1 every 0.5 second | ||
*/ | ||
void bluetoggle(TimerHandle_t _handle) | ||
{ | ||
digitalToggle(LED_BLUE); // Toggle LED | ||
} |
50 changes: 50 additions & 0 deletions
50
libraries/Bluefruit52Lib/examples/LowPower/Blink_loopless/Blink_loopless.ino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* | ||
Blink_loopless | ||
Created 2019-05-03 | ||
by Pol Van Aubel | ||
Turns on an LED on for one second, then off for one second, repeatedly. | ||
This example is based on the original Blink sketch. The Adafruit nRF52* boards | ||
are more advanced than "normal" Arduinos, however, and come with freeRTOS | ||
and proper task management. This blink sketch demonstrates the use of | ||
SoftwareTimer to perform a repetitive delayed task without using the energy | ||
that a continuously running loop() function has. | ||
AdaFruit's nRF-boards have multiple on-board LEDs you can control. These are | ||
addressable using the LED_RED, LED_BLUE, LED_BUILTIN and LED_CONN definitions. | ||
These take care to use the correct LED pin regardless of which board is used. | ||
If you want to know what pin the on-board LED is connected to on your model, | ||
check the Technical Specs of your board on https://www.adafruit.com/ or the | ||
board's variant.h at | ||
https://github.com/adafruit/Adafruit_nRF52_Arduino/tree/master/variants | ||
Based on the original Blink, the code of which is in the public domain. | ||
*/ | ||
|
||
// Create a SoftwareTimer that will drive our LED. | ||
SoftwareTimer led_timer; | ||
|
||
// the setup function runs once when you press reset or power the board | ||
void setup(void) { | ||
// initialize digital pin LED_BUILTIN as an output. | ||
pinMode(LED_RED, OUTPUT); | ||
|
||
// Set up a repeating timer that fires every half second (500ms) to toggle the LED. | ||
led_timer.begin(500, timer_callback); | ||
led_timer.start(); | ||
|
||
// Since loop() is empty, suspend its task so that the system never runs it | ||
// and can go to sleep properly. | ||
suspendLoop(); | ||
} | ||
|
||
void timer_callback(TimerHandle_t _handle) { | ||
digitalToggle(LED_RED); // toggle the red LED | ||
} | ||
|
||
// the loop function is empty and should never run. | ||
void loop(void) { } |
67 changes: 67 additions & 0 deletions
67
libraries/Bluefruit52Lib/examples/LowPower/Button_interrupt/Button_interrupt.ino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/* | ||
Button_interrupt | ||
Created 2019-05-04 | ||
by Pol Van Aubel | ||
Uses an interrupt to listen for a button input. On the nRF52840, it can listen | ||
on pin 7 to the UserSW. On other boards, an external switch needs to be provided. | ||
The Adafruit nRF52* boards are more advanced than "normal" Arduinos and come | ||
with freeRTOS, interrupts available on every pin, and proper task management. | ||
This button sketch demonstrates the use of interrupts to act on an input such | ||
as a switch, without having to poll it in a continuously scanning loop() function. | ||
Even though human button presses are slow, and therefore unlikely to be missed | ||
using a scanning loop, the interrupt technique allows the board to go into sleep | ||
mode while waiting for an input, thereby saving a lot of energy. | ||
AdaFruit's nRF-boards have multiple on-board LEDs you can control. These are | ||
addressable using the LED_RED, LED_BLUE, LED_BUILTIN and LED_CONN definitions. | ||
These take care to use the correct LED pin regardless of which board is used. | ||
If you want to know what pin the on-board LED is connected to on your model, | ||
check the Technical Specs of your board on https://www.adafruit.com/ or the | ||
board's variant.h at | ||
https://github.com/adafruit/Adafruit_nRF52_Arduino/tree/master/variants | ||
This code is licensed under CC0, effectively putting it in the Public Domain | ||
where possible. | ||
*/ | ||
|
||
// On the nRF52840, pin 7 is the UserSW/DFU switch. | ||
int interruptPin = 7; | ||
|
||
// the setup function runs once when you press reset or power the board | ||
void setup(void) { | ||
pinMode(LED_RED, OUTPUT); | ||
pinMode(interruptPin, INPUT_PULLUP); // Configure the switch pin as an input with internal pull-up register enabled. | ||
|
||
// Configure it to call switch_callback if the switch pin transitions from HIGH to LOW, i.e. when it is pressed. | ||
// On the nRF52840, RISING and CHANGE are also valid options. Depending on your platform, LOW may also be available. | ||
attachInterrupt(interruptPin, switch_callback, FALLING); | ||
|
||
// Since loop() is empty, suspend its task so that the system never runs it | ||
// and can go to sleep properly. | ||
suspendLoop(); | ||
} | ||
|
||
// the loop function is empty and should never run. | ||
void loop(void) { } | ||
|
||
// The switch_callback function is the function we attached to the interrupt on line 42. | ||
// This is known as an Interrupt Service Routine, or ISR. | ||
// It gets run every time the interrupt fires, in the interrupt context. Nothing else | ||
// happens while this is running. Therefore, it should be fast and simple. | ||
// In particular, it should never block, nor do Serial communication or use the Bluefruit API. | ||
// There are a few freeRTOS functions specifically designed to be run from an ISR. | ||
// If you need a longer ISR, other examples show how to do this. | ||
void switch_callback(void) { | ||
digitalToggle(LED_RED); // toggle the red LED | ||
|
||
// You may notice that the LED does not reliably turn on on one press of the switch, | ||
// then off on the next. This is likely due to a phenomenon physical switches exhibit called "bounce". | ||
// Effectively this means that the pin goes through multiple transitions of HIGH to LOW, | ||
// back to HIGH, to LOW again, for a single press of the button. | ||
// Some debouncing techniques using interrupts are shown in another example. | ||
} |
104 changes: 104 additions & 0 deletions
104
...it52Lib/examples/LowPower/Button_interrupt_ada_callback/Button_interrupt_ada_callback.ino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
/* | ||
Button_interrupt_ada_callback | ||
Created 2019-05-04 | ||
by Pol Van Aubel | ||
Uses an interrupt to listen for a button input. On the nRF52840, it can listen | ||
on pin 7 to the UserSW. On other boards, an external switch needs to be provided. | ||
The Adafruit nRF52* boards are more advanced than "normal" Arduinos and come | ||
with freeRTOS, interrupts available on every pin, and proper task management. | ||
This button sketch demonstrates the use of interrupts to act on an input such | ||
as a switch, without having to poll it in a continuously scanning loop() function. | ||
Even though human button presses are slow, and therefore unlikely to be missed | ||
using a scanning loop, the interrupt technique allows the board to go into sleep | ||
mode while waiting for an input, thereby saving a lot of energy. | ||
However, because interrupts need to be fast, you must not do Serial communication | ||
or long tasks directly in an ISR. This is where deferred ISRs come in. However, | ||
deferred ISRs cannot have a single time-critical component. By using | ||
ada_callback_fromISR, you can run a fast time-critical component in a normal | ||
ISR, and then queue up a callback to process the rest. | ||
AdaFruit's nRF-boards have multiple on-board LEDs you can control. These are | ||
addressable using the LED_RED, LED_BLUE, LED_BUILTIN and LED_CONN definitions. | ||
These take care to use the correct LED pin regardless of which board is used. | ||
If you want to know what pin the on-board LED is connected to on your model, | ||
check the Technical Specs of your board on https://www.adafruit.com/ or the | ||
board's variant.h at | ||
https://github.com/adafruit/Adafruit_nRF52_Arduino/tree/master/variants | ||
This code is licensed under CC0, effectively putting it in the Public Domain | ||
where possible. | ||
*/ | ||
|
||
// On the nRF52840, pin 7 is the UserSW/DFU switch. | ||
int interruptPin = 7; | ||
|
||
// Because this variable is modified inside a non-deferred ISR, and used outside it, | ||
// it must be declared volatile to ensure that the most recently written value is | ||
// always used. | ||
volatile int numinterrupts; | ||
|
||
// the setup function runs once when you press reset or power the board | ||
void setup(void) { | ||
Serial.begin(115200); // Not required on the nRF52840 with native USB. | ||
|
||
while (!Serial) { // Stalls the nRF52840 until the USB serial console has been opened on the host PC. | ||
delay(10); | ||
} | ||
Serial.println("Press the button!"); | ||
Serial.flush(); // Because this sketch does nothing else, it will go to sleep rather than send the | ||
// entire Serial buffer to the host PC. So, use Serial.flush() to make sure it does that | ||
// before allowing it to sleep. | ||
|
||
pinMode(LED_RED, OUTPUT); | ||
pinMode(interruptPin, INPUT_PULLUP); // Configure the switch pin as an input with internal pull-up register enabled. | ||
|
||
// Configure it to call switch_callback if the switch pin transitions from HIGH to LOW, i.e. when it is pressed. | ||
// On the nRF52840, RISING and CHANGE are also valid options. Depending on your platform, LOW may also be available. | ||
attachInterrupt(interruptPin, switch_isr, FALLING); | ||
|
||
// Since loop() is empty, suspend its task so that the system never runs it | ||
// and can go to sleep properly. | ||
suspendLoop(); | ||
} | ||
|
||
// the loop function is empty and should never run. | ||
void loop(void) { } | ||
|
||
// The switch_isr function is the function we attached to the interrupt on line 63. | ||
// This is known as an Interrupt Service Routine, or ISR. | ||
// It gets run every time the interrupt fires, in the interrupt context. Nothing else | ||
// happens while this is running. Therefore, it should be fast and simple. | ||
// In particular, it should never block, nor do Serial communication or use the Bluefruit API. | ||
// There are a few freeRTOS functions specifically designed to be run from an ISR. | ||
void switch_isr(void) { | ||
// Do short time-critical processing (setting flags, queueing up tasks, etc) here. | ||
digitalToggle(LED_RED); | ||
|
||
++numinterrupts; | ||
ada_callback_fromISR(NULL, 0, switch_isr_callback); // Queue up a task with no extra variables and no arguments. | ||
// Every single interrupt is serviced, because internally, a | ||
// queue is used. | ||
} | ||
|
||
|
||
// The switch_isr_callback function is the function we set up as the ada_callback on line 84. | ||
// It gets run once for every interrupt that switch_isr ran for, but with no guarantees about | ||
// when that happens. However, the advantage is you have the full range of Serial, Bluefruit, | ||
// and freeRTOS API to use now. | ||
// Bear in mind, however, that if this function takes longer to run than the average time between | ||
// interrupts, at some point your ada_callback_queue will overflow. For that scenario, consider | ||
// batch-processing interrupts by using direct-to-task notifications. | ||
void switch_isr_callback(void) { | ||
Serial.println("Interrupt serviced!"); | ||
Serial.print("The number of interrupts received at this point was "); | ||
Serial.println(numinterrupts); | ||
Serial.flush(); // Because this sketch does nothing else, it will go to sleep rather than send the | ||
// entire Serial buffer to the host PC. However, here, Serial.flush() doesn't seem | ||
// to work either. Maybe something to do with the task context? | ||
} |
83 changes: 83 additions & 0 deletions
83
.../Bluefruit52Lib/examples/LowPower/Button_interrupt_deferred/Button_interrupt_deferred.ino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/* | ||
Button_interrupt_deferred | ||
Created 2019-05-04 | ||
by Pol Van Aubel | ||
Uses an interrupt to listen for a button input. On the nRF52840, it can listen | ||
on pin 7 to the UserSW. On other boards, an external switch needs to be provided. | ||
The Adafruit nRF52* boards are more advanced than "normal" Arduinos and come | ||
with freeRTOS, interrupts available on every pin, and proper task management. | ||
This button sketch demonstrates the use of interrupts to act on an input such | ||
as a switch, without having to poll it in a continuously scanning loop() function. | ||
Even though human button presses are slow, and therefore unlikely to be missed | ||
using a scanning loop, the interrupt technique allows the board to go into sleep | ||
mode while waiting for an input, thereby saving a lot of energy. | ||
However, because interrupts need to be fast, you must not do Serial communication | ||
or long tasks directly in an ISR. This is where deferred ISRs come in. | ||
AdaFruit's nRF-boards have multiple on-board LEDs you can control. These are | ||
addressable using the LED_RED, LED_BLUE, LED_BUILTIN and LED_CONN definitions. | ||
These take care to use the correct LED pin regardless of which board is used. | ||
If you want to know what pin the on-board LED is connected to on your model, | ||
check the Technical Specs of your board on https://www.adafruit.com/ or the | ||
board's variant.h at | ||
https://github.com/adafruit/Adafruit_nRF52_Arduino/tree/master/variants | ||
This code is licensed under CC0, effectively putting it in the Public Domain | ||
where possible. | ||
*/ | ||
|
||
// On the nRF52840, pin 7 is the UserSW/DFU switch. | ||
int interruptPin = 7; | ||
|
||
// the setup function runs once when you press reset or power the board | ||
void setup(void) { | ||
Serial.begin(115200); // Not required on the nRF52840 with native USB. | ||
|
||
while (!Serial) { // Stalls the nRF52840 until the USB serial console has been opened on the host PC. | ||
delay(10); | ||
} | ||
Serial.println("Press the button!"); | ||
|
||
pinMode(LED_RED, OUTPUT); | ||
pinMode(interruptPin, INPUT_PULLUP); // Configure the switch pin as an input with internal pull-up register enabled. | ||
|
||
// Configure it to call switch_callback if the switch pin transitions from HIGH to LOW, i.e. when it is pressed. | ||
// On the nRF52840, RISING and CHANGE are also valid options. Depending on your platform, LOW may also be available. | ||
// The ISR_DEFERRED flag ensures that the interrupt is serviced by a scheduled operating system task. | ||
// What this means is that the ISR is allowed to perform slow functionality, including Serial communication, | ||
// using the Bluefruit API, and the entire freeRTOS API rather than just the *FromISR functions. | ||
// Use this if your interrupt servicing is not time-critical. | ||
attachInterrupt(interruptPin, switch_deferred, ISR_DEFERRED | FALLING); | ||
|
||
// Since loop() is empty, suspend its task so that the system never runs it | ||
// and can go to sleep properly. | ||
suspendLoop(); | ||
} | ||
|
||
// the loop function is empty and should never run. | ||
void loop(void) { } | ||
|
||
// The switch_deferred function is the function we attached to the interrupt on line 56. | ||
// This is known as an Interrupt Service Routine, or ISR. | ||
// Because it is a deferred ISR, it is not guaranteed to run immediately after the interrupt | ||
// happens. However, the advantage is you have the full range of Serial, Bluefruit, | ||
// and freeRTOS API to use now. | ||
void switch_deferred(void) { | ||
digitalToggle(LED_RED); | ||
Serial.println("Interrupt serviced!"); | ||
Serial.flush(); // Because this sketch does nothing else, it will go to sleep rather than send the | ||
// entire Serial buffer to the host PC. So, use Serial.flush() to make sure it does that | ||
// before allowing it to sleep. | ||
|
||
// You may notice that you receive multiple messages per press of the switch, | ||
// This is likely due to a phenomenon physical switches exhibit called "bounce". | ||
// Effectively this means that the pin goes through multiple transitions of HIGH to LOW, | ||
// back to HIGH, to LOW again, for a single press of the button. | ||
// Some debouncing techniques using interrupts are shown in another example. | ||
} |
Oops, something went wrong.