diff options
Diffstat (limited to 'stmhal/extint.c')
-rw-r--r-- | stmhal/extint.c | 145 |
1 files changed, 84 insertions, 61 deletions
diff --git a/stmhal/extint.c b/stmhal/extint.c index 289a519762..61469e0a17 100644 --- a/stmhal/extint.c +++ b/stmhal/extint.c @@ -15,58 +15,52 @@ #include "pin.h" #include "extint.h" -// Usage Model: -// -// There are a total of 22 interrupt lines. 16 of these can come from GPIO pins -// and the remaining 6 are from internal sources. -// -// For lines 0 thru 15, a given line can map to the corresponding line from an -// arbitrary port. So line 0 can map to Px0 where x is A, B, C, ... and -// line 1 can map to Px1 where x is A, B, C, ... -// -// def callback(line): -// print("line =", line) -// -// # Note: ExtInt will automatically configure the gpio line as an input. -// extint = pyb.ExtInt(pin, pyb.ExtInt.IRQ_FALLING, pyb.GPIO.PULL_UP, callback) -// -// Now every time a falling edge is seen on the X1 pin, the callback will be -// called. Caution: mechanical pushbuttons have "bounce" and pushing or -// releasing a switch will often generate multiple edges. -// See: http://www.eng.utah.edu/~cs5780/debouncing.pdf for a detailed -// explanation, along with various techniques for debouncing. -// -// Trying to register 2 callbacks onto the same pin will throw an exception. -// -// If pin is passed as an integer, then it is assumed to map to one of the -// internal interrupt sources, and must be in the range 16 thru 22. -// -// All other pin objects go through the pin mapper to come up with one of the -// gpio pins. -// -// extint = pyb.ExtInt(pin, mode, pull, callback) -// -// Valid modes are pyb.ExtInt.IRQ_RISING, pyb.ExtInt.IRQ_FALLING, -// pyb.ExtInt.IRQ_RISING_FALLING, pyb.ExtInt.EVT_RISING, -// pyb.ExtInt.EVT_FALLING, and pyb.ExtInt.EVT_RISING_FALLING. -// -// Only the IRQ_xxx modes have been tested. The EVT_xxx modes have -// something to do with sleep mode and the WFE instruction. -// -// Valid pull values are pyb.GPIO.PULL_UP, pyb.GPIO.PULL_DOWN, pyb.GPIO.PULL_NONE. -// -// extint.line() will return the line number that pin was mapped to. -// extint.disable() can be use to disable the interrupt associated with a given -// exti object. This could be useful for debouncing. -// extint.enable() enables a disabled interrupt -// extint.swint() will allow the callback to be triggered from software. -// -// pyb.ExtInt.regs() will dump the values of the EXTI registers. -// -// There is also a C API, so that drivers which require EXTI interrupt lines -// can also use this code. See extint.h for the available functions and -// usrsw.h for an example of using this. -// +/// \moduleref pyb +/// \class ExtInt - configure I/O pins to interrupt on external events +/// +/// There are a total of 22 interrupt lines. 16 of these can come from GPIO pins +/// and the remaining 6 are from internal sources. +/// +/// For lines 0 thru 15, a given line can map to the corresponding line from an +/// arbitrary port. So line 0 can map to Px0 where x is A, B, C, ... and +/// line 1 can map to Px1 where x is A, B, C, ... +/// +/// def callback(line): +/// print("line =", line) +/// +/// Note: ExtInt will automatically configure the gpio line as an input. +/// +/// extint = pyb.ExtInt(pin, pyb.ExtInt.IRQ_FALLING, pyb.GPIO.PULL_UP, callback) +/// +/// Now every time a falling edge is seen on the X1 pin, the callback will be +/// called. Caution: mechanical pushbuttons have "bounce" and pushing or +/// releasing a switch will often generate multiple edges. +/// See: http://www.eng.utah.edu/~cs5780/debouncing.pdf for a detailed +/// explanation, along with various techniques for debouncing. +/// +/// Trying to register 2 callbacks onto the same pin will throw an exception. +/// +/// If pin is passed as an integer, then it is assumed to map to one of the +/// internal interrupt sources, and must be in the range 16 thru 22. +/// +/// All other pin objects go through the pin mapper to come up with one of the +/// gpio pins. +/// +/// extint = pyb.ExtInt(pin, mode, pull, callback) +/// +/// Valid modes are pyb.ExtInt.IRQ_RISING, pyb.ExtInt.IRQ_FALLING, +/// pyb.ExtInt.IRQ_RISING_FALLING, pyb.ExtInt.EVT_RISING, +/// pyb.ExtInt.EVT_FALLING, and pyb.ExtInt.EVT_RISING_FALLING. +/// +/// Only the IRQ_xxx modes have been tested. The EVT_xxx modes have +/// something to do with sleep mode and the WFE instruction. +/// +/// Valid pull values are pyb.GPIO.PULL_UP, pyb.GPIO.PULL_DOWN, pyb.GPIO.PULL_NONE. +/// +/// There is also a C API, so that drivers which require EXTI interrupt lines +/// can also use this code. See extint.h for the available functions and +/// usrsw.h for an example of using this. + // TODO Add python method to change callback object. #define EXTI_OFFSET (EXTI_BASE - PERIPH_BASE) @@ -204,29 +198,45 @@ void extint_swint(uint line) { EXTI->SWIER = (1 << line); } +/// \method line() +/// Return the line number that the pin is mapped to. STATIC mp_obj_t extint_obj_line(mp_obj_t self_in) { extint_obj_t *self = self_in; return MP_OBJ_NEW_SMALL_INT(self->line); } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_line_obj, extint_obj_line); +/// \method enable() +/// Enable a disabled interrupt. STATIC mp_obj_t extint_obj_enable(mp_obj_t self_in) { extint_obj_t *self = self_in; extint_enable(self->line); return mp_const_none; } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_enable_obj, extint_obj_enable); +/// \method disable() +/// Disable the interrupt associated with the ExtInt object. +/// This could be useful for debouncing. STATIC mp_obj_t extint_obj_disable(mp_obj_t self_in) { extint_obj_t *self = self_in; extint_disable(self->line); return mp_const_none; } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_disable_obj, extint_obj_disable); +/// \method swint() +/// Trigger the callback from software. STATIC mp_obj_t extint_obj_swint(mp_obj_t self_in) { extint_obj_t *self = self_in; extint_swint(self->line); return mp_const_none; } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_swint_obj, extint_obj_swint); +// TODO document as a staticmethod +/// \classmethod regs() +/// Dump the values of the EXTI registers. STATIC mp_obj_t extint_regs(void) { printf("EXTI_IMR %08lx\n", EXTI->IMR); printf("EXTI_EMR %08lx\n", EXTI->EMR); @@ -236,9 +246,24 @@ STATIC mp_obj_t extint_regs(void) { printf("EXTI_PR %08lx\n", EXTI->PR); return mp_const_none; } +STATIC MP_DEFINE_CONST_FUN_OBJ_0(extint_regs_fun_obj, extint_regs); +STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(extint_regs_obj, (mp_obj_t)&extint_regs_fun_obj); -// line_obj = pyb.ExtInt(pin, mode, pull, callback) - +/// \classmethod \constructor(pin, mode, pull, callback) +/// Create an ExtInt object: +/// +/// - `pin` is the pin on which to enable the interrupt (can be a pin object or any valid pin name). +/// - `mode` can be one of: +/// - `ExtInt.IRQ_RISING` - trigger on a rising edge; +/// - `ExtInt.IRQ_FALLING` - trigger on a falling edge; +/// - `ExtInt.IRQ_RISING_FALLING` - trigger on a rising or falling edge. +/// - `pull` can be one of: +/// - `pyb.Pin.PULL_NONE` - no pull up or down resistors; +/// - `pyb.Pin.PULL_UP` - enable the pull-up resistor; +/// - `pyb.Pin.PULL_DOWN` - enable the pull-down resistor. +/// - `callback` is the function to call when the interrupt triggers. The +/// callback function must accept exactly 1 argument, which is the line that +/// triggered the interrupt. STATIC const mp_arg_t pyb_extint_make_new_args[] = { { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, @@ -268,19 +293,17 @@ STATIC void extint_obj_print(void (*print)(void *env, const char *fmt, ...), voi print(env, "<ExtInt line=%u>", self->line); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_line_obj, extint_obj_line); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_enable_obj, extint_obj_enable); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_disable_obj, extint_obj_disable); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_swint_obj, extint_obj_swint); -STATIC MP_DEFINE_CONST_FUN_OBJ_0(extint_regs_fun_obj, extint_regs); -STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(extint_regs_obj, (mp_obj_t)&extint_regs_fun_obj); - STATIC const mp_map_elem_t extint_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_line), (mp_obj_t)&extint_obj_line_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&extint_obj_enable_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&extint_obj_disable_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_swint), (mp_obj_t)&extint_obj_swint_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_regs), (mp_obj_t)&extint_regs_obj }, + + // class constants + /// \constant IRQ_RISING - interrupt on a rising edge + /// \constant IRQ_FALLING - interrupt on a falling edge + /// \constant IRQ_RISING_FALLING - interrupt on a rising or falling edge { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_IT_RISING) }, { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_FALLING), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_IT_FALLING) }, { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING_FALLING), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_IT_RISING_FALLING) }, |