From a5b5d4f27f94befaf5577563a0319e8194377118 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Sun, 3 Jun 2012 20:30:13 -0400 Subject: Bring back EXTI on F1, with deprecations for gpio.h on F1. Tested on Maple Mini with examples/mini-exti-test. Changes to Wirish are minor: use the new EXTI types exti_num and exti_cfg (see below) in place of now-deprecated variants in ext_interrupts.cpp. The way I originally did libmaple/exti.h was stupid, and fixing it turned out to be a little disruptive. libmaple/exti.h depends on libmaple/gpio.h (for AFIO), but that's a classic case of exposed implementation detail. So invert the dependency: make gpio.h depend on exti.h. Do this by adding exti_num and exti_cfg to exti.h; these respectively replace afio_exti_num and afio_exti_port. The afio_* variants are now deprecated. (Throw in a typedef and some macros at the bottom of the F1 series/gpio.h for backwards compatibility). Make exti_attach_interrupt() and exti_detach_interrupt() take exti_num/exti_cfg arguments instead of the afio_* variants. Make the EXTI dispatch routines __always_inline to defeat GCC -Os. Many renames throughout libmaple/stm32f1/ to stop using the deprecated names. Also move the previously F1-only gpio_exti_port() function into the public libmaple header. Reimplementing it in terms of rcc_clk_ids lets us deprecate the gpio_dev->exti_port field, which will save space in the future. While we're there, I notice that struct gpio_dev is defined once per series. That's dumb, as it misses the entire point of having device structs: they contain what's portable. So put the F1 version (which has the extra EXTI port field) into libmaple/gpio.h, and add the necessary exti_ports to libmaple/stm32f2/gpio.c. Sigh. We'll get rid of it eventually, at least. Clean up some other mistakes in gpio.h files as well (mostly removing util.h dependency). Sorry for the messy commit. For portability, add a new series-specific exti function, exti_select(). The F1 version in (new) libmaple/stm32f1/exti.c uses AFIO and some new private functionality in libmaple/exti.c and (new) libmaple/exti_private.h to make this convenient. We'll be able to do the SYSCFG equivalent on F2 without any trouble. Signed-off-by: Marti Bolivar --- libmaple/exti.c | 58 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 20 deletions(-) (limited to 'libmaple/exti.c') diff --git a/libmaple/exti.c b/libmaple/exti.c index 248c4b6..d84b789 100644 --- a/libmaple/exti.c +++ b/libmaple/exti.c @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011, 2012 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -66,7 +67,7 @@ static exti_channel exti_channels[] = { }; /* - * Convenience routines + * Portable routines */ /** @@ -80,13 +81,13 @@ static exti_channel exti_channels[] = { * @param handler Function handler to execute when interrupt is triggered. * @param mode Type of transition to trigger on, one of: * EXTI_RISING, EXTI_FALLING, EXTI_RISING_FALLING. - * @see afio_exti_num - * @see afio_exti_port + * @see exti_num + * @see exti_cfg * @see voidFuncPtr * @see exti_trigger_mode */ -void exti_attach_interrupt(afio_exti_num num, - afio_exti_port port, +void exti_attach_interrupt(exti_num num, + exti_cfg port, voidFuncPtr handler, exti_trigger_mode mode) { ASSERT(handler); @@ -108,8 +109,8 @@ void exti_attach_interrupt(afio_exti_num num, break; } - /* Map num to port */ - afio_exti_select(num, port); + /* Use the chip-specific exti_select() to map num to port */ + exti_select(num, port); /* Unmask external interrupt request */ bb_peri_set_bit(&EXTI_BASE->IMR, num, 1); @@ -120,10 +121,10 @@ void exti_attach_interrupt(afio_exti_num num, /** * @brief Unregister an external interrupt handler - * @param num Number of the external interrupt line to disable. - * @see afio_exti_num + * @param num External interrupt line to disable. + * @see exti_num */ -void exti_detach_interrupt(afio_exti_num num) { +void exti_detach_interrupt(exti_num num) { /* First, mask the interrupt request */ bb_peri_set_bit(&EXTI_BASE->IMR, num, 0); @@ -135,28 +136,45 @@ void exti_detach_interrupt(afio_exti_num num) { exti_channels[num].handler = NULL; } +/* Weak default exti_select(), until we get F2 support */ +__weak void exti_select(exti_num num, exti_cfg port) { + ASSERT(0); +} + +/* + * Private routines + */ + +void exti_do_select(__io uint32 *exti_cr, exti_num num, exti_cfg port) { + uint32 shift = 4 * (num % 4); + uint32 cr = *exti_cr; + cr &= ~(0xF << shift); + cr |= port << shift; + *exti_cr = cr; +} + /* * Interrupt handlers */ void __irq_exti0(void) { - dispatch_single_exti(AFIO_EXTI_0); + dispatch_single_exti(EXTI0); } void __irq_exti1(void) { - dispatch_single_exti(AFIO_EXTI_1); + dispatch_single_exti(EXTI1); } void __irq_exti2(void) { - dispatch_single_exti(AFIO_EXTI_2); + dispatch_single_exti(EXTI2); } void __irq_exti3(void) { - dispatch_single_exti(AFIO_EXTI_3); + dispatch_single_exti(EXTI3); } void __irq_exti4(void) { - dispatch_single_exti(AFIO_EXTI_4); + dispatch_single_exti(EXTI4); } void __irq_exti9_5(void) { @@ -177,7 +195,7 @@ void __irq_exti15_10(void) { * won't actually be cleared in time and the ISR will fire again. To * compensate, this function NOPs for 2 cycles after clearing the * pending bits to ensure it takes effect. */ -static inline void clear_pending_msk(uint32 exti_msk) { +static __always_inline void clear_pending_msk(uint32 exti_msk) { EXTI_BASE->PR = exti_msk; asm volatile("nop"); asm volatile("nop"); @@ -185,7 +203,7 @@ static 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 inline void dispatch_single_exti(uint32 exti) { +static __always_inline void dispatch_single_exti(uint32 exti) { voidFuncPtr handler = exti_channels[exti].handler; if (!handler) { @@ -193,18 +211,18 @@ static inline void dispatch_single_exti(uint32 exti) { } handler(); - clear_pending_msk(BIT(exti)); + clear_pending_msk(1U << exti); } /* Dispatch routine for EXTIs which share an IRQ. */ -static inline void dispatch_extis(uint32 start, uint32 stop) { +static __always_inline void dispatch_extis(uint32 start, uint32 stop) { uint32 pr = EXTI_BASE->PR; uint32 handled_msk = 0; uint32 exti; /* Dispatch user handlers for pending EXTIs. */ for (exti = start; exti <= stop; exti++) { - uint32 eb = BIT(exti); + uint32 eb = (1U << exti); if (pr & eb) { voidFuncPtr handler = exti_channels[exti].handler; if (handler) { -- cgit v1.2.3