From ac88e2de8ca29af4d30f1a53c74b86d58f0254cf Mon Sep 17 00:00:00 2001 From: joeycastillo Date: Wed, 18 Sep 2024 15:29:31 -0400 Subject: [PATCH] port external interrupts to gossamer framework --- Makefile | 1 + app.c | 15 ++-- watch-library/hardware/watch/watch_extint.c | 96 +++++++-------------- watch-library/shared/watch/watch.h | 2 +- watch-library/shared/watch/watch_extint.h | 24 ++---- 5 files changed, 47 insertions(+), 91 deletions(-) diff --git a/Makefile b/Makefile index db2a0417..54fb26bf 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,7 @@ INCLUDES += \ # Add your source files here. SRCS += \ + ./watch-library/hardware/watch/watch_extint.c \ ./watch-library/hardware/watch/watch_gpio.c \ ./watch-library/hardware/watch/watch_rtc.c \ ./watch-library/hardware/watch/watch_tcc.c \ diff --git a/app.c b/app.c index 0ba7a444..9daf3fb9 100644 --- a/app.c +++ b/app.c @@ -4,22 +4,25 @@ #include "delay.h" void app_init(void) { - _watch_rtc_init(); } void app_setup(void) { watch_enable_leds(); - watch_rtc_register_periodic_callback(NULL, 1); + watch_enable_external_interrupts(); + watch_register_interrupt_callback(HAL_GPIO_BTN_LIGHT_pin(), NULL, INTERRUPT_TRIGGER_FALLING); + watch_register_interrupt_callback(HAL_GPIO_BTN_MODE_pin(), NULL, INTERRUPT_TRIGGER_FALLING); + watch_register_interrupt_callback(HAL_GPIO_BTN_ALARM_pin(), NULL, INTERRUPT_TRIGGER_FALLING); } bool app_loop(void) { - watch_date_time date_time = watch_rtc_get_date_time(); + static bool on = false; - if (date_time.unit.second % 2 == 0) { - watch_set_led_red(); + if (on) { + watch_set_led_off(); } else { - watch_set_led_green(); + watch_set_led_yellow(); } + on = !on; return true; } \ No newline at end of file diff --git a/watch-library/hardware/watch/watch_extint.c b/watch-library/hardware/watch/watch_extint.c index 13e8eaa3..9a77d2b5 100644 --- a/watch-library/hardware/watch/watch_extint.c +++ b/watch-library/hardware/watch/watch_extint.c @@ -22,82 +22,44 @@ * SOFTWARE. */ +#include #include "watch_extint.h" +#include "watch_gpio.h" +#include "eic.h" + +watch_cb_t eic_callbacks[16] = { NULL }; + +void watch_eic_callback(uint8_t channel); void watch_enable_external_interrupts(void) { - // Configure EIC to use GCLK3 (the 32.768 kHz crystal) - hri_gclk_write_PCHCTRL_reg(GCLK, EIC_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK3_Val | (1 << GCLK_PCHCTRL_CHEN_Pos)); - // Enable AHB clock for the EIC - hri_mclk_set_APBAMASK_EIC_bit(MCLK); - // call HAL's external interrupt init function - ext_irq_init(); + eic_init(); + eic_configure_callback(watch_eic_callback); + eic_enable(); } void watch_disable_external_interrupts(void) { - ext_irq_deinit(); - hri_mclk_clear_APBAMASK_EIC_bit(MCLK); + eic_disable(); } -void watch_register_interrupt_callback(const uint8_t pin, ext_irq_cb_t callback, watch_interrupt_trigger trigger) { - uint8_t config_index; - uint8_t sense_pos; - switch (pin) { - case A0: - // for EIC channels 8-15, we need to set the SENSE value in CONFIG[1] - config_index = (WATCH_A0_EIC_CHANNEL > 7) ? 1 : 0; - // either way the index in CONFIG[n] must be 0-7 - sense_pos = 4 * (WATCH_A0_EIC_CHANNEL % 8); - break; - case A1: - config_index = (WATCH_A1_EIC_CHANNEL > 7) ? 1 : 0; - sense_pos = 4 * (WATCH_A1_EIC_CHANNEL % 8); - break; - case A2: - config_index = (WATCH_A2_EIC_CHANNEL > 7) ? 1 : 0; - sense_pos = 4 * (WATCH_A2_EIC_CHANNEL % 8); - break; - case A3: - config_index = (WATCH_A3_EIC_CHANNEL > 7) ? 1 : 0; - sense_pos = 4 * (WATCH_A3_EIC_CHANNEL % 8); - break; - case A4: - config_index = (WATCH_A4_EIC_CHANNEL > 7) ? 1 : 0; - sense_pos = 4 * (WATCH_A4_EIC_CHANNEL % 8); - break; - case BTN_ALARM: - config_index = (WATCH_BTN_ALARM_EIC_CHANNEL > 7) ? 1 : 0; - sense_pos = 4 * (WATCH_BTN_ALARM_EIC_CHANNEL % 8); - break; - case BTN_LIGHT: - config_index = (WATCH_BTN_LIGHT_EIC_CHANNEL > 7) ? 1 : 0; - sense_pos = 4 * (WATCH_BTN_LIGHT_EIC_CHANNEL % 8); - break; - case BTN_MODE: - config_index = (WATCH_BTN_MODE_EIC_CHANNEL > 7) ? 1 : 0; - sense_pos = 4 * (WATCH_BTN_MODE_EIC_CHANNEL % 8); - break; - default: - return; +void watch_register_interrupt_callback(const uint8_t pin, watch_cb_t callback, eic_interrupt_trigger trigger) { + watch_enable_digital_input(pin); + + // check if this is a button pin + if (pin == HAL_GPIO_BTN_LIGHT_pin() || pin == HAL_GPIO_BTN_MODE_pin() || pin == HAL_GPIO_BTN_ALARM_pin()) { + // if so, enable the pull-down resistor + watch_enable_pull_down(pin); } - gpio_set_pin_direction(pin, GPIO_DIRECTION_IN); - - // EIC configuration register is enable-protected, so we have to disable it first... - if (hri_eic_get_CTRLA_reg(EIC, EIC_CTRLA_ENABLE)) { - hri_eic_clear_CTRLA_ENABLE_bit(EIC); - // ...and wait for it to synchronize. - hri_eic_wait_for_sync(EIC, EIC_SYNCBUSY_ENABLE); + int8_t channel = eic_configure_pin(pin, trigger); + if (channel >= 0 && channel < 16) { + printf("Configured port %d pin %d on channel %d\n", pin >> 5, pin & 0x1F, channel); + eic_enable_interrupt(pin); + eic_callbacks[channel] = callback; + } +} + +void watch_eic_callback(uint8_t channel) { + if (eic_callbacks[channel] != NULL) { + eic_callbacks[channel](); } - // now update the configuration... - hri_eic_config_reg_t config = EIC->CONFIG[config_index].reg; - config &= ~(7 << sense_pos); - config |= trigger << (sense_pos); - hri_eic_write_CONFIG_reg(EIC, config_index, config); - // ...set the pin mode... - gpio_set_pin_function(pin, GPIO_PIN_FUNCTION_A); - if (pin == BTN_ALARM || pin == BTN_LIGHT || pin == BTN_MODE) gpio_set_pin_pull_mode(pin, GPIO_PULL_DOWN); - // ...and re-enable the EIC - hri_eic_set_CTRLA_ENABLE_bit(EIC); - - ext_irq_register(pin, callback); } diff --git a/watch-library/shared/watch/watch.h b/watch-library/shared/watch/watch.h index ecff1927..59a89efa 100644 --- a/watch-library/shared/watch/watch.h +++ b/watch-library/shared/watch/watch.h @@ -63,7 +63,7 @@ typedef void (*watch_cb_t)(void); #include "watch_rtc.h" // #include "watch_slcd.h" -// #include "watch_extint.h" +#include "watch_extint.h" #include "watch_tcc.h" // #include "watch_adc.h" #include "watch_gpio.h" diff --git a/watch-library/shared/watch/watch_extint.h b/watch-library/shared/watch/watch_extint.h index 84194e9a..df8ffaae 100644 --- a/watch-library/shared/watch/watch_extint.h +++ b/watch-library/shared/watch/watch_extint.h @@ -21,12 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _WATCH_EXTINT_H_INCLUDED -#define _WATCH_EXTINT_H_INCLUDED + +#pragma once + ////< @file watch_extint.h #include "watch.h" -#include "hal_ext_irq.h" +#include "eic.h" /** @addtogroup buttons Buttons & External Interrupts * @brief This section covers functions related to the three buttons: Light, Mode and Alarm, as well as @@ -40,14 +41,6 @@ */ /// @{ -///@brief An enum defining the types of interrupt trigger you wish to scan for. -typedef enum watch_interrupt_trigger { - INTERRUPT_TRIGGER_NONE = 0, - INTERRUPT_TRIGGER_RISING, - INTERRUPT_TRIGGER_FALLING, - INTERRUPT_TRIGGER_BOTH, -} watch_interrupt_trigger; - /// @brief Enables the external interrupt controller. void watch_enable_external_interrupts(void); @@ -62,7 +55,7 @@ void watch_disable_external_interrupts(void); * want to detect both rising and falling conditions (i.e. button down and button up), use * INTERRUPT_TRIGGER_BOTH and use watch_get_pin_level to check the pin level in your callback * to determine which condition caused the interrupt. - * @param pin One of BTN_LIGHT, BTN_MODE, BTN_ALARM, A0, A1, A3 or A4. If the pin parameter matches one of + * @param pin One of BTN_LIGHT, BTN_MODE, BTN_ALARM, A0, A1, A2, A3 or A4. If the pin parameter matches one of * the three button pins, this function will also enable an internal pull-down resistor. If * the pin parameter is A0-A4, you are responsible for setting any required pull configuration * using watch_enable_pull_up or watch_enable_pull_down. @@ -70,11 +63,8 @@ void watch_disable_external_interrupts(void); * @param trigger The condition on which you wish to trigger: rising, falling or both. * @note Pins A2 and A4 can also generate interrupts via the watch_register_extwake_callback function, which * will allow them to trigger even when the watch is in deep sleep mode. - * @warning As of now, A2 is not usable via the watch_register_interrupt_callback function. To enable an - * external interrupt on pin A2, use the watch_register_extwake_callback function. This issue will be - * addressed in a future revision of the watch library. + * @warning Pin A2 shares an interrupt channel with the Alarm button; use caution when configuring both. */ -void watch_register_interrupt_callback(const uint8_t pin, ext_irq_cb_t callback, watch_interrupt_trigger trigger); +void watch_register_interrupt_callback(const uint8_t pin, watch_cb_t callback, eic_interrupt_trigger trigger); /// @} -#endif