aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_gpiote.c
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_gpiote.c')
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_gpiote.c826
1 files changed, 826 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_gpiote.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_gpiote.c
new file mode 100644
index 0000000..8412b60
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_gpiote.c
@@ -0,0 +1,826 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <nrfx.h>
+
+#if NRFX_CHECK(NRFX_GPIOTE_ENABLED)
+
+#include <nrfx_gpiote.h>
+#include "nrf_bitmask.h"
+#include <string.h>
+
+#define NRFX_LOG_MODULE GPIOTE
+#include <nrfx_log.h>
+
+
+#define FORBIDDEN_HANDLER_ADDRESS ((nrfx_gpiote_evt_handler_t)UINT32_MAX)
+#define PIN_NOT_USED (-1)
+#define PIN_USED (-2)
+#define NO_CHANNELS (-1)
+#define SENSE_FIELD_POS (6)
+#define SENSE_FIELD_MASK (0xC0)
+
+/**
+ * @brief Macro for converting task-event index to an address of an event register.
+ *
+ * Macro utilizes the fact that registers are grouped together in ascending order.
+ */
+#define TE_IDX_TO_EVENT_ADDR(idx) (nrf_gpiote_events_t)((uint32_t)NRF_GPIOTE_EVENTS_IN_0 + \
+ (sizeof(uint32_t) * (idx)))
+
+/**
+ * @brief Macro for converting task-event index of OUT task to an address of a task register.
+ *
+ * Macro utilizes the fact that registers are grouped together in ascending order.
+ */
+#define TE_OUT_IDX_TO_TASK_ADDR(idx) (nrf_gpiote_tasks_t)((uint32_t)NRF_GPIOTE_TASKS_OUT_0 + \
+ (sizeof(uint32_t) * (idx)))
+
+#if defined(GPIOTE_FEATURE_SET_PRESENT) || defined(__NRFX_DOXYGEN__)
+/**
+ * @brief Macro for converting task-event index of SET task to an address of a task register.
+ *
+ * Macro utilizes the fact that registers are grouped together in ascending order.
+ */
+#define TE_SET_IDX_TO_TASK_ADDR(idx) (nrf_gpiote_tasks_t)((uint32_t)NRF_GPIOTE_TASKS_SET_0 + \
+ (sizeof(uint32_t) * (idx)))
+
+#endif // defined(GPIOTE_FEATURE_SET_PRESENT) || defined(__NRFX_DOXYGEN__)
+
+#if defined(GPIOTE_FEATURE_CLR_PRESENT) || defined(__NRFX_DOXYGEN__)
+/**
+ * @brief Macro for converting task-event index of CLR task to an address of a task register.
+ *
+ * Macro utilizes the fact that registers are grouped together in ascending order.
+ */
+#define TE_CLR_IDX_TO_TASK_ADDR(idx) (nrf_gpiote_tasks_t)((uint32_t)NRF_GPIOTE_TASKS_CLR_0 + \
+ (sizeof(uint32_t) * (idx)))
+
+#endif // defined(GPIOTE_FEATURE_CLR_PRESENT) || defined(__NRFX_DOXYGEN__)
+
+/*lint -save -e571*/ /* Suppress "Warning 571: Suspicious cast" */
+typedef struct
+{
+ nrfx_gpiote_evt_handler_t handlers[GPIOTE_CH_NUM + NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS];
+ int8_t pin_assignments[NUMBER_OF_PINS];
+ int8_t port_handlers_pins[NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS];
+ uint8_t configured_pins[((NUMBER_OF_PINS)+7) / 8];
+ nrfx_drv_state_t state;
+} gpiote_control_block_t;
+
+static gpiote_control_block_t m_cb;
+
+__STATIC_INLINE bool pin_in_use(uint32_t pin)
+{
+ return (m_cb.pin_assignments[pin] != PIN_NOT_USED);
+}
+
+
+__STATIC_INLINE bool pin_in_use_as_non_task_out(uint32_t pin)
+{
+ return (m_cb.pin_assignments[pin] == PIN_USED);
+}
+
+
+__STATIC_INLINE bool pin_in_use_by_te(uint32_t pin)
+{
+ return (m_cb.pin_assignments[pin] >= 0 && m_cb.pin_assignments[pin] < GPIOTE_CH_NUM) ?
+ true : false;
+}
+
+
+__STATIC_INLINE bool pin_in_use_by_port(uint32_t pin)
+{
+ return (m_cb.pin_assignments[pin] >= GPIOTE_CH_NUM);
+}
+
+
+__STATIC_INLINE bool pin_in_use_by_gpiote(uint32_t pin)
+{
+ return (m_cb.pin_assignments[pin] >= 0);
+}
+
+
+__STATIC_INLINE void pin_in_use_by_te_set(uint32_t pin,
+ uint32_t channel_id,
+ nrfx_gpiote_evt_handler_t handler,
+ bool is_channel)
+{
+ m_cb.pin_assignments[pin] = channel_id;
+ m_cb.handlers[channel_id] = handler;
+ if (!is_channel)
+ {
+ m_cb.port_handlers_pins[channel_id - GPIOTE_CH_NUM] = (int8_t)pin;
+ }
+}
+
+
+__STATIC_INLINE void pin_in_use_set(uint32_t pin)
+{
+ m_cb.pin_assignments[pin] = PIN_USED;
+}
+
+
+__STATIC_INLINE void pin_in_use_clear(uint32_t pin)
+{
+ m_cb.pin_assignments[pin] = PIN_NOT_USED;
+}
+
+
+__STATIC_INLINE void pin_configured_set(uint32_t pin)
+{
+ nrf_bitmask_bit_set(pin, m_cb.configured_pins);
+}
+
+__STATIC_INLINE void pin_configured_clear(uint32_t pin)
+{
+ nrf_bitmask_bit_clear(pin, m_cb.configured_pins);
+}
+
+__STATIC_INLINE bool pin_configured_check(uint32_t pin)
+{
+ return 0 != nrf_bitmask_bit_is_set(pin, m_cb.configured_pins);
+}
+
+__STATIC_INLINE int8_t channel_port_get(uint32_t pin)
+{
+ return m_cb.pin_assignments[pin];
+}
+
+
+__STATIC_INLINE nrfx_gpiote_evt_handler_t channel_handler_get(uint32_t channel)
+{
+ return m_cb.handlers[channel];
+}
+
+
+static int8_t channel_port_alloc(uint32_t pin, nrfx_gpiote_evt_handler_t handler, bool channel)
+{
+ int8_t channel_id = NO_CHANNELS;
+ uint32_t i;
+
+ uint32_t start_idx = channel ? 0 : GPIOTE_CH_NUM;
+ uint32_t end_idx =
+ channel ? GPIOTE_CH_NUM : (GPIOTE_CH_NUM + NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS);
+
+ // critical section
+
+ for (i = start_idx; i < end_idx; i++)
+ {
+ if (m_cb.handlers[i] == FORBIDDEN_HANDLER_ADDRESS)
+ {
+ pin_in_use_by_te_set(pin, i, handler, channel);
+ channel_id = i;
+ break;
+ }
+ }
+ // critical section
+ return channel_id;
+}
+
+
+static void channel_free(uint8_t channel_id)
+{
+ m_cb.handlers[channel_id] = FORBIDDEN_HANDLER_ADDRESS;
+ if (channel_id >= GPIOTE_CH_NUM)
+ {
+ m_cb.port_handlers_pins[channel_id - GPIOTE_CH_NUM] = (int8_t)PIN_NOT_USED;
+ }
+}
+
+
+nrfx_err_t nrfx_gpiote_init(void)
+{
+ nrfx_err_t err_code;
+
+ if (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED)
+ {
+ err_code = NRFX_ERROR_INVALID_STATE;
+ NRFX_LOG_WARNING("Function: %s, error code: %s.",
+ __func__,
+ NRFX_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+
+ uint8_t i;
+
+ for (i = 0; i < NUMBER_OF_PINS; i++)
+ {
+ pin_in_use_clear(i);
+ }
+
+ for (i = 0; i < (GPIOTE_CH_NUM + NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS); i++)
+ {
+ channel_free(i);
+ }
+
+ memset(m_cb.configured_pins, 0, sizeof(m_cb.configured_pins));
+
+ NRFX_IRQ_PRIORITY_SET(GPIOTE_IRQn, NRFX_GPIOTE_CONFIG_IRQ_PRIORITY);
+ NRFX_IRQ_ENABLE(GPIOTE_IRQn);
+ nrf_gpiote_event_clear(NRF_GPIOTE_EVENTS_PORT);
+ nrf_gpiote_int_enable(GPIOTE_INTENSET_PORT_Msk);
+ m_cb.state = NRFX_DRV_STATE_INITIALIZED;
+
+ err_code = NRFX_SUCCESS;
+ NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+}
+
+
+bool nrfx_gpiote_is_init(void)
+{
+ return (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED) ? true : false;
+}
+
+
+void nrfx_gpiote_uninit(void)
+{
+ NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
+
+ uint32_t i;
+
+ for (i = 0; i < NUMBER_OF_PINS; i++)
+ {
+ if (pin_in_use_as_non_task_out(i))
+ {
+ nrfx_gpiote_out_uninit(i);
+ }
+ else if ( pin_in_use_by_gpiote(i))
+ {
+ /* Disable gpiote_in is having the same effect on out pin as gpiote_out_uninit on
+ * so it can be called on all pins used by GPIOTE.
+ */
+ nrfx_gpiote_in_uninit(i);
+ }
+ }
+ m_cb.state = NRFX_DRV_STATE_UNINITIALIZED;
+ NRFX_LOG_INFO("Uninitialized.");
+}
+
+
+nrfx_err_t nrfx_gpiote_out_init(nrfx_gpiote_pin_t pin,
+ nrfx_gpiote_out_config_t const * p_config)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_INITIALIZED);
+ NRFX_ASSERT(p_config);
+
+ nrfx_err_t err_code = NRFX_SUCCESS;
+
+ if (pin_in_use(pin))
+ {
+ err_code = NRFX_ERROR_INVALID_STATE;
+ }
+ else
+ {
+ if (p_config->task_pin)
+ {
+ int8_t channel = channel_port_alloc(pin, NULL, true);
+
+ if (channel != NO_CHANNELS)
+ {
+ nrf_gpiote_task_configure((uint32_t)channel,
+ pin,
+ p_config->action,
+ p_config->init_state);
+ }
+ else
+ {
+ err_code = NRFX_ERROR_NO_MEM;
+ }
+ }
+ else
+ {
+ pin_in_use_set(pin);
+ }
+
+ if (err_code == NRFX_SUCCESS)
+ {
+ if (p_config->init_state == NRF_GPIOTE_INITIAL_VALUE_HIGH)
+ {
+ nrf_gpio_pin_set(pin);
+ }
+ else
+ {
+ nrf_gpio_pin_clear(pin);
+ }
+
+ nrf_gpio_cfg_output(pin);
+ pin_configured_set(pin);
+ }
+ }
+
+ NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+}
+
+
+void nrfx_gpiote_out_uninit(nrfx_gpiote_pin_t pin)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use(pin));
+
+ if (pin_in_use_by_te(pin))
+ {
+ channel_free((uint8_t)channel_port_get(pin));
+ nrf_gpiote_te_default((uint32_t)channel_port_get(pin));
+ }
+ pin_in_use_clear(pin);
+
+ if (pin_configured_check(pin))
+ {
+ nrf_gpio_cfg_default(pin);
+ pin_configured_clear(pin);
+ }
+}
+
+
+void nrfx_gpiote_out_set(nrfx_gpiote_pin_t pin)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use(pin));
+ NRFX_ASSERT(!pin_in_use_by_te(pin));
+
+ nrf_gpio_pin_set(pin);
+}
+
+
+void nrfx_gpiote_out_clear(nrfx_gpiote_pin_t pin)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use(pin));
+ NRFX_ASSERT(!pin_in_use_by_te(pin));
+
+ nrf_gpio_pin_clear(pin);
+}
+
+
+void nrfx_gpiote_out_toggle(nrfx_gpiote_pin_t pin)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use(pin));
+ NRFX_ASSERT(!pin_in_use_by_te(pin));
+
+ nrf_gpio_pin_toggle(pin);
+}
+
+
+void nrfx_gpiote_out_task_enable(nrfx_gpiote_pin_t pin)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use(pin));
+ NRFX_ASSERT(pin_in_use_by_te(pin));
+
+ nrf_gpiote_task_enable((uint32_t)m_cb.pin_assignments[pin]);
+}
+
+
+void nrfx_gpiote_out_task_disable(nrfx_gpiote_pin_t pin)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use(pin));
+ NRFX_ASSERT(pin_in_use_by_te(pin));
+
+ nrf_gpiote_task_disable((uint32_t)m_cb.pin_assignments[pin]);
+}
+
+
+uint32_t nrfx_gpiote_out_task_addr_get(nrfx_gpiote_pin_t pin)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use_by_te(pin));
+
+ nrf_gpiote_tasks_t task = TE_OUT_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin));
+ return nrf_gpiote_task_addr_get(task);
+}
+
+
+#if defined(GPIOTE_FEATURE_SET_PRESENT)
+uint32_t nrfx_gpiote_set_task_addr_get(nrfx_gpiote_pin_t pin)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use_by_te(pin));
+
+ nrf_gpiote_tasks_t task = TE_SET_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin));
+ return nrf_gpiote_task_addr_get(task);
+}
+
+
+#endif // defined(GPIOTE_FEATURE_SET_PRESENT)
+
+#if defined(GPIOTE_FEATURE_CLR_PRESENT)
+uint32_t nrfx_gpiote_clr_task_addr_get(nrfx_gpiote_pin_t pin)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use_by_te(pin));
+
+ nrf_gpiote_tasks_t task = TE_CLR_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin));
+ return nrf_gpiote_task_addr_get(task);
+}
+
+
+#endif // defined(GPIOTE_FEATURE_CLR_PRESENT)
+
+void nrfx_gpiote_out_task_force(nrfx_gpiote_pin_t pin, uint8_t state)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use(pin));
+ NRFX_ASSERT(pin_in_use_by_te(pin));
+
+ nrf_gpiote_outinit_t init_val =
+ state ? NRF_GPIOTE_INITIAL_VALUE_HIGH : NRF_GPIOTE_INITIAL_VALUE_LOW;
+ nrf_gpiote_task_force((uint32_t)m_cb.pin_assignments[pin], init_val);
+}
+
+
+void nrfx_gpiote_out_task_trigger(nrfx_gpiote_pin_t pin)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use(pin));
+ NRFX_ASSERT(pin_in_use_by_te(pin));
+
+ nrf_gpiote_tasks_t task = TE_OUT_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin));
+ nrf_gpiote_task_set(task);
+}
+
+
+#if defined(GPIOTE_FEATURE_SET_PRESENT)
+void nrfx_gpiote_set_task_trigger(nrfx_gpiote_pin_t pin)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use(pin));
+ NRFX_ASSERT(pin_in_use_by_te(pin));
+
+ nrf_gpiote_tasks_t task = TE_SET_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin));
+ nrf_gpiote_task_set(task);
+}
+
+
+#endif // defined(GPIOTE_FEATURE_SET_PRESENT)
+
+#if defined(GPIOTE_FEATURE_CLR_PRESENT)
+void nrfx_gpiote_clr_task_trigger(nrfx_gpiote_pin_t pin)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use(pin));
+ NRFX_ASSERT(pin_in_use_by_te(pin));
+
+ nrf_gpiote_tasks_t task = TE_CLR_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin));
+ nrf_gpiote_task_set(task);
+}
+
+
+#endif // defined(GPIOTE_FEATURE_CLR_PRESENT)
+
+nrfx_err_t nrfx_gpiote_in_init(nrfx_gpiote_pin_t pin,
+ nrfx_gpiote_in_config_t const * p_config,
+ nrfx_gpiote_evt_handler_t evt_handler)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ nrfx_err_t err_code = NRFX_SUCCESS;
+
+ /* Only one GPIOTE channel can be assigned to one physical pin. */
+ if (pin_in_use_by_gpiote(pin))
+ {
+ err_code = NRFX_ERROR_INVALID_STATE;
+ }
+ else
+ {
+ int8_t channel = channel_port_alloc(pin, evt_handler, p_config->hi_accuracy);
+ if (channel != NO_CHANNELS)
+ {
+ if (!p_config->skip_gpio_setup)
+ {
+ if (p_config->is_watcher)
+ {
+ nrf_gpio_cfg_watcher(pin);
+ }
+ else
+ {
+ nrf_gpio_cfg_input(pin, p_config->pull);
+ }
+ pin_configured_set(pin);
+ }
+
+ if (p_config->hi_accuracy)
+ {
+ nrf_gpiote_event_configure((uint32_t)channel, pin, p_config->sense);
+ }
+ else
+ {
+ m_cb.port_handlers_pins[channel -
+ GPIOTE_CH_NUM] |= (p_config->sense) << SENSE_FIELD_POS;
+ }
+ }
+ else
+ {
+ err_code = NRFX_ERROR_NO_MEM;
+ }
+ }
+
+ NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+}
+
+void nrfx_gpiote_in_event_enable(nrfx_gpiote_pin_t pin, bool int_enable)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use_by_gpiote(pin));
+ if (pin_in_use_by_port(pin))
+ {
+ uint8_t pin_and_sense = (uint8_t)
+ m_cb.port_handlers_pins[channel_port_get(pin) - GPIOTE_CH_NUM];
+ nrf_gpiote_polarity_t polarity =
+ (nrf_gpiote_polarity_t)(pin_and_sense >> SENSE_FIELD_POS);
+ nrf_gpio_pin_sense_t sense;
+ if (polarity == NRF_GPIOTE_POLARITY_TOGGLE)
+ {
+ /* read current pin state and set for next sense to oposit */
+ sense = (nrf_gpio_pin_read(pin)) ?
+ NRF_GPIO_PIN_SENSE_LOW : NRF_GPIO_PIN_SENSE_HIGH;
+ }
+ else
+ {
+ sense = (polarity == NRF_GPIOTE_POLARITY_LOTOHI) ?
+ NRF_GPIO_PIN_SENSE_HIGH : NRF_GPIO_PIN_SENSE_LOW;
+ }
+ nrf_gpio_cfg_sense_set(pin, sense);
+ }
+ else if (pin_in_use_by_te(pin))
+ {
+ int32_t channel = (int32_t)channel_port_get(pin);
+ nrf_gpiote_events_t event = TE_IDX_TO_EVENT_ADDR((uint32_t)channel);
+
+ nrf_gpiote_event_enable((uint32_t)channel);
+
+ nrf_gpiote_event_clear(event);
+ if (int_enable)
+ {
+ nrfx_gpiote_evt_handler_t handler = channel_handler_get((uint32_t)channel_port_get(pin));
+ // Enable the interrupt only if event handler was provided.
+ if (handler)
+ {
+ nrf_gpiote_int_enable(1 << channel);
+ }
+ }
+ }
+}
+
+
+void nrfx_gpiote_in_event_disable(nrfx_gpiote_pin_t pin)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use_by_gpiote(pin));
+ if (pin_in_use_by_port(pin))
+ {
+ nrf_gpio_cfg_sense_set(pin, NRF_GPIO_PIN_NOSENSE);
+ }
+ else if (pin_in_use_by_te(pin))
+ {
+ int32_t channel = (int32_t)channel_port_get(pin);
+ nrf_gpiote_event_disable((uint32_t)channel);
+ nrf_gpiote_int_disable(1 << channel);
+ }
+}
+
+
+void nrfx_gpiote_in_uninit(nrfx_gpiote_pin_t pin)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use_by_gpiote(pin));
+ nrfx_gpiote_in_event_disable(pin);
+ if (pin_in_use_by_te(pin))
+ {
+ nrf_gpiote_te_default((uint32_t)channel_port_get(pin));
+ }
+ if (pin_configured_check(pin))
+ {
+ nrf_gpio_cfg_default(pin);
+ pin_configured_clear(pin);
+ }
+ channel_free((uint8_t)channel_port_get(pin));
+ pin_in_use_clear(pin);
+}
+
+
+bool nrfx_gpiote_in_is_set(nrfx_gpiote_pin_t pin)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ return nrf_gpio_pin_read(pin) ? true : false;
+}
+
+
+uint32_t nrfx_gpiote_in_event_addr_get(nrfx_gpiote_pin_t pin)
+{
+ NRFX_ASSERT(pin < NUMBER_OF_PINS);
+ NRFX_ASSERT(pin_in_use_by_port(pin) || pin_in_use_by_te(pin));
+
+ nrf_gpiote_events_t event = NRF_GPIOTE_EVENTS_PORT;
+
+ if (pin_in_use_by_te(pin))
+ {
+ event = TE_IDX_TO_EVENT_ADDR((uint32_t)channel_port_get(pin));
+ }
+ return nrf_gpiote_event_addr_get(event);
+}
+
+
+void nrfx_gpiote_irq_handler(void)
+{
+ uint32_t status = 0;
+ uint32_t input[GPIO_COUNT] = {0};
+
+ /* collect status of all GPIOTE pin events. Processing is done once all are collected and cleared.*/
+ uint32_t i;
+ nrf_gpiote_events_t event = NRF_GPIOTE_EVENTS_IN_0;
+ uint32_t mask = (uint32_t)NRF_GPIOTE_INT_IN0_MASK;
+
+ for (i = 0; i < GPIOTE_CH_NUM; i++)
+ {
+ if (nrf_gpiote_event_is_set(event) && nrf_gpiote_int_is_enabled(mask))
+ {
+ nrf_gpiote_event_clear(event);
+ status |= mask;
+ }
+ mask <<= 1;
+ /* Incrementing to next event, utilizing the fact that events are grouped together
+ * in ascending order. */
+ event = (nrf_gpiote_events_t)((uint32_t)event + sizeof(uint32_t));
+ }
+
+ /* collect PORT status event, if event is set read pins state. Processing is postponed to the
+ * end of interrupt. */
+ if (nrf_gpiote_event_is_set(NRF_GPIOTE_EVENTS_PORT))
+ {
+ nrf_gpiote_event_clear(NRF_GPIOTE_EVENTS_PORT);
+ status |= (uint32_t)NRF_GPIOTE_INT_PORT_MASK;
+ nrf_gpio_ports_read(0, GPIO_COUNT, input);
+ }
+
+ /* Process pin events. */
+ if (status & NRF_GPIOTE_INT_IN_MASK)
+ {
+ mask = (uint32_t)NRF_GPIOTE_INT_IN0_MASK;
+
+ for (i = 0; i < GPIOTE_CH_NUM; i++)
+ {
+ if (mask & status)
+ {
+ nrfx_gpiote_pin_t pin = nrf_gpiote_event_pin_get(i);
+ NRFX_LOG_DEBUG("Event in number: %d.", i);
+ nrf_gpiote_polarity_t polarity = nrf_gpiote_event_polarity_get(i);
+ nrfx_gpiote_evt_handler_t handler = channel_handler_get(i);
+ NRFX_LOG_DEBUG("Pin: %d, polarity: %d.", pin, polarity);
+ if (handler)
+ {
+ handler(pin, polarity);
+ }
+ }
+ mask <<= 1;
+ }
+ }
+
+ if (status & (uint32_t)NRF_GPIOTE_INT_PORT_MASK)
+ {
+ /* Process port event. */
+ uint32_t port_idx;
+ uint8_t repeat = 0;
+ uint32_t toggle_mask[GPIO_COUNT] = {0};
+ uint32_t pins_to_check[GPIO_COUNT];
+
+ // Faster way of doing memset because in interrupt context.
+ for (port_idx = 0; port_idx < GPIO_COUNT; port_idx++)
+ {
+ pins_to_check[port_idx] = 0xFFFFFFFF;
+ }
+
+ do
+ {
+ repeat = 0;
+
+ for (i = 0; i < NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS; i++)
+ {
+ uint8_t pin_and_sense = (uint8_t)m_cb.port_handlers_pins[i];
+ nrfx_gpiote_pin_t pin = (pin_and_sense & ~SENSE_FIELD_MASK);
+
+ if ((m_cb.port_handlers_pins[i] != PIN_NOT_USED)
+ && nrf_bitmask_bit_is_set(pin, pins_to_check))
+ {
+ nrf_gpiote_polarity_t polarity =
+ (nrf_gpiote_polarity_t)((pin_and_sense &
+ SENSE_FIELD_MASK) >> SENSE_FIELD_POS);
+ nrfx_gpiote_evt_handler_t handler =
+ channel_handler_get((uint32_t)channel_port_get(pin));
+ if (handler || (polarity == NRF_GPIOTE_POLARITY_TOGGLE))
+ {
+ if (polarity == NRF_GPIOTE_POLARITY_TOGGLE)
+ {
+ nrf_bitmask_bit_set(pin, toggle_mask);
+ }
+ nrf_gpio_pin_sense_t sense = nrf_gpio_pin_sense_get(pin);
+ uint32_t pin_state = nrf_bitmask_bit_is_set(pin, input);
+ if ((pin_state && (sense == NRF_GPIO_PIN_SENSE_HIGH)) ||
+ (!pin_state && (sense == NRF_GPIO_PIN_SENSE_LOW)) )
+ {
+ NRFX_LOG_DEBUG("PORT event for pin: %d, polarity: %d.", pin, polarity);
+ if (polarity == NRF_GPIOTE_POLARITY_TOGGLE)
+ {
+ nrf_gpio_pin_sense_t next_sense =
+ (sense == NRF_GPIO_PIN_SENSE_HIGH) ?
+ NRF_GPIO_PIN_SENSE_LOW :
+ NRF_GPIO_PIN_SENSE_HIGH;
+ nrf_gpio_cfg_sense_set(pin, next_sense);
+ ++repeat;
+
+ }
+ if (handler)
+ {
+ handler(pin, polarity);
+ }
+ }
+ }
+ }
+ }
+
+ if (repeat)
+ {
+ // When one of the pins in low-accuracy and toggle mode becomes active,
+ // it's sense mode is inverted to clear the internal SENSE signal.
+ // State of any other enabled low-accuracy input in toggle mode must be checked
+ // explicitly, because it does not trigger the interrput when SENSE signal is active.
+ // For more information about SENSE functionality, refer to Product Specification.
+
+ uint32_t new_input[GPIO_COUNT];
+ bool input_unchanged = true;
+ nrf_gpio_ports_read(0, GPIO_COUNT, new_input);
+
+ // Faster way of doing memcmp because in interrupt context.
+ for (port_idx = 0; port_idx < GPIO_COUNT; port_idx++)
+ {
+ if (new_input[port_idx] != input[port_idx])
+ {
+ input_unchanged = false;
+ break;
+ }
+ }
+
+ if (input_unchanged)
+ {
+ // No change.
+ repeat = 0;
+ }
+ else
+ {
+ // Faster way of doing memcpy because in interrupt context.
+ for (port_idx = 0; port_idx < GPIO_COUNT; port_idx++)
+ {
+ input[port_idx] = new_input[port_idx];
+ pins_to_check[port_idx] = toggle_mask[port_idx];
+ }
+ }
+ }
+ }
+ while (repeat);
+ }
+}
+
+
+/*lint -restore*/
+#endif // NRFX_CHECK(NRFX_GPIOTE_ENABLED)