You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ut...@apache.org on 2018/02/26 10:22:57 UTC

[mynewt-core] 12/17: Added support for gpio_irq_...

This is an automated email from the ASF dual-hosted git repository.

utzig pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit 65781b1d2f8ac68d96f922868238a717c209286a
Author: Markus Lampert <ma...@bibi.ca>
AuthorDate: Fri Jan 19 20:32:49 2018 -0800

    Added support for gpio_irq_...
---
 hw/mcu/stm/stm32f3xx/src/hal_gpio.c | 313 ++++++++++++++++++++++++++++++++----
 1 file changed, 285 insertions(+), 28 deletions(-)

diff --git a/hw/mcu/stm/stm32f3xx/src/hal_gpio.c b/hw/mcu/stm/stm32f3xx/src/hal_gpio.c
index c34337e..020e769 100644
--- a/hw/mcu/stm/stm32f3xx/src/hal_gpio.c
+++ b/hw/mcu/stm/stm32f3xx/src/hal_gpio.c
@@ -27,11 +27,33 @@
 #include "hal/hal_gpio.h"
 #include "bsp/cmsis_nvic.h"
 #include "stm32f3xx.h"
+#include "stm32f3xx_hal_cortex.h"
 #include "stm32f3xx_hal_gpio.h"
 #include "stm32f3xx_hal_rcc.h"
 #include "mcu/stm32f3xx_mynewt_hal.h"
 #include <assert.h>
 
+ /* XXX: Notes
+ * 1) Right now, we are not disabling the NVIC interrupt source; we only
+ * disable the external interrupt from occurring. Dont think either way
+ * to do it is an issue... when we release we may want to disable the NVIC
+ *
+ * 2) investigate how thread safe these routines are. HAL_GPIO_Init, for
+ * example. Looks like if it gets interrupted while doing config an error
+ * may occur. Read/modify write could cause screw-ups.
+ *
+ * 3) Currently, this code does not change the interrupt priority of the
+ * external interrupt vectors in the NVIC. The application developer must
+ * decide on the priority level for each external interrupt and program that
+ * by using the CMSIS NVIC API  (NVIC_SetPriority and NVIC_SetPriorityGrouping)
+ *
+ * 4) The code probably does not handle "re-purposing" gpio very well.
+ * "Re-purposing" means changing a gpio from input to output, or calling
+ * gpio_init_in and expecting previously enabled interrupts to be stopped.
+ *
+ * 5) Possbily add access to HAL_GPIO_DeInit.
+ */
+
 /*
  * GPIO pin mapping
  *
@@ -59,6 +81,90 @@ static GPIO_TypeDef * const portmap[HAL_GPIO_PORT_COUNT] =
     HAL_GPIO_PORT_LIST
 };
 
+/* Storage for GPIO ISRS. */
+struct hal_gpio_irq_isr_t
+{
+    hal_gpio_irq_handler_t  isr;
+    void                    *arg;
+    volatile uint32_t       invoked;
+    volatile uint32_t       dropped;
+};
+struct hal_gpio_irq_isr_t hal_gpio_irq[16];
+
+void hal_gpio_ext_irq_handler(uint16_t index)
+{
+    uint32_t mask;
+
+    mask = HAL_GPIO_PIN(index);
+    if (__HAL_GPIO_EXTI_GET_IT(mask) != RESET) {
+        __HAL_GPIO_EXTI_CLEAR_IT(mask);
+      if (hal_gpio_irq[index].isr) {
+          ++hal_gpio_irq[index].invoked;
+          hal_gpio_irq[index].isr(hal_gpio_irq[index].arg);
+      } else {
+          ++hal_gpio_irq[index].dropped;
+      }
+    }
+}
+
+
+/* External interrupt 0 */
+static void
+hal_gpio_ext_irq0(void)
+{
+    hal_gpio_ext_irq_handler(0);
+}
+
+/* External interrupt 1 */
+static void
+hal_gpio_ext_irq1(void)
+{
+    hal_gpio_ext_irq_handler(1);
+}
+
+/* External interrupt 2 */
+static void
+hal_gpio_ext_irq2(void)
+{
+    hal_gpio_ext_irq_handler(2);
+}
+
+/* External interrupt 3 */
+static void
+hal_gpio_ext_irq3(void)
+{
+    hal_gpio_ext_irq_handler(3);
+}
+
+/* External interrupt 4 */
+static void
+hal_gpio_ext_irq4(void)
+{
+    hal_gpio_ext_irq_handler(4);
+}
+
+/* External interrupt 9 through 5 */
+static void
+hal_gpio_ext_irq9_5(void)
+{
+    int index;
+
+    for (index = 5; index <= 9; ++index) {
+        hal_gpio_ext_irq_handler(index);
+    }
+}
+
+/* External interrupt 15 through 10 */
+static void
+hal_gpio_ext_irq15_10(void)
+{
+    int index;
+
+    for (index = 10; index <= 15; ++index) {
+        hal_gpio_ext_irq_handler(index);
+    }
+}
+
 /**
  * hal gpio clk enable
  *
@@ -151,19 +257,76 @@ hal_gpio_clk_enable(uint32_t port_idx)
     }
 }
 
-
 /**
- * hal gpio init
+ * hal gpio pin to irq
  *
- * Called to initialize a gpio.
+ * Converts the logical pin number to the IRQ number associated with the
+ * external interrupt for that particular GPIO.
  *
  * @param pin
- * @param cfg
  *
- * @return int
+ * @return IRQn_Type
  */
-int
-hal_gpio_init_stm(int pin, GPIO_InitTypeDef *cfg)
+static IRQn_Type
+hal_gpio_pin_to_irq(int pin)
+{
+    int index;
+    IRQn_Type irqn;
+
+    index = HAL_GPIO_PIN_NUM(pin);
+    if (index <= 4) {
+        irqn = EXTI0_IRQn + index;
+    } else if (index <=  9) {
+        irqn = EXTI9_5_IRQn;
+    } else {
+        irqn = EXTI15_10_IRQn;
+    }
+
+    return irqn;
+}
+
+static void
+hal_gpio_set_nvic(IRQn_Type irqn)
+{
+    void (*isr)(void);
+
+    switch (irqn) {
+    case EXTI0_IRQn:
+        isr = hal_gpio_ext_irq0;
+        break;
+    case EXTI1_IRQn:
+        isr = hal_gpio_ext_irq1;
+        break;
+    case EXTI2_TSC_IRQn:
+        isr = hal_gpio_ext_irq2;
+        break;
+    case EXTI3_IRQn:
+        isr = hal_gpio_ext_irq3;
+        break;
+    case EXTI4_IRQn:
+        isr = hal_gpio_ext_irq4;
+        break;
+    case EXTI9_5_IRQn:
+        isr = hal_gpio_ext_irq9_5;
+        break;
+    case EXTI15_10_IRQn:
+        isr = hal_gpio_ext_irq15_10;
+        break;
+    default:
+        assert(0);
+        break;
+    }
+
+    /* Set isr in vector table if not yet set */
+    if (NVIC_GetVector(irqn) != (uint32_t)isr) {
+        NVIC_SetVector(irqn, (uint32_t)isr);
+        NVIC_EnableIRQ(irqn);
+    }
+}
+
+
+static int
+hal_gpio_init_stm32_int(int pin, GPIO_InitTypeDef *cfg, GPIO_PinState *state)
 {
     int port;
     uint32_t mcu_gpio_pin;
@@ -180,13 +343,33 @@ hal_gpio_init_stm(int pin, GPIO_InitTypeDef *cfg)
     /* Enable the GPIO clock */
     hal_gpio_clk_enable(port);
 
-    /* Initialize pin as an input, setting proper mode */
+    /* Write initial state if required */
+    if (NULL != state) {
+        HAL_GPIO_WritePin(portmap[port], mcu_gpio_pin, *state);
+    }
+
+    /* Initialize pin setting proper mode */
     HAL_GPIO_Init(portmap[port], cfg);
 
     return 0;
 }
 
 /**
+ * hal gpio init
+ *
+ * Called to initialize a gpio.
+ *
+ * @param pin
+ * @param cfg
+ *
+ * @return int
+ */
+int
+hal_gpio_init_stm(int pin, GPIO_InitTypeDef *cfg)
+{
+  return hal_gpio_init_stm32_int(pin, cfg, NULL);
+}
+/**
  * hal gpio deinit
  *
  * Called to deinitialize a gpio.
@@ -253,19 +436,16 @@ hal_gpio_init_in(int pin, hal_gpio_pull_t pull)
  */
 int hal_gpio_init_out(int pin, int val)
 {
-    int rc;
     GPIO_InitTypeDef cfg;
+    GPIO_PinState state;
 
     cfg.Mode  = GPIO_MODE_OUTPUT_PP;
     cfg.Pull  = GPIO_NOPULL;
     cfg.Speed = GPIO_SPEED_FREQ_HIGH;
 
-    rc = hal_gpio_init_stm(pin, &cfg);
-    if (HAL_OK == rc) {
-        hal_gpio_write(pin, val);
-    }
+    state = val ? GPIO_PIN_SET : GPIO_PIN_RESET;
 
-    return rc;
+    return hal_gpio_init_stm32_int(pin, &cfg, &state);
 }
 
 /**
@@ -368,8 +548,6 @@ int hal_gpio_toggle(int pin)
  *
  * Initialize an external interrupt on a gpio pin
  *
- * irq support not implemented yet.
- *
  * @param pin       Pin number to enable gpio.
  * @param handler   Interrupt handler
  * @param arg       Argument to pass to interrupt handler
@@ -382,50 +560,129 @@ int
 hal_gpio_irq_init(int pin, hal_gpio_irq_handler_t handler, void *arg,
                   hal_gpio_irq_trig_t trig, hal_gpio_pull_t pull)
 {
-    (void)pin;
-    (void)handler;
-    (void)arg;
-    (void)trig;
-    (void)pull;
+    int rc;
+    int irqn;
+    int index;
+    uint32_t pin_mask;
+    uint32_t mode;
+    GPIO_InitTypeDef cfg;
+
+    /* Configure the gpio for an external interrupt */
+    rc = 0;
+    switch (trig) {
+    case HAL_GPIO_TRIG_NONE:
+        rc = -1;
+        break;
+    case HAL_GPIO_TRIG_RISING:
+        mode = GPIO_MODE_IT_RISING;
+        break;
+    case HAL_GPIO_TRIG_FALLING:
+        mode = GPIO_MODE_IT_FALLING;
+        break;
+    case HAL_GPIO_TRIG_BOTH:
+        mode = GPIO_MODE_IT_RISING_FALLING;
+        break;
+    case HAL_GPIO_TRIG_LOW:
+        rc = -1;
+        break;
+    case HAL_GPIO_TRIG_HIGH:
+        rc = -1;
+        break;
+    default:
+        rc = -1;
+        break;
+    }
 
-    return -1;
+    /* Check to make sure no error has occurred */
+    if (!rc) {
+        /* Disable interrupt and clear any pending */
+        hal_gpio_irq_disable(pin);
+        pin_mask = HAL_GPIO_PIN(pin);
+        __HAL_GPIO_EXTI_CLEAR_FLAG(pin_mask);
+
+        /* Set the gpio irq handler */
+        index = HAL_GPIO_PIN_NUM(pin);
+        hal_gpio_irq[index].isr = handler;
+        hal_gpio_irq[index].arg = arg;
+        hal_gpio_irq[index].invoked = 0;
+
+        /* Configure the GPIO */
+        cfg.Mode = mode;
+        cfg.Pull = pull;
+        rc = hal_gpio_init_stm(pin, &cfg);
+        if (!rc) {
+            /* Enable interrupt vector in NVIC */
+            irqn = hal_gpio_pin_to_irq(pin);
+            hal_gpio_set_nvic(irqn);
+        }
+    }
+
+    return rc;
 }
 
 /**
  * gpio irq release
  *
- * irq support not implemented yet.
+ * No longer interrupt when something occurs on the pin. NOTE: this function
+ * does not change the GPIO push/pull setting nor does it change the
+ * SYSCFG EXTICR registers. It also does not disable the NVIC interrupt enable
+ * setting for the irq.
  *
  * @param pin
  */
 void
 hal_gpio_irq_release(int pin)
 {
-    (void)pin;
+    int index;
+    uint32_t pin_mask;
+
+    /* Disable the interrupt */
+    hal_gpio_irq_disable(pin);
+
+    /* Clear any pending interrupts */
+    pin_mask = HAL_GPIO_PIN(pin);
+    __HAL_GPIO_EXTI_CLEAR_FLAG(pin_mask);
+
+    /* Clear out the irq handler */
+    index = HAL_GPIO_PIN_NUM(pin);
+    hal_gpio_irq[index].arg = NULL;
+    hal_gpio_irq[index].isr = NULL;
 }
 
 /**
  * gpio irq enable
  *
- * irq support not implemented yet.
+ * Enable the irq on the specified pin
  *
  * @param pin
  */
 void
 hal_gpio_irq_enable(int pin)
 {
-    (void)pin;
+    uint32_t ctx;
+    uint32_t mask;
+
+    mask = HAL_GPIO_PIN(pin);
+
+    __HAL_DISABLE_INTERRUPTS(ctx);
+    EXTI->IMR |= mask;
+    __HAL_ENABLE_INTERRUPTS(ctx);
 }
 
 /**
  * gpio irq disable
  *
- * irq support not implemented yet.
  *
  * @param pin
  */
 void
 hal_gpio_irq_disable(int pin)
 {
-    (void)pin;
+    uint32_t ctx;
+    uint32_t mask;
+
+    mask = HAL_GPIO_PIN(pin);
+    __HAL_DISABLE_INTERRUPTS(ctx);
+    EXTI->IMR &= ~mask;
+    __HAL_ENABLE_INTERRUPTS(ctx);
 }

-- 
To stop receiving notification emails like this one, please contact
utzig@apache.org.