From 07dd41d49d84d1c294165e4a94d60a36d8db6211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Wed, 4 Jun 2025 08:34:40 +0200 Subject: [PATCH] nrfx: drivers: gpiote: Add support for GPIOTE0 on cpurad MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GPIOTE0 on radio core is special in a way that: - PORT event is not supported - Channel id is fixed to pin - Various interrupt register that shall be used (index 0 for GPIOTE0 and index 2 for GPIOTE130) Signed-off-by: Krzysztof Chruściński --- nrfx/drivers/src/nrfx_gpiote.c | 193 +++++++++++++++++++++++++-------- nrfx/haly/nrfy_gpiote.h | 7 +- 2 files changed, 155 insertions(+), 45 deletions(-) diff --git a/nrfx/drivers/src/nrfx_gpiote.c b/nrfx/drivers/src/nrfx_gpiote.c index 547db52d..635c87d2 100644 --- a/nrfx/drivers/src/nrfx_gpiote.c +++ b/nrfx/drivers/src/nrfx_gpiote.c @@ -190,15 +190,28 @@ typedef struct /* Mask for tracking event handler entries allocation. */ nrfx_atomic_t available_evt_handlers; - /* Mask of available ports for GPIOTE instance. */ - uint32_t available_gpio_ports; - + uint16_t ch_pin[GPIOTE_CH_NUM]; #if !defined(NRF_GPIO_LATCH_PRESENT) uint32_t port_pins[GPIO_COUNT]; #endif nrfx_drv_state_t state; } gpiote_control_block_t; +typedef struct +{ + /* Number of GPIOTE channels. */ + uint32_t channels_number; + + /* Mask of available ports for GPIOTE instance. */ + uint32_t available_gpio_ports; + +#if NRFX_CHECK(NRFX_GPIOTE_CONFIG_NONUNIFORM_INSTANCES) + uint8_t group_idx; + bool port_supported; + bool dynamic_chan_supported; +#endif +} gpiote_config_t; + #if !defined(__NRFX_DOXYGEN__) #if (defined(NRF_GPIOTE) || defined(NRF_GPIOTE0)) && !defined(NRFX_GPIOTE0_CHANNELS_USED) /* Bitmask that defines GPIOTE0 channels that are reserved for use outside of the nrfx library. */ @@ -231,16 +244,34 @@ typedef struct #endif #endif // !defined(__NRFX_DOXYGEN__) -#define _NRFX_GPIOTE_CB_INITIALIZER(periph_name, prefix, idx, _) \ +#if NRFX_CHECK(NRFX_GPIOTE_CONFIG_NONUNIFORM_INSTANCES) +#define GPIOTE_VAR_INIT(prefix, idx) \ + .group_idx = idx == 0 ? 0 : NRF_GPIOTE_IRQ_GROUP, \ + .port_supported = idx != 0, \ + .dynamic_chan_supported = idx != 0, +#else +#define GPIOTE_VAR_INIT(prefix, idx) +#endif + +#define _NRFX_GPIOTE_CONFIG_INITIALIZER(periph_name, prefix, idx, _) \ [NRFX_CONCAT(NRFX_, periph_name, idx, _INST_IDX)] = { \ .channels_number = NRFX_CONCAT_3(periph_name, idx, _CH_NUM), \ - .available_channels_mask = (nrfx_atomic_t)NRFX_GPIOTE_APP_CHANNELS_MASK(idx), \ .available_gpio_ports = NRFX_CONCAT_3(periph_name, idx, _AVAILABLE_GPIO_PORTS), \ + GPIOTE_VAR_INIT(prefix, idx) \ }, -static gpiote_control_block_t m_cb[NRFX_GPIOTE_ENABLED_COUNT] = { - NRFX_FOREACH_ENABLED(GPIOTE, _NRFX_GPIOTE_CB_INITIALIZER, (), ()) +#define _NRFX_GPIOTE_CHANNEL_INITIALIZER(periph_name, prefix, idx, _) \ + [NRFX_CONCAT(NRFX_, periph_name, idx, _INST_IDX)] = \ + (nrfx_atomic_t)NRFX_GPIOTE_APP_CHANNELS_MASK(idx), + +/* Mask for tracking GPIOTE channel allocation. */ +static nrfx_atomic_t available_channels_mask[NRFX_GPIOTE_ENABLED_COUNT] = { + NRFX_FOREACH_ENABLED(GPIOTE, _NRFX_GPIOTE_CHANNEL_INITIALIZER, (), ()) }; +static const gpiote_config_t m_config[NRFX_GPIOTE_ENABLED_COUNT] = { + NRFX_FOREACH_ENABLED(GPIOTE, _NRFX_GPIOTE_CONFIG_INITIALIZER, (), ()) +}; +static gpiote_control_block_t m_cb[NRFX_GPIOTE_ENABLED_COUNT]; #if defined(NRF_GPIO_LATCH_PRESENT) || (!FULL_PORTS_PRESENT) static const uint8_t ports[GPIO_COUNT] = GPIO_PORT_NUM_LIST; @@ -301,6 +332,26 @@ static gpiote_control_block_t * get_cb(uint32_t idx) } } +/** @brief Function for getting instance configuration structure. + * + * Function is optimized for case when there is only one GPIOTE instance. + * + * @param[in] idx Instance index. + * + * @return Configure structure. + */ +static const gpiote_config_t * get_config(uint32_t idx) +{ + if (NRFX_GPIOTE_ENABLED_COUNT == 1) + { + return &m_config[0]; + } + else + { + return &m_config[idx]; + } +} + /** @brief Checks if pin is in use by a given GPIOTE instance. * * @param[in] p_instance Pointer to the driver instance structure. @@ -471,7 +522,13 @@ static void pin_trigger_disable(nrfx_gpiote_t const * p_instance, nrfx_gpiote_pi { uint8_t ch = pin_te_get(p_instance, pin); +#if NRFX_CHECK(NRFX_GPIOTE_CONFIG_NONUNIFORM_INSTANCES) + nrf_gpiote_int_group_disable(p_instance->p_reg, + get_config(p_instance->drv_inst_idx)->group_idx, + NRFX_BIT(ch)); +#else nrfy_gpiote_int_disable(p_instance->p_reg, NRFX_BIT(ch)); +#endif nrfy_gpiote_event_disable(p_instance->p_reg, ch); } else @@ -622,6 +679,7 @@ static nrfx_err_t gpiote_input_configure(nrfx_gpiote_t const * { nrfx_err_t err; uint8_t idx = get_pin_idx(pin); + gpiote_control_block_t *cb = get_cb(p_instance->drv_inst_idx); if (p_config->p_pull_config) { @@ -635,8 +693,8 @@ static nrfx_err_t gpiote_input_configure(nrfx_gpiote_t const * nrfy_gpio_reconfigure(pin, &dir, &input_connect, p_config->p_pull_config, NULL, NULL); - get_cb(p_instance->drv_inst_idx)->pin_flags[idx] &= (uint16_t)~PIN_FLAG_OUTPUT; - get_cb(p_instance->drv_inst_idx)->pin_flags[idx] |= PIN_FLAG_IN_USE; + cb->pin_flags[idx] &= (uint16_t)~PIN_FLAG_OUTPUT; + cb->pin_flags[idx] |= PIN_FLAG_IN_USE; } if (p_config->p_trigger_config) @@ -653,7 +711,7 @@ static nrfx_err_t gpiote_input_configure(nrfx_gpiote_t const * } else { - get_cb(p_instance->drv_inst_idx)->pin_flags[idx] &= + cb->pin_flags[idx] &= (uint16_t) ~(PIN_TE_ID_MASK | PIN_FLAG_TE_USED); if (use_evt) { bool edge = trigger <= NRFX_GPIOTE_TRIGGER_TOGGLE; @@ -677,23 +735,29 @@ static nrfx_err_t gpiote_input_configure(nrfx_gpiote_t const * nrfy_gpiote_event_disable(p_instance->p_reg, ch); nrfy_gpiote_event_configure(p_instance->p_reg, ch, pin, polarity); - - get_cb(p_instance->drv_inst_idx)->pin_flags[idx] |= (uint16_t)PIN_FLAG_TE_ID(ch); + cb->ch_pin[ch] = (uint16_t)pin; + cb->pin_flags[idx] |= (uint16_t)PIN_FLAG_TE_ID(ch); } } } #if !defined(NRF_GPIO_LATCH_PRESENT) if (use_evt || trigger == NRFX_GPIOTE_TRIGGER_NONE) { - nrf_bitmask_bit_clear(pin, (uint8_t *)get_cb(p_instance->drv_inst_idx)->port_pins); + nrf_bitmask_bit_clear(pin, (uint8_t *)cb->port_pins); } else { - nrf_bitmask_bit_set(pin, (uint8_t *)get_cb(p_instance->drv_inst_idx)->port_pins); +#if NRFX_CHECK(NRFX_GPIOTE_CONFIG_NONUNIFORM_INSTANCES) + if (!get_config(p_instance->drv_inst_idx)->port_supported) + { + return NRFX_ERROR_INVALID_PARAM; + } +#endif + nrf_bitmask_bit_set(pin, (uint8_t *)cb->port_pins); } #endif - get_cb(p_instance->drv_inst_idx)->pin_flags[idx] &= (uint16_t)~PIN_FLAG_TRIG_MODE_MASK; - get_cb(p_instance->drv_inst_idx)->pin_flags[idx] |= (uint16_t)PIN_FLAG_TRIG_MODE_SET(trigger); + cb->pin_flags[idx] &= (uint16_t)~PIN_FLAG_TRIG_MODE_MASK; + cb->pin_flags[idx] |= (uint16_t)PIN_FLAG_TRIG_MODE_SET(trigger); } if (p_config->p_handler_config) @@ -805,7 +869,8 @@ static nrfx_err_t gpiote_init(nrfx_gpiote_t const * p_instance, uint8_t interrup nrfx_err_t err_code = NRFX_SUCCESS; NRFX_LOG_INFO("channels_number: %d, available_channels_mask: 0x%x", - (int)p_cb->channels_number, (int)p_cb->available_channels_mask); + (int)get_config(p_instance->drv_inst_idx)->channels_number, + (int)available_channels_mask[p_instance->drv_inst_idx]); if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED) { @@ -822,11 +887,18 @@ static nrfx_err_t gpiote_init(nrfx_gpiote_t const * p_instance, uint8_t interrup memset(p_cb->pin_flags, 0, sizeof(p_cb->pin_flags)); +#if NRFX_CHECK(NRFX_GPIOTE_CONFIG_NONUNIFORM_INSTANCES) + uint32_t int_mask = get_config(p_instance->drv_inst_idx)->port_supported ? + NRF_GPIOTE_INT_PORT_MASK : 0; +#else + uint32_t int_mask = NRF_GPIOTE_INT_PORT_MASK; +#endif + nrfy_gpiote_int_init(p_instance->p_reg, - (uint32_t)NRF_GPIOTE_INT_PORT_MASK, + int_mask, interrupt_priority, false, - p_cb->channels_number); + get_config(p_instance->drv_inst_idx)->channels_number); p_cb->state = NRFX_DRV_STATE_INITIALIZED; p_cb->available_evt_handlers = NRFX_BIT_MASK(NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS); @@ -875,14 +947,31 @@ static void gpiote_uninit(nrfx_gpiote_t const * p_instance) static nrfx_err_t pin_channel_free(nrfx_gpiote_t const * p_instance, uint8_t channel) { - return nrfx_flag32_free(&get_cb(p_instance->drv_inst_idx)->available_channels_mask, channel); +#if NRFX_CHECK(NRFX_GPIOTE_CONFIG_NONUNIFORM_INSTANCES) + const gpiote_config_t * p_config = get_config(p_instance->drv_inst_idx); + + if (!p_config->dynamic_chan_supported) + { + return NRFX_ERROR_NOT_SUPPORTED; + } +#endif + return nrfx_flag32_free(&available_channels_mask[p_instance->drv_inst_idx], channel); } static nrfx_err_t pin_channel_alloc(nrfx_gpiote_t const * p_instance, uint8_t * p_channel) { NRFX_LOG_INFO("available_channels_mask = %d", - (int)get_cb(p_instance->drv_inst_idx)->available_channels_mask); - return nrfx_flag32_alloc(&get_cb(p_instance->drv_inst_idx)->available_channels_mask, p_channel); + (int)&available_channels_mask[p_instance->drv_inst_idx]); +#if NRFX_CHECK(NRFX_GPIOTE_CONFIG_NONUNIFORM_INSTANCES) + const gpiote_config_t * p_config = get_config(p_instance->drv_inst_idx); + + if (!p_config->dynamic_chan_supported) + { + return NRFX_ERROR_NOT_SUPPORTED; + } +#endif + + return nrfx_flag32_alloc(&available_channels_mask[p_instance->drv_inst_idx], p_channel); } static void pin_out_set(nrfx_gpiote_t const * p_instance, nrfx_gpiote_pin_t pin) @@ -1017,11 +1106,6 @@ static void pin_trigger_enable(nrfx_gpiote_t const * p_instance, { NRFX_ASSERT(pin_has_trigger(p_instance, pin)); - if (!nrfy_gpiote_int_enable_check(p_instance->p_reg, (uint32_t)NRF_GPIOTE_INT_PORT_MASK)) - { - nrfy_gpiote_int_enable(p_instance->p_reg, (uint32_t)NRF_GPIOTE_INT_PORT_MASK); - } - if (pin_in_use_by_te(p_instance, pin) && pin_is_input(p_instance, pin)) { uint8_t ch = pin_te_get(p_instance, pin); @@ -1030,11 +1114,22 @@ static void pin_trigger_enable(nrfx_gpiote_t const * p_instance, nrfy_gpiote_event_enable(p_instance->p_reg, ch); if (int_enable) { +#if NRFX_CHECK(NRFX_GPIOTE_CONFIG_NONUNIFORM_INSTANCES) + nrf_gpiote_int_group_enable(p_instance->p_reg, + get_config(p_instance->drv_inst_idx)->group_idx, + NRFX_BIT(ch)); +#else nrfy_gpiote_int_enable(p_instance->p_reg, NRFX_BIT(ch)); +#endif } } else { + if (!nrfy_gpiote_int_enable_check(p_instance->p_reg, (uint32_t)NRF_GPIOTE_INT_PORT_MASK)) + { + nrfy_gpiote_int_enable(p_instance->p_reg, (uint32_t)NRF_GPIOTE_INT_PORT_MASK); + } + NRFX_ASSERT(int_enable); nrfy_gpio_cfg_sense_set(pin, get_initial_sense(p_instance, pin)); } @@ -1079,9 +1174,7 @@ nrfx_err_t nrfx_gpiote_channel_get(nrfx_gpiote_t const * p_instance, uint32_t nrfx_gpiote_channels_number_get(nrfx_gpiote_t const * p_instance) { - gpiote_control_block_t * p_cb = get_cb(p_instance->drv_inst_idx); - - return p_cb->channels_number; + return get_config(p_instance->drv_inst_idx)->channels_number; } nrfx_err_t nrfx_gpiote_init(nrfx_gpiote_t const * p_instance, uint8_t interrupt_priority) @@ -1479,16 +1572,17 @@ static bool latch_pending_read_and_check(uint32_t * latch, uint32_t available_gp return false; } -static void port_event_handle(NRF_GPIOTE_Type * p_gpiote, gpiote_control_block_t * p_cb) +static void port_event_handle(NRF_GPIOTE_Type * p_gpiote, gpiote_control_block_t * p_cb, + const gpiote_config_t * p_config) { uint32_t latch[GPIO_COUNT] = {0}; - latch_pending_read_and_check(latch, p_cb->available_gpio_ports); + latch_pending_read_and_check(latch, p_config->available_gpio_ports); do { for (uint32_t i = 0; i < GPIO_COUNT; i++) { - if (nrf_bitmask_bit_is_set(port_index[i], &p_cb->available_gpio_ports)) + if (nrf_bitmask_bit_is_set(port_index[i], &p_config->available_gpio_ports)) { while (latch[i]) { @@ -1516,7 +1610,7 @@ static void port_event_handle(NRF_GPIOTE_Type * p_gpiote, gpiote_control_block_t /* All pins have been handled, clear PORT, check latch again in case * something came between deciding to exit and clearing PORT event. */ (void)nrfy_gpiote_events_process(p_gpiote, (uint32_t)NRF_GPIOTE_INT_PORT_MASK, 0); - } while (latch_pending_read_and_check(latch, p_cb->available_gpio_ports)); + } while (latch_pending_read_and_check(latch, p_config->available_gpio_ports)); } #else @@ -1554,7 +1648,8 @@ static bool input_read_and_check(uint32_t * input, return process_inputs_again; } -static void port_event_handle(NRF_GPIOTE_Type * p_gpiote, gpiote_control_block_t * p_cb) +static void port_event_handle(NRF_GPIOTE_Type * p_gpiote, gpiote_control_block_t * p_cb, + const gpiote_config_t * p_config) { uint32_t pins_to_check[GPIO_COUNT] = {0}; uint32_t input[GPIO_COUNT] = {0}; @@ -1564,7 +1659,7 @@ static void port_event_handle(NRF_GPIOTE_Type * p_gpiote, gpiote_control_block_t for (uint32_t port_idx = 0; port_idx < GPIO_COUNT; port_idx++) { - if (nrf_bitmask_bit_is_set(port_index[port_idx], &p_cb->available_gpio_ports)) + if (nrf_bitmask_bit_is_set(port_index[port_idx], &p_config->available_gpio_ports)) { nrfy_gpio_ports_read(port_idx, 1, &input[port_idx]); pins_to_check[port_idx] = p_cb->port_pins[port_idx]; @@ -1599,7 +1694,7 @@ static void port_event_handle(NRF_GPIOTE_Type * p_gpiote, gpiote_control_block_t for (uint32_t port_idx = 0; port_idx < GPIO_COUNT; port_idx++) { - if (nrf_bitmask_bit_is_set(port_index[port_idx], &p_cb->available_gpio_ports)) + if (nrf_bitmask_bit_is_set(port_index[port_idx], &p_config->available_gpio_ports)) { /* All pins used with PORT must be rechecked because it's content and * number of port pins may have changed during handler execution. */ @@ -1633,7 +1728,7 @@ static void port_event_handle(NRF_GPIOTE_Type * p_gpiote, gpiote_control_block_t } (void)nrfy_gpiote_events_process(p_gpiote, (uint32_t)NRF_GPIOTE_INT_PORT_MASK, 0); - } while (input_read_and_check(input, pins_to_check, p_cb->available_gpio_ports)); + } while (input_read_and_check(input, pins_to_check, p_config->available_gpio_ports)); } #endif // defined(NRF_GPIO_LATCH_PRESENT) @@ -1645,7 +1740,7 @@ static void gpiote_evt_handle(NRF_GPIOTE_Type * p_gpiote, { uint32_t ch = NRF_CTZ(mask); mask &= ~NRFX_BIT(ch); - nrfx_gpiote_pin_t pin = nrfy_gpiote_event_pin_get(p_gpiote, ch); + nrfx_gpiote_pin_t pin = p_cb->ch_pin[ch]; nrf_gpiote_polarity_t polarity = nrfy_gpiote_event_polarity_get(p_gpiote, ch); call_handler(p_cb, pin, gpiote_polarity_to_trigger(polarity)); @@ -1654,17 +1749,27 @@ static void gpiote_evt_handle(NRF_GPIOTE_Type * p_gpiote, static void irq_handler(NRF_GPIOTE_Type * p_gpiote, gpiote_control_block_t * p_cb) { + uint32_t instance_idx = (uint32_t)((uint8_t *)p_cb - (uint8_t *)m_cb) / sizeof(*p_cb); + const gpiote_config_t * p_config = get_config(instance_idx); /* Collect status of all GPIOTE pin events. Processing is done once all are collected and cleared.*/ - uint32_t enabled_in_events = nrf_gpiote_int_enable_check(p_gpiote, NRF_GPIOTE_INT_IN_MASK); +#if NRFX_CHECK(NRFX_GPIOTE_CONFIG_NONUNIFORM_INSTANCES) + uint32_t enabled_in_events = nrf_gpiote_int_group_enable_check(p_gpiote, + p_config->group_idx, + NRF_GPIOTE_INT_IN_MASK); + uint32_t enabled_events = enabled_in_events | + (p_config->port_supported ? NRF_GPIOTE_INT_PORT_MASK : 0); +#else + uint32_t enabled_events = nrf_gpiote_int_enable_check(p_gpiote, NRF_GPIOTE_INT_IN_MASK) | + NRF_GPIOTE_INT_PORT_MASK; +#endif uint32_t evt_mask = nrfy_gpiote_events_process(p_gpiote, - enabled_in_events | - (uint32_t)NRF_GPIOTE_INT_PORT_MASK, - p_cb->channels_number); + enabled_events, + p_config->channels_number); /* Handle PORT event. */ if (evt_mask & (uint32_t)NRF_GPIOTE_INT_PORT_MASK) { - port_event_handle(p_gpiote, p_cb); + port_event_handle(p_gpiote, p_cb, p_config); evt_mask &= ~(uint32_t)NRF_GPIOTE_INT_PORT_MASK; } diff --git a/nrfx/haly/nrfy_gpiote.h b/nrfx/haly/nrfy_gpiote.h index 1ff35272..dfd40262 100644 --- a/nrfx/haly/nrfy_gpiote.h +++ b/nrfx/haly/nrfy_gpiote.h @@ -94,6 +94,8 @@ NRFY_STATIC_INLINE void nrfy_gpiote_int_init(NRF_GPIOTE_Type * p_reg, #if defined(NRF_GPIOTE_IRQn_EXT) IRQn_Type irqn = NRF_GPIOTE_IRQn_EXT; +#elif defined(NRF_GPIOTE130) && defined(NRF_GPIOTE0) + IRQn_Type irqn = (p_reg == NRF_GPIOTE0) ? GPIOTE_0_IRQn : GPIOTE130_IRQn; #elif defined(NRF_GPIOTE130) IRQn_Type irqn = GPIOTE130_IRQn; #elif defined(LUMOS_XXAA) && defined(NRF_APPLICATION) && !defined(NRF_TRUSTZONE_NONSECURE) @@ -412,7 +414,10 @@ NRFY_STATIC_INLINE uint32_t __nrfy_internal_gpiote_events_process(NRF_GPIOTE_Typ &event_mask); } - (void)__nrfy_internal_gpiote_event_handle(p_reg, mask, NRF_GPIOTE_EVENT_PORT, &event_mask); + if (mask & NRF_GPIOTE_INT_PORT_MASK) + { + (void)__nrfy_internal_gpiote_event_handle(p_reg, mask, NRF_GPIOTE_EVENT_PORT, &event_mask); + } return event_mask; }