diff --git a/stm/Makefile b/stm/Makefile index 991645b6c9000..cc16eda43783e 100644 --- a/stm/Makefile +++ b/stm/Makefile @@ -25,6 +25,9 @@ CFLAGS += -I$(FATFS_DIR) #CFLAGS += -I$(CC3K_DIR) BOARD ?= PYBOARD4 +ifeq ($(wildcard boards/$(BOARD)/.),) +$(error Invalid BOARD specified) +endif CFLAGS += -Iboards/$(BOARD) #Debugging/Optimization @@ -67,13 +70,14 @@ SRC_C = \ audio.c \ sdcard.c \ i2c.c \ - usrsw.c \ adc.c \ rtc.c \ file.c \ pin.c \ pin_named_pins.c \ pin_map.c \ + exti.c \ + usrsw.c \ # pybwlan.c \ SRC_S = \ @@ -185,10 +189,21 @@ MAKE_PINS = boards/make-pins.py BOARD_PINS = boards/$(BOARD)/pins.csv AF_FILE = boards/stm32f4xx-af.csv PREFIX_FILE = boards/stm32f4xx-prefix.c - -$(BUILD)/pins_$(BOARD).c: $(MAKE_PINS) $(BOARD_PINS) $(AF_FILE) $(PREFIX_FILE) +GEN_PINS_SRC = $(BUILD)/pins_$(BOARD).c +GEN_PINS_HDR = $(BUILD)/pins.h + +# Making OBJ use an order-only depenedency on the generated pins.h file +# has the side effect of making the pins.h file before we actually compile +# any of the objects. The normal dependency generation will deal with the +# case when pins.h is modified. But when it doesn't exist, we don't know +# which source files might need it. +$(OBJ): | $(BUILD)/pins.h + +# Use a pattern rule here so that make will only call make-pins.py once to make +# both pins_$(BOARD).c and pins.h +$(BUILD)/%_$(BOARD).c $(BUILD)/%.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) $(ECHO) "Create $@" - $(Q)python $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) > $@ + $(Q)python $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) > $(GEN_PINS_SRC) $(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c $(call compile_c) diff --git a/stm/boards/NETDUINO_PLUS_2/mpconfigboard.h b/stm/boards/NETDUINO_PLUS_2/mpconfigboard.h index 9c407d9cd4aa0..2c0e4b74c0a81 100644 --- a/stm/boards/NETDUINO_PLUS_2/mpconfigboard.h +++ b/stm/boards/NETDUINO_PLUS_2/mpconfigboard.h @@ -18,14 +18,11 @@ #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_AUDIO (0) -#define USRSW_PORT (GPIOB) -#define USRSW_PIN (GPIO_Pin_11) +// USRSW is pulled low. Pressing the button makes the input go high. +#define USRSW_PIN (pin_B11) #define USRSW_PUPD (GPIO_PuPd_NOPULL) -#define USRSW_EXTI_PIN (EXTI_PinSource11) -#define USRSW_EXTI_PORT (EXTI_PortSourceGPIOB) -#define USRSW_EXTI_LINE (EXTI_Line11) -#define USRSW_EXTI_IRQN (EXTI15_10_IRQn) #define USRSW_EXTI_EDGE (EXTI_Trigger_Rising) +#define USRSW_PRESSED (1) /* LED */ #define PYB_LED1_PORT (GPIOA) // Blue LED diff --git a/stm/boards/PYBOARD3/mpconfigboard.h b/stm/boards/PYBOARD3/mpconfigboard.h index 1632445741082..88573e2b1655e 100644 --- a/stm/boards/PYBOARD3/mpconfigboard.h +++ b/stm/boards/PYBOARD3/mpconfigboard.h @@ -14,14 +14,11 @@ #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_AUDIO (0) -#define USRSW_PORT (GPIOA) -#define USRSW_PIN (GPIO_Pin_13) +// USRSW has no pullup or pulldown, and pressing the switch makes the input go low +#define USRSW_PIN (pin_A13) #define USRSW_PUPD (GPIO_PuPd_UP) -#define USRSW_EXTI_PIN (EXTI_PinSource13) -#define USRSW_EXTI_PORT (EXTI_PortSourceGPIOA) -#define USRSW_EXTI_LINE (EXTI_Line13) -#define USRSW_EXTI_IRQN (EXTI15_10_IRQn) -#define USRSW_EXTI_EDGE (EXTI_Trigger_Rising) +#define USRSW_EXTI_EDGE (EXTI_Trigger_Falling) +#define USRSW_PRESSED (0) /* LED */ #define PYB_LED1_PORT (GPIOA) diff --git a/stm/boards/PYBOARD4/mpconfigboard.h b/stm/boards/PYBOARD4/mpconfigboard.h index 3cb00b4027c69..88c3944312967 100644 --- a/stm/boards/PYBOARD4/mpconfigboard.h +++ b/stm/boards/PYBOARD4/mpconfigboard.h @@ -14,14 +14,11 @@ #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_AUDIO (0) -#define USRSW_PORT (GPIOB) -#define USRSW_PIN (GPIO_Pin_3) +// USRSW has no pullup or pulldown, and pressing the switch makes the input go low +#define USRSW_PIN (pin_B3) #define USRSW_PUPD (GPIO_PuPd_UP) -#define USRSW_EXTI_PIN (EXTI_PinSource3) -#define USRSW_EXTI_PORT (EXTI_PortSourceGPIOB) -#define USRSW_EXTI_LINE (EXTI_Line3) -#define USRSW_EXTI_IRQN (EXTI3_IRQn) -#define USRSW_EXTI_EDGE (EXTI_Trigger_Rising) +#define USRSW_EXTI_EDGE (EXTI_Trigger_Falling) +#define USRSW_PRESSED (0) /* LED */ #define PYB_LED1_PORT (GPIOA) diff --git a/stm/boards/STM32F4DISC/mpconfigboard.h b/stm/boards/STM32F4DISC/mpconfigboard.h index 2708504cb0979..1e26f730ec06d 100644 --- a/stm/boards/STM32F4DISC/mpconfigboard.h +++ b/stm/boards/STM32F4DISC/mpconfigboard.h @@ -14,14 +14,11 @@ #define MICROPY_HW_ENABLE_SERVO (0) #define MICROPY_HW_ENABLE_AUDIO (0) -#define USRSW_PORT (GPIOA) -#define USRSW_PIN (GPIO_Pin_0) +// USRSW is pulled low. Pressing the button makes the input go high. +#define USRSW_PIN (pin_A0) #define USRSW_PUPD (GPIO_PuPd_NOPULL) -#define USRSW_EXTI_PIN (EXTI_PinSource0) -#define USRSW_EXTI_PORT (EXTI_PortSourceGPIOA) -#define USRSW_EXTI_LINE (EXTI_Line0) -#define USRSW_EXTI_IRQN (EXTI0_IRQn) -#define USRSW_EXTI_EDGE (EXTI_Trigger_Falling) +#define USRSW_EXTI_EDGE (EXTI_Trigger_Rising) +#define USRSW_PRESSED (1) /* LED */ #define PYB_LED1_PORT (GPIOD) diff --git a/stm/boards/make-pins.py b/stm/boards/make-pins.py index 0bc9118b089c7..b39a2b9dddefc 100755 --- a/stm/boards/make-pins.py +++ b/stm/boards/make-pins.py @@ -133,6 +133,13 @@ def print(self): self.alt_fn_count, self.alt_fn_name())) print('') + def print_header(self, hdr_file): + hdr_file.write('extern const pin_obj_t pin_{:s};\n'. + format(self.pin_name())) + if self.alt_fn_count > 0: + hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'. + format(self.pin_name())) + class Pins(object): @@ -191,6 +198,12 @@ def print(self): print('') self.print_named('board', self.board_pins) + def print_header(self, hdr_filename): + with open(hdr_filename, 'wb') as hdr_file: + for pin in self.pins: + if pin.board_name: + pin.print_header(hdr_file) + def main(): parser = argparse.ArgumentParser( @@ -215,6 +228,12 @@ def main(): help="Specifies beginning portion of generated pins file", default="stm32f4xx-prefix.c" ) + parser.add_argument( + "-r", "--hdr", + dest="hdr_filename", + help="Specifies name of generated pin header file", + default="build/pins.h" + ) args = parser.parse_args(sys.argv[1:]) pins = Pins() @@ -235,6 +254,7 @@ def main(): with open(args.prefix_filename, 'r') as prefix_file: print(prefix_file.read()) pins.print() + pins.print_header(args.hdr_filename) if __name__ == "__main__": diff --git a/stm/exti.c b/stm/exti.c new file mode 100644 index 0000000000000..6b0711a71591f --- /dev/null +++ b/stm/exti.c @@ -0,0 +1,417 @@ +#include +#include +#include + +#include +#include + +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "runtime.h" +#include "nlr.h" + +#include "pin.h" +#include "exti.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, param): +// print("line =", line, "param =", param) +// +// # Configure the pin as a GPIO input. +// pin = pyb.Pin.board.X1 +// pyb.gpio_in(pin, pyb.PULL_UP) +// exti = pyb.Exti(pin, pyb.Exti.MODE_IRQ, pyb.Exti.TRIGGER_RISING, callback, 37) +// +// Now every time a rising 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. +// +// Valid modes are pyb.Exti.MODE_IRQ and pyb.Exti.MODE_EVENT (Only MODE_IRQ +// has been tested. MODE_EVENT has something to do with sleep mode and the +// WFE instruction). +// +// Valid edge triggers are pyb.Exti.TRIGGER_RISING, TRIGGER_FALLING, and TRIGGER_BOTH. +// +// exti.line() will return the line number that pin was mapped to. +// exti.disable() can be use to disable the interrupt associated with a given +// exti object. This could be useful for debouncing. +// exti.enable() enables a disabled interrupt +// exti.swint() will allow the callback to be triggered from software. +// +// pyb.Exti.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 exti.h for the available functions and +// usrsw.h for an example of using this. + +#define EXTI_OFFSET (EXTI_BASE - PERIPH_BASE) + +// Macro used to set/clear the bit corresponding to the line in the IMR/EMR +// register in an atomic fashion by using bitband addressing. +#define EXTI_MODE_BB(mode, line) (*(vu32 *)(PERIPH_BB_BASE + ((EXTI_OFFSET + (mode)) * 32) + ((line) * 4))) + +// This macro will work with the EXTI_Trigger_Rising and EXTI_Trigger_Falling constants +// but not EXTI_Trigger_Rising_Falling. +#define EXTI_EDGE_BB(edge, line) (*(vu32 *)(PERIPH_BB_BASE + ((EXTI_OFFSET + (edge)) * 32) + ((line) * 4))) + +#define EXTI_SWIER_BB(line) (*(vu32 *)(PERIPH_BB_BASE + ((EXTI_OFFSET + offsetof(EXTI_TypeDef, SWIER)) * 32) + ((line) * 4))) +#define EXTI_PR_BB(line) (*(vu32 *)(PERIPH_BB_BASE + ((EXTI_OFFSET + offsetof(EXTI_TypeDef, PR)) * 32) + ((line) * 4))) + +typedef struct { + mp_obj_base_t base; + mp_small_int_t line; +} exti_obj_t; + +typedef struct { + mp_obj_t callback_obj; + mp_obj_t param_obj; + EXTIMode_TypeDef mode; +} exti_vector_t; + +static exti_vector_t exti_vector[EXTI_NUM_VECTORS]; + +static const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = { + EXTI0_IRQn, EXTI1_IRQn, EXTI2_IRQn, EXTI3_IRQn, EXTI4_IRQn, + EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, + EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, + EXTI15_10_IRQn, PVD_IRQn, RTC_Alarm_IRQn, OTG_FS_WKUP_IRQn, ETH_WKUP_IRQn, + OTG_HS_WKUP_IRQn, TAMP_STAMP_IRQn, RTC_WKUP_IRQn +}; + +uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t trigger_obj, mp_obj_t callback_obj, mp_obj_t param_obj) { + const pin_obj_t *pin = NULL; + uint v_line; + + if (MP_OBJ_IS_INT(pin_obj)) { + // If an integer is passed in, then use it to identify lines 16 thru 22 + // We expect lines 0 thru 15 to be passed in as a pin, so that we can + // get both the port number and line number. + v_line = mp_obj_get_int(pin_obj); + if (v_line < 16) { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d < 16, use a Pin object", v_line)); + } + if (v_line >= EXTI_NUM_VECTORS) { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d >= max of %d", v_line, EXTI_NUM_VECTORS)); + } + } else { + pin = pin_map_user_obj(pin_obj); + v_line = pin->pin; + } + int mode = mp_obj_get_int(mode_obj); + if (!IS_EXTI_MODE(mode)) { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid EXTI Mode: %d", mode)); + } + int trigger = mp_obj_get_int(trigger_obj); + if (!IS_EXTI_TRIGGER(trigger)) { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid EXTI Trigger: %d", trigger)); + } + + exti_vector_t *v = &exti_vector[v_line]; + if (v->callback_obj != mp_const_none && callback_obj != mp_const_none) { + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d is already in use", v_line)); + } + + // We need to update callback and param atomically, so we disable the line + // before we update anything. + + exti_disable(v_line); + + if (pin && callback_obj) { + // Enable SYSCFG clock + RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); + + // For EXTI lines 0 thru 15, we need to configure which port controls + // the line. + SYSCFG_EXTILineConfig(pin->port, v_line); + } + v->callback_obj = callback_obj; + v->param_obj = param_obj; + v->mode = mode; + + if (v->callback_obj != mp_const_none) { + // The EXTI_Init function isn't atomic. It uses |= and &=. + // We use bit band operations to make it atomic. + exti_disable(v_line); + EXTI_EDGE_BB(EXTI_Trigger_Rising, v_line) = + trigger == EXTI_Trigger_Rising || trigger == EXTI_Trigger_Rising_Falling; + EXTI_EDGE_BB(EXTI_Trigger_Falling, v_line) = + trigger == EXTI_Trigger_Falling || trigger == EXTI_Trigger_Rising_Falling; + exti_enable(v_line); + + /* Enable and set NVIC Interrupt to the lowest priority */ + NVIC_InitTypeDef NVIC_InitStructure; + NVIC_InitStructure.NVIC_IRQChannel = nvic_irq_channel[v_line]; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + } + return v_line; +} + +void exti_enable(uint line) { + if (line >= EXTI_NUM_VECTORS) { + return; + } + // Since manipulating IMR/EMR is a read-modify-write, and we want this to + // be atomic, we use the bit-band area to just affect the bit we're + // interested in. + EXTI_MODE_BB(exti_vector[line].mode, line) = 1; +} + +void exti_disable(uint line) { + if (line >= EXTI_NUM_VECTORS) { + return; + } + // Since manipulating IMR/EMR is a read-modify-write, and we want this to + // be atomic, we use the bit-band area to just affect the bit we're + // interested in. + EXTI_MODE_BB(EXTI_Mode_Interrupt, line) = 0; + EXTI_MODE_BB(EXTI_Mode_Event, line) = 0; +} + +void exti_swint(uint line) { + if (line >= EXTI_NUM_VECTORS) { + return; + } + EXTI_SWIER_BB(line) = 1; +} + +static mp_obj_t exti_obj_line(mp_obj_t self_in) { + exti_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(self->line); +} + +static mp_obj_t exti_obj_enable(mp_obj_t self_in) { + exti_obj_t *self = self_in; + exti_enable(self->line); + return mp_const_none; +} + +static mp_obj_t exti_obj_disable(mp_obj_t self_in) { + exti_obj_t *self = self_in; + exti_disable(self->line); + return mp_const_none; +} + +static mp_obj_t exti_obj_swint(mp_obj_t self_in) { + exti_obj_t *self = self_in; + exti_swint(self->line); + return mp_const_none; +} + +static MP_DEFINE_CONST_FUN_OBJ_1(exti_obj_line_obj, exti_obj_line); +static MP_DEFINE_CONST_FUN_OBJ_1(exti_obj_enable_obj, exti_obj_enable); +static MP_DEFINE_CONST_FUN_OBJ_1(exti_obj_disable_obj, exti_obj_disable); +static MP_DEFINE_CONST_FUN_OBJ_1(exti_obj_swint_obj, exti_obj_swint); + +static const mp_method_t exti_methods[] = { + { "line", &exti_obj_line_obj }, + { "enable", &exti_obj_enable_obj }, + { "disable", &exti_obj_disable_obj }, + { "swint", &exti_obj_swint_obj }, + { NULL, NULL }, +}; + +static mp_obj_t exti_regs(void) { + printf("EXTI_IMR %08lx\n", EXTI->IMR); + printf("EXTI_EMR %08lx\n", EXTI->EMR); + printf("EXTI_RTSR %08lx\n", EXTI->RTSR); + printf("EXTI_FTSR %08lx\n", EXTI->FTSR); + printf("EXTI_SWIER %08lx\n", EXTI->SWIER); + printf("EXTI_PR %08lx\n", EXTI->PR); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_0(exti_regs_obj, exti_regs); + +typedef struct { + const char *name; + uint val; +} exti_const_t; + +static const exti_const_t exti_const[] = { + { "MODE_IRQ", EXTI_Mode_Interrupt }, + { "MODE_EVENT", EXTI_Mode_Event }, + { "TRIGGER_RISING", EXTI_Trigger_Rising }, + { "TRIGGER_FALLING", EXTI_Trigger_Falling }, + { "TRIGGER_BOTH", EXTI_Trigger_Rising_Falling }, +}; +#define EXTI_NUM_CONST (sizeof(exti_const) / sizeof(exti_const[0])) + +static void exti_load_attr(mp_obj_t self_in, qstr attr_qstr, mp_obj_t *dest) { + (void)self_in; + const char *attr = qstr_str(attr_qstr); + + if (strcmp(attr, "regs") == 0) { + dest[0] = (mp_obj_t)&exti_regs_obj; + return; + } + const exti_const_t *entry = &exti_const[0]; + for (; entry < &exti_const[EXTI_NUM_CONST]; entry++) { + if (strcmp(attr, entry->name) == 0) { + dest[0] = MP_OBJ_NEW_SMALL_INT(entry->val); + dest[1] = MP_OBJ_NULL; + return; + } + } +} + +// line_obj = pyb.Exti(pin, mode, trigger, callback, [param]) + +static mp_obj_t exti_call(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { + // type_in == exti_obj_type + + rt_check_nargs(n_args, 4, 5, n_kw, 0); + + exti_obj_t *self = m_new_obj(exti_obj_t); + self->base.type = type_in; + mp_obj_t line_obj = args[0]; + mp_obj_t mode_obj = args[1]; + mp_obj_t trigger_obj = args[2]; + mp_obj_t callback_obj = args[3]; + mp_obj_t param_obj = mp_const_none; + if (n_args > 4) { + param_obj = args[4]; + } + self->line = exti_register(line_obj, mode_obj, trigger_obj, callback_obj, param_obj); + + return self; +} + +static void exti_meta_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { + (void) self_in; + print(env, ""); +} + +static void exti_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { + exti_obj_t *self = self_in; + print(env, "", self->line); +} + +static const mp_obj_type_t exti_meta_obj_type = { + { &mp_type_type }, + .name = MP_QSTR_ExtiMeta, + .print = exti_meta_obj_print, + .call = exti_call, + .load_attr = exti_load_attr, +}; + +static const mp_obj_type_t exti_obj_type = { + { &exti_meta_obj_type }, + .name = MP_QSTR_Exti, + .print = exti_obj_print, + .methods = exti_methods, +}; + +void exti_init_early(void) { + for (exti_vector_t *v = exti_vector; v < &exti_vector[EXTI_NUM_VECTORS]; v++) { + v->callback_obj = mp_const_none; + v->param_obj = mp_const_none; + v->mode = EXTI_Mode_Interrupt; + } +} + +void exti_init(mp_obj_t mod) { + rt_store_attr(mod, MP_QSTR_Exti, (mp_obj_t)&exti_obj_type); +} + +static void Handle_EXTI_Irq(uint32_t line) { + if (EXTI_PR_BB(line)) { + EXTI_PR_BB(line) = 1; // Clears bit + if (line < EXTI_NUM_VECTORS) { + exti_vector_t *v = &exti_vector[line]; + if (v->callback_obj != mp_const_none) { + rt_call_function_2(v->callback_obj, MP_OBJ_NEW_SMALL_INT(line), v->param_obj); + } + } + } +} + +void EXTI0_IRQHandler(void) { + Handle_EXTI_Irq(0); +} + +void EXTI1_IRQHandler(void) { + Handle_EXTI_Irq(1); +} + +void EXTI2_IRQHandler(void) { + Handle_EXTI_Irq(2); +} + +void EXTI3_IRQHandler(void) { + Handle_EXTI_Irq(3); +} + +void EXTI4_IRQHandler(void) { + Handle_EXTI_Irq(4); +} + +void EXTI9_5_IRQHandler(void) { + Handle_EXTI_Irq(5); + Handle_EXTI_Irq(6); + Handle_EXTI_Irq(7); + Handle_EXTI_Irq(8); + Handle_EXTI_Irq(9); +} + +void EXTI15_10_IRQHandler(void) { + Handle_EXTI_Irq(10); + Handle_EXTI_Irq(11); + Handle_EXTI_Irq(12); + Handle_EXTI_Irq(13); + Handle_EXTI_Irq(14); + Handle_EXTI_Irq(15); +} + +void PVD_IRQHandler(void) { + Handle_EXTI_Irq(16); +} + +void RTC_Alarm_IRQHandler(void) { + Handle_EXTI_Irq(17); +} + +#if 0 // dealt with in stm32fxxx_it.c +void OTG_FS_WKUP_IRQHandler(void) { + Handle_EXTI_Irq(18); +} +#endif + +void ETH_WKUP_IRQHandler(void) { + Handle_EXTI_Irq(19); +} + +#if 0 // dealt with in stm32fxxx_it.c +void OTG_HS_WKUP_IRQHandler(void) { + Handle_EXTI_Irq(20); +} +#endif + +void TAMP_STAMP_IRQHandler(void) { + Handle_EXTI_Irq(21); +} + +void RTC_WKUP_IRQHandler(void) { + Handle_EXTI_Irq(22); +} diff --git a/stm/exti.h b/stm/exti.h new file mode 100644 index 0000000000000..f5b11d0496cf1 --- /dev/null +++ b/stm/exti.h @@ -0,0 +1,29 @@ +// Vectors 0-15 are for regular pins +// Vectors 16-22 are for internal sources. +// +// Use the following constants for the internal sources: + +#define EXTI_PVD_OUTPUT (16) +#define EXTI_RTC_ALARM (17) +#define EXTI_USB_OTG_FS_WAKEUP (18) +#define EXTI_ETH_WAKEUP (19) +#define EXTI_USB_OTG_HS_WAKEUP (20) +#define EXTI_RTC_TIMESTAMP (21) +#define EXTI_RTC_WAKEUP (22) + +#define EXTI_NUM_VECTORS 23 + +void exti_init_early(void); +void exti_init(mp_obj_t mod); + +uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t trigger_obj, mp_obj_t callback_obj, mp_obj_t param_obj); + +void exti_enable(uint line); +void exti_disable(uint line); +void exti_swint(uint line); + +typedef struct { + mp_obj_t callback; + mp_obj_t param; +} exti_t; + diff --git a/stm/gpio.h b/stm/gpio.h index 2f81ac6658796..1071c9ef01eff 100644 --- a/stm/gpio.h +++ b/stm/gpio.h @@ -1 +1,4 @@ +mp_obj_t pyb_gpio(uint n_args, mp_obj_t *args); +mp_obj_t pyb_gpio_input(mp_obj_t arg_pin, mp_obj_t arg_mode); +mp_obj_t pyb_gpio_output(mp_obj_t arg_pin, mp_obj_t arg_mode); void gpio_init(mp_obj_t mod); diff --git a/stm/main.c b/stm/main.c index 2757e7665d064..86a6570dd85a9 100644 --- a/stm/main.c +++ b/stm/main.c @@ -51,6 +51,7 @@ #include "rtc.h" #include "file.h" #include "pin.h" +#include "exti.h" int errno; @@ -346,9 +347,6 @@ int main(void) { led_state(PYB_LED_G1, 1); // more sub-system init -#if MICROPY_HW_HAS_SWITCH - switch_init(); -#endif #if MICROPY_HW_HAS_SDCARD sdcard_init(); #endif @@ -374,6 +372,11 @@ int main(void) { def_path[2] = MP_OBJ_NEW_QSTR(MP_QSTR_0_colon__slash_lib); sys_path = mp_obj_new_list(3, def_path); + exti_init_early(); +#if MICROPY_HW_HAS_SWITCH + switch_init(); +#endif + #if MICROPY_HW_HAS_LCD // LCD init (just creates class, init hardware by calling LCD()) lcd_init(); @@ -449,7 +452,7 @@ int main(void) { pin_map_init(m); gpio_init(m); - + exti_init(m); rt_store_name(MP_QSTR_pyb, m); rt_store_name(MP_QSTR_open, rt_make_function_n(2, pyb_io_open)); diff --git a/stm/qstrdefsport.h b/stm/qstrdefsport.h index 3b20e3acd3ee1..645c2b8c72476 100644 --- a/stm/qstrdefsport.h +++ b/stm/qstrdefsport.h @@ -12,6 +12,7 @@ Q(sync) Q(gc) Q(delay) Q(switch) +Q(SW) Q(servo) Q(pwm) Q(accel) @@ -40,3 +41,5 @@ Q(Pin) Q(PinMap) Q(PinAF) Q(PinNamed) +Q(Exti) +Q(ExtiMeta) diff --git a/stm/stm32fxxx_it.c b/stm/stm32fxxx_it.c index 1a6862bbd149e..1cef4514c166f 100644 --- a/stm/stm32fxxx_it.c +++ b/stm/stm32fxxx_it.c @@ -284,66 +284,4 @@ void TIM6_DAC_IRQHandler(void) { } } -#include "std.h" -#include "misc.h" -#include "mpconfig.h" -#include "qstr.h" -#include "obj.h" -#include "led.h" - -void Default_Handler(void); // Found in startup_stm32f40xx.s - -// EXTI -// for USRSW on A13 for PYBOARD3, and B11 for NETDUINO_PLUS_2 -// for cc3000 on A14 -void EXTI15_10_IRQHandler(void) { - // work out if it's the user switch that had the interrupt - // Note that if the user switch is on a diffetent IRQ, then this code - // should be optimized out. - if (USRSW_EXTI_IRQN == EXTI15_10_IRQn) { - if (EXTI_GetITStatus(USRSW_EXTI_LINE) != RESET) { - // this is used just to wake the device - EXTI_ClearITPendingBit(USRSW_EXTI_LINE); - } - } - // work out if it's A14 that had the interrupt - if (EXTI_GetITStatus(EXTI_Line14) != RESET) { - led_toggle(PYB_LED_G2); - /* these are needed for CC3000 support - extern void SpiIntGPIOHandler(void); - extern uint32_t exti14_enabled; - extern uint32_t exti14_missed; - //printf("-> EXTI14 en=%lu miss=%lu\n", exti14_enabled, exti14_missed); - if (exti14_enabled) { - exti14_missed = 0; - SpiIntGPIOHandler(); // CC3000 interrupt - } else { - exti14_missed = 1; - } - */ - EXTI_ClearITPendingBit(EXTI_Line14); - //printf("<- EXTI14 done\n"); - } -} - -// STM32F4DISC is setup for A0 -void EXTI0_IRQHandler(void) { - if (USRSW_EXTI_IRQN == EXTI0_IRQn) { - // this is used just to wake the device - EXTI_ClearITPendingBit(USRSW_EXTI_LINE); - } else { - Default_Handler(); - } -} - -// PYBOARD4 has button on PB3 -void EXTI3_IRQHandler(void) { - if (USRSW_EXTI_IRQN == EXTI3_IRQn) { - // this is used just to wake the device - EXTI_ClearITPendingBit(USRSW_EXTI_LINE); - } else { - Default_Handler(); - } -} - /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/stm/usrsw.c b/stm/usrsw.c index 528c57e80dfee..53c6a1470b773 100644 --- a/stm/usrsw.c +++ b/stm/usrsw.c @@ -1,78 +1,67 @@ -#include -#include -#include -#include -#include +#include +#include #include "misc.h" #include "mpconfig.h" #include "qstr.h" #include "obj.h" +#include "runtime.h" #include "usrsw.h" -void switch_init(void) { - // make it an input with pull-up - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Pin = USRSW_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; - GPIO_InitStructure.GPIO_PuPd = USRSW_PUPD; - GPIO_Init(USRSW_PORT, &GPIO_InitStructure); - - // the rest does the EXTI interrupt +#include "exti.h" +#include "gpio.h" +#include "pin.h" +#include "build/pins.h" - /* Enable SYSCFG clock */ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); +// Usage Model: +// +// pyb.switch() returns True if the user switch is pressed, False otherwise. +// +// pyb.switch(callback) will register a callback to be called when the user +// switch is pressed. +// pyb.switch(None) will remove the callback. +// +// Example: +// +// def callback(): +// print("User Switch pressed") +// +// pyb.switch(callback) - /* Connect EXTI Line to GPIO pin */ - SYSCFG_EXTILineConfig(USRSW_EXTI_PORT, USRSW_EXTI_PIN); +static mp_obj_t switch_user_callback_obj; - /* Configure EXTI Line */ - EXTI_InitTypeDef EXTI_InitStructure; - EXTI_InitStructure.EXTI_Line = USRSW_EXTI_LINE; - EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; - EXTI_InitStructure.EXTI_Trigger = USRSW_EXTI_EDGE; - EXTI_InitStructure.EXTI_LineCmd = ENABLE; - EXTI_Init(&EXTI_InitStructure); +static mp_obj_t switch_callback(mp_obj_t line, mp_obj_t param) { + if (switch_user_callback_obj != mp_const_none) { + rt_call_function_0(switch_user_callback_obj); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(switch_callback_obj, switch_callback); - /* Enable and set EXTI15_10 Interrupt to the lowest priority */ - NVIC_InitTypeDef NVIC_InitStructure; - NVIC_InitStructure.NVIC_IRQChannel = USRSW_EXTI_IRQN; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F; - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - NVIC_Init(&NVIC_InitStructure); +void switch_init(void) { + switch_user_callback_obj = mp_const_none; + exti_register((mp_obj_t)&USRSW_PIN, + MP_OBJ_NEW_SMALL_INT(EXTI_Mode_Interrupt), + MP_OBJ_NEW_SMALL_INT(USRSW_EXTI_EDGE), + (mp_obj_t)&switch_callback_obj, + mp_const_none); + pyb_gpio_input((mp_obj_t)&USRSW_PIN, MP_OBJ_NEW_SMALL_INT(USRSW_PUPD)); } int switch_get(void) { -#if defined (PYBOARD3) || defined (PYBOARD4) - if (USRSW_PORT->IDR & USRSW_PIN) { - // pulled high, so switch is not pressed - return 0; - } else { - // pulled low, so switch is pressed - return 1; - } -#elif defined (STM32F4DISC) || defined(NETDUINO_PLUS_2) - /* switch pulled down */ - if (USRSW_PORT->IDR & USRSW_PIN) { - // pulled high, so switch is pressed - return 1; - } else { - // pulled low, so switch is not pressed - return 0; - } -#endif + int val = ((USRSW_PIN.gpio->IDR & USRSW_PIN.pin_mask) != 0); + return val == USRSW_PRESSED; } /******************************************************************************/ /* Micro Python bindings */ -static mp_obj_t pyb_switch(void) { - if (switch_get()) { - return mp_const_true; - } else { - return mp_const_false; +static mp_obj_t pyb_switch(uint n_args, mp_obj_t *args) { + if (n_args == 0) { + return switch_get() ? mp_const_true : mp_const_false; } + switch_user_callback_obj = args[0]; + return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_0(pyb_switch_obj, pyb_switch); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_switch_obj, 0, 1, pyb_switch); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy