aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarti Bolivar <mbolivar@leaflabs.com>2012-09-03 18:29:45 -0400
committerMarti Bolivar <mbolivar@leaflabs.com>2012-09-03 18:29:45 -0400
commit5a5aee7906b5c11a38d2a71fc2e8849f2afae4bc (patch)
treedfbbf24f499ca6dee1ad40a4639a196d502805c4
parent359117bc2009a9302884f61b0b359bb1723ee0bd (diff)
parent9b8d7c508f9ff0633b5ab8acf9e64bee891604dc (diff)
downloadlibrambutan-5a5aee7906b5c11a38d2a71fc2e8849f2afae4bc.tar.gz
librambutan-5a5aee7906b5c11a38d2a71fc2e8849f2afae4bc.zip
Merge branch 'callback_interrupt_handlers'
-rw-r--r--examples/exti-interrupt-callback.cpp87
-rw-r--r--examples/exti-interrupt.cpp50
-rw-r--r--libmaple/exti.c106
-rw-r--r--libmaple/include/libmaple/exti.h5
-rw-r--r--libmaple/include/libmaple/libmaple_types.h1
-rw-r--r--wirish/ext_interrupts.cpp26
-rw-r--r--wirish/include/wirish/ext_interrupts.h22
7 files changed, 263 insertions, 34 deletions
diff --git a/examples/exti-interrupt-callback.cpp b/examples/exti-interrupt-callback.cpp
new file mode 100644
index 0000000..c87c064
--- /dev/null
+++ b/examples/exti-interrupt-callback.cpp
@@ -0,0 +1,87 @@
+// Toggles the built-in LED when the built in button
+// on the Maple is pushed in. This uses the attachInterrupt function to
+// setup the interrupt handler for the button being pressed.
+//
+// This is similar to the exti-interrupt example, but shows the use of a class
+// method to handle interrupts.
+//
+// More about attachInterrupt:
+// http://leaflabs.com/docs/lang/api/attachinterrupt.html
+//
+
+
+#include <wirish/wirish.h>
+
+class MyAwesomeClass {
+public:
+ // Setup the interrupt handler
+ void initialize() {
+ // LED is off by default
+ this->isLEDOn = false;
+
+ // Attach interrupt to class method handler
+ attachInterrupt(BOARD_BUTTON_PIN, buttonInterruptHandler, this, RISING);
+ }
+
+private:
+
+ bool isLEDOn;
+
+ // Static event handler takes a void * argument that was originally
+ // passed to the attachInterrupt call. If the argument in question is an
+ // instance of the class (MyAwesomeClass in this case), the static function
+ // get access to that instance's data (even private data).
+ //
+ // In other words, this setup allows the Maple to have class method
+ // interrupt handlers (albeit with a work around).
+ //
+ // However, as you might imagine, this argument can be anything (if you
+ // don't need instance data access).
+ //
+ static void buttonInterruptHandler(void *arg) {
+ // Cast the "generic" void argument to the class instance.
+ MyAwesomeClass *instance = (MyAwesomeClass *)arg;
+
+ // Accessing private instance data
+ instance->isLEDOn = !(instance->isLEDOn);
+
+ // Set LED
+ digitalWrite(BOARD_LED_PIN, instance->isLEDOn);
+
+ // Delay slightly for switch de-bouncing
+ delay(20);
+ }
+};
+
+MyAwesomeClass myClass;
+
+// Setup pin modes and the interrupt handler class
+void setup() {
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+ pinMode(BOARD_LED_PIN, OUTPUT);
+
+ // The initialize method sets up the event handler to the private method
+ // in MyAwesomeClass. There is however, nothing stopping you from setting
+ // up event handlers which are public methods in classes.
+ myClass.initialize();
+}
+
+// Loop. Does nothing in this example.
+void loop() {
+
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/exti-interrupt.cpp b/examples/exti-interrupt.cpp
new file mode 100644
index 0000000..89382d7
--- /dev/null
+++ b/examples/exti-interrupt.cpp
@@ -0,0 +1,50 @@
+// Toggles the built-in LED when the built in button
+// on the Maple is pushed in. This uses the attachInterrupt function to
+// setup the interrupt handler for the button being pressed.
+//
+// More about attachInterrupt:
+// http://leaflabs.com/docs/lang/api/attachinterrupt.html
+//
+
+#include <wirish/wirish.h>
+
+// LED is off by default
+bool isLEDOn = false;
+
+// Interrupt handler takes in nothing and returns nothing.
+void interruptHandler() {
+ // Set LED
+ isLEDOn = !isLEDOn;
+ digitalWrite(BOARD_LED_PIN, isLEDOn);
+
+ // Delay slightly for switch debouncing.
+ delay(20);
+}
+
+// Setup pin modes and the interrupt handler
+void setup() {
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+ pinMode(BOARD_LED_PIN, OUTPUT);
+
+ attachInterrupt(BOARD_BUTTON_PIN, interruptHandler, RISING);
+}
+
+// Loop. Does nothing in this example.
+void loop() {
+
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/libmaple/exti.c b/libmaple/exti.c
index 9023782..91d8551 100644
--- a/libmaple/exti.c
+++ b/libmaple/exti.c
@@ -43,27 +43,27 @@ static inline void dispatch_extis(uint32 start, uint32 stop);
*/
typedef struct exti_channel {
- void (*handler)(void);
- uint32 irq_line;
+ void (*handler)(void *);
+ void *arg;
} exti_channel;
static exti_channel exti_channels[] = {
- { .handler = NULL, .irq_line = NVIC_EXTI0 }, // EXTI0
- { .handler = NULL, .irq_line = NVIC_EXTI1 }, // EXTI1
- { .handler = NULL, .irq_line = NVIC_EXTI2 }, // EXTI2
- { .handler = NULL, .irq_line = NVIC_EXTI3 }, // EXTI3
- { .handler = NULL, .irq_line = NVIC_EXTI4 }, // EXTI4
- { .handler = NULL, .irq_line = NVIC_EXTI_9_5 }, // EXTI5
- { .handler = NULL, .irq_line = NVIC_EXTI_9_5 }, // EXTI6
- { .handler = NULL, .irq_line = NVIC_EXTI_9_5 }, // EXTI7
- { .handler = NULL, .irq_line = NVIC_EXTI_9_5 }, // EXTI8
- { .handler = NULL, .irq_line = NVIC_EXTI_9_5 }, // EXTI9
- { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI10
- { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI11
- { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI12
- { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI13
- { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI14
- { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI15
+ { .handler = NULL, .arg = NULL }, // EXTI0
+ { .handler = NULL, .arg = NULL }, // EXTI1
+ { .handler = NULL, .arg = NULL }, // EXTI2
+ { .handler = NULL, .arg = NULL }, // EXTI3
+ { .handler = NULL, .arg = NULL }, // EXTI4
+ { .handler = NULL, .arg = NULL }, // EXTI5
+ { .handler = NULL, .arg = NULL }, // EXTI6
+ { .handler = NULL, .arg = NULL }, // EXTI7
+ { .handler = NULL, .arg = NULL }, // EXTI8
+ { .handler = NULL, .arg = NULL }, // EXTI9
+ { .handler = NULL, .arg = NULL }, // EXTI10
+ { .handler = NULL, .arg = NULL }, // EXTI11
+ { .handler = NULL, .arg = NULL }, // EXTI12
+ { .handler = NULL, .arg = NULL }, // EXTI13
+ { .handler = NULL, .arg = NULL }, // EXTI14
+ { .handler = NULL, .arg = NULL }, // EXTI15
};
/*
@@ -90,10 +90,37 @@ void exti_attach_interrupt(exti_num num,
exti_cfg port,
voidFuncPtr handler,
exti_trigger_mode mode) {
+ // Call callback version with arg being null
+ exti_attach_callback(num, port, (voidArgumentFuncPtr)handler, NULL, mode);
+}
+
+/**
+ * @brief Register a handler with an argument to run upon external interrupt.
+ *
+ * This function assumes that the interrupt request corresponding to
+ * the given external interrupt is masked.
+ *
+ * @param num External interrupt line number.
+ * @param port Port to use as source input for external interrupt.
+ * @param handler Function handler to execute when interrupt is triggered.
+ * @param arg Argument to pass to the interrupt handler.
+ * @param mode Type of transition to trigger on, one of:
+ * EXTI_RISING, EXTI_FALLING, EXTI_RISING_FALLING.
+ * @see exti_num
+ * @see exti_cfg
+ * @see voidFuncPtr
+ * @see exti_trigger_mode
+ */
+void exti_attach_callback(exti_num num,
+ exti_cfg port,
+ voidArgumentFuncPtr handler,
+ void *arg,
+ exti_trigger_mode mode) {
ASSERT(handler);
/* Register the handler */
exti_channels[num].handler = handler;
+ exti_channels[num].arg = arg;
/* Set trigger mode */
switch (mode) {
@@ -116,7 +143,39 @@ void exti_attach_interrupt(exti_num num,
bb_peri_set_bit(&EXTI_BASE->IMR, num, 1);
/* Enable the interrupt line */
- nvic_irq_enable(exti_channels[num].irq_line);
+ switch(num)
+ {
+ case 0:
+ nvic_irq_enable(NVIC_EXTI0);
+ break;
+ case 1:
+ nvic_irq_enable(NVIC_EXTI1);
+ break;
+ case 2:
+ nvic_irq_enable(NVIC_EXTI2);
+ break;
+ case 3:
+ nvic_irq_enable(NVIC_EXTI3);
+ break;
+ case 4:
+ nvic_irq_enable(NVIC_EXTI4);
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ nvic_irq_enable(NVIC_EXTI_9_5);
+ break;
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ nvic_irq_enable(NVIC_EXTI_15_10);
+ break;
+ }
}
/**
@@ -134,6 +193,7 @@ void exti_detach_interrupt(exti_num num) {
/* Finally, unregister the user's handler */
exti_channels[num].handler = NULL;
+ exti_channels[num].arg = NULL;
}
/*
@@ -199,13 +259,13 @@ static __always_inline void clear_pending_msk(uint32 exti_msk) {
/* This dispatch routine is for non-multiplexed EXTI lines only; i.e.,
* it doesn't check EXTI_PR. */
static __always_inline void dispatch_single_exti(uint32 exti) {
- voidFuncPtr handler = exti_channels[exti].handler;
+ voidArgumentFuncPtr handler = exti_channels[exti].handler;
if (!handler) {
return;
}
- handler();
+ handler(exti_channels[exti].arg);
clear_pending_msk(1U << exti);
}
@@ -219,9 +279,9 @@ static __always_inline void dispatch_extis(uint32 start, uint32 stop) {
for (exti = start; exti <= stop; exti++) {
uint32 eb = (1U << exti);
if (pr & eb) {
- voidFuncPtr handler = exti_channels[exti].handler;
+ voidArgumentFuncPtr handler = exti_channels[exti].handler;
if (handler) {
- handler();
+ handler(exti_channels[exti].arg);
handled_msk |= eb;
}
}
diff --git a/libmaple/include/libmaple/exti.h b/libmaple/include/libmaple/exti.h
index 3800b4a..1d201ac 100644
--- a/libmaple/include/libmaple/exti.h
+++ b/libmaple/include/libmaple/exti.h
@@ -115,6 +115,11 @@ void exti_attach_interrupt(exti_num num,
exti_cfg port,
voidFuncPtr handler,
exti_trigger_mode mode);
+void exti_attach_callback(exti_num num,
+ exti_cfg port,
+ voidArgumentFuncPtr handler,
+ void *arg,
+ exti_trigger_mode mode);
void exti_detach_interrupt(exti_num num);
/**
diff --git a/libmaple/include/libmaple/libmaple_types.h b/libmaple/include/libmaple/libmaple_types.h
index 9e1fbb3..60dd2ff 100644
--- a/libmaple/include/libmaple/libmaple_types.h
+++ b/libmaple/include/libmaple/libmaple_types.h
@@ -48,6 +48,7 @@ typedef int int32;
typedef long long int64;
typedef void (*voidFuncPtr)(void);
+typedef void (*voidArgumentFuncPtr)(void *);
#define __io volatile
#define __attr_flash __attribute__((section (".USER_FLASH")))
diff --git a/wirish/ext_interrupts.cpp b/wirish/ext_interrupts.cpp
index a3e61fd..1195ea9 100644
--- a/wirish/ext_interrupts.cpp
+++ b/wirish/ext_interrupts.cpp
@@ -39,13 +39,6 @@
static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode);
-/**
- * @brief Attach an interrupt handler to a pin, triggering on the given mode.
- * @param pin Pin to attach an interrupt handler onto.
- * @param handler Function to call when the external interrupt is triggered.
- * @param mode Trigger mode for the given interrupt.
- * @see ExtIntTriggerMode
- */
void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) {
if (pin >= BOARD_NR_GPIO_PINS || !handler) {
return;
@@ -59,10 +52,21 @@ void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) {
outMode);
}
-/**
- * @brief Disable any external interrupt attached to a pin.
- * @param pin Pin number to detach any interrupt from.
- */
+void attachInterrupt(uint8 pin, voidArgumentFuncPtr handler, void *arg,
+ ExtIntTriggerMode mode) {
+ if (pin >= BOARD_NR_GPIO_PINS || !handler) {
+ return;
+ }
+
+ exti_trigger_mode outMode = exti_out_mode(mode);
+
+ exti_attach_callback((exti_num)(PIN_MAP[pin].gpio_bit),
+ gpio_exti_port(PIN_MAP[pin].gpio_device),
+ handler,
+ arg,
+ outMode);
+}
+
void detachInterrupt(uint8 pin) {
if (pin >= BOARD_NR_GPIO_PINS) {
return;
diff --git a/wirish/include/wirish/ext_interrupts.h b/wirish/include/wirish/ext_interrupts.h
index 933be04..ce1ca03 100644
--- a/wirish/include/wirish/ext_interrupts.h
+++ b/wirish/include/wirish/ext_interrupts.h
@@ -69,6 +69,28 @@ typedef enum ExtIntTriggerMode {
void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode);
/**
+ * @brief Registers an interrupt handler on a pin.
+ *
+ * The interrupt will be triggered on a given transition on the pin,
+ * as specified by the mode parameter. The handler runs in interrupt
+ * context. The new handler will replace whatever handler is
+ * currently registered for the pin, if any.
+ *
+ * @param pin Pin number
+ * @param handler Static class member function to run upon external interrupt
+ * trigger. The handler should take 1 argument and return void
+ * @param arg Argument that the handler will be passed when it's called. One
+ * use of this is to pass the specific instance of the class that
+ * will handle the interrupt.
+ * @param mode Type of transition to trigger on, e.g. falling, rising, etc.
+ *
+ * @sideeffect Registers a handler
+ * @see detachInterrupt()
+ */
+void attachInterrupt(uint8 pin, voidArgumentFuncPtr handler, void *arg,
+ ExtIntTriggerMode mode);
+
+/**
* @brief Disable any registered external interrupt.
* @param pin Maple pin number
* @sideeffect unregisters external interrupt handler