diff --git a/subsys/mpsl/CMakeLists.txt b/subsys/mpsl/CMakeLists.txt index 62ab0071ff53..67769ade935b 100644 --- a/subsys/mpsl/CMakeLists.txt +++ b/subsys/mpsl/CMakeLists.txt @@ -15,3 +15,5 @@ endif() if (CONFIG_MPSL_CX AND NOT CONFIG_MPSL_FEM_ONLY) add_subdirectory(cx) endif() + +add_subdirectory_ifdef(CONFIG_MPSL_PIN_DEBUG pin_debug) diff --git a/subsys/mpsl/Kconfig b/subsys/mpsl/Kconfig index c8a418edaef3..e70756bf1fa5 100644 --- a/subsys/mpsl/Kconfig +++ b/subsys/mpsl/Kconfig @@ -18,6 +18,7 @@ if !MPSL_FEM_ONLY rsource "cx/Kconfig" rsource "init/Kconfig" +rsource "pin_debug/Kconfig" endif # !MPSL_FEM_ONLY diff --git a/subsys/mpsl/pin_debug/CMakeLists.txt b/subsys/mpsl/pin_debug/CMakeLists.txt new file mode 100644 index 000000000000..df8231088c37 --- /dev/null +++ b/subsys/mpsl/pin_debug/CMakeLists.txt @@ -0,0 +1,9 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +zephyr_library() +zephyr_library_sources_ifdef(CONFIG_MPSL_PIN_DEBUG_APP_CORE mpsl_pin_debug_app_core.c) +zephyr_library_sources_ifdef(CONFIG_MPSL_PIN_DEBUG_RADIO_CORE mpsl_pin_debug_radio_core.c) diff --git a/subsys/mpsl/pin_debug/Kconfig b/subsys/mpsl/pin_debug/Kconfig new file mode 100644 index 000000000000..2f8e0fa07d66 --- /dev/null +++ b/subsys/mpsl/pin_debug/Kconfig @@ -0,0 +1,48 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +config MPSL_PIN_DEBUG + bool "Toggle MPSL debug pins [EXPERIMENTAL]" + select EXPERIMENTAL + depends on (BOARD_NRF52DK_NRF52832 || \ + BOARD_NRF52833DK_NRF52833 || \ + BOARD_NRF52840DK_NRF52840 || \ + BOARD_NRF5340DK_NRF5340_CPUNET || \ + BOARD_NRF5340DK_NRF5340_CPUAPP) + help + Set this option to enable toggling of GPIO pins upon radio + events. This can be useful for debugging purposes to figure + out when the radio is used. + +config MPSL_PIN_DEBUG_APP_CORE + bool + depends on MPSL_PIN_DEBUG + depends on SOC_COMPATIBLE_NRF5340_CPUAPP + default y if SOC_COMPATIBLE_NRF5340_CPUAPP + +config MPSL_PIN_DEBUG_RADIO_CORE + bool + depends on MPSL_PIN_DEBUG + select NRFX_GPIOTE + select NRFX_PPI if HAS_HW_NRF_PPI + select NRFX_DPPI if HAS_HW_NRF_DPPIC + default y if (SOC_COMPATIBLE_NRF52X || SOC_COMPATIBLE_NRF5340_CPUNET) + +config MPSL_PIN_DEBUG_RADIO_READY_AND_DISABLED_PIN + int "Pin toggled upon the events RADIO->EVENTS_READY and RADIO->EVENTS_DISABLED" + depends on MPSL_PIN_DEBUG + default 3 if SOC_COMPATIBLE_NRF52X + default 4 if SOC_COMPATIBLE_NRF53X + help + Only PORT0 can be used. + +config MPSL_PIN_DEBUG_RADIO_ADDRESS_AND_END_PIN + int "Pin toggled upon the events RADIO->EVENTS_ADDRESS and RADIO->EVENTS_END" + depends on MPSL_PIN_DEBUG + default 4 if SOC_COMPATIBLE_NRF52X + default 5 if SOC_COMPATIBLE_NRF53X + help + Only PORT0 can be used. diff --git a/subsys/mpsl/pin_debug/mpsl_pin_debug_app_core.c b/subsys/mpsl/pin_debug/mpsl_pin_debug_app_core.c new file mode 100644 index 000000000000..f454e5b2698d --- /dev/null +++ b/subsys/mpsl/pin_debug/mpsl_pin_debug_app_core.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include + +/* Only PORT 0 can be used. */ +BUILD_ASSERT(CONFIG_MPSL_PIN_DEBUG_RADIO_READY_AND_DISABLED_PIN < + ARRAY_SIZE(NRF_P0_S->PIN_CNF)); +BUILD_ASSERT(CONFIG_MPSL_PIN_DEBUG_RADIO_ADDRESS_AND_END_PIN < + ARRAY_SIZE(NRF_P0_S->PIN_CNF)); + +static const uint8_t pins_used[] = {CONFIG_MPSL_PIN_DEBUG_RADIO_READY_AND_DISABLED_PIN, + CONFIG_MPSL_PIN_DEBUG_RADIO_ADDRESS_AND_END_PIN}; + +/** @brief Allow access to specific GPIOs for the network core. */ +static int network_gpio_allow(void) +{ + for (uint32_t i = 0; i < ARRAY_SIZE(pins_used); i++) { + uint8_t pin = pins_used[i]; + + NRF_P0_S->PIN_CNF[pin] = + (GPIO_PIN_CNF_MCUSEL_NetworkMCU << GPIO_PIN_CNF_MCUSEL_Pos); + } + + return 0; +} +SYS_INIT(network_gpio_allow, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/subsys/mpsl/pin_debug/mpsl_pin_debug_radio_core.c b/subsys/mpsl/pin_debug/mpsl_pin_debug_radio_core.c new file mode 100644 index 000000000000..43ede3bf8c4b --- /dev/null +++ b/subsys/mpsl/pin_debug/mpsl_pin_debug_radio_core.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include +#include +#include +#include + +#ifdef PPI_PRESENT +#include +#elif defined(DPPI_PRESENT) +#include +#include +#include +#endif + +LOG_MODULE_REGISTER(mpsl_radio_pin_debug, CONFIG_MPSL_LOG_LEVEL); + +static int m_ppi_config(void) +{ +#if defined(PPI_PRESENT) + uint8_t ppi_chan_radio_ready; + uint8_t ppi_chan_radio_address; + uint8_t ppi_chan_radio_end; + uint8_t ppi_chan_radio_disabled; + + if (nrfx_ppi_channel_alloc(&ppi_chan_radio_ready) != NRFX_SUCCESS) { + LOG_ERR("Failed allocating PPI chan"); + return -ENOMEM; + } + + if (nrfx_ppi_channel_alloc(&ppi_chan_radio_address) != NRFX_SUCCESS) { + LOG_ERR("Failed allocating PPI chan"); + return -ENOMEM; + } + + if (nrfx_ppi_channel_alloc(&ppi_chan_radio_end) != NRFX_SUCCESS) { + LOG_ERR("Failed allocating PPI chan"); + return -ENOMEM; + } + + if (nrfx_ppi_channel_alloc(&ppi_chan_radio_disabled) != NRFX_SUCCESS) { + LOG_ERR("Failed allocating PPI chan"); + return -ENOMEM; + } + + nrfx_gppi_channel_endpoints_setup( + ppi_chan_radio_ready, nrf_radio_event_address_get(NRF_RADIO, NRF_RADIO_EVENT_READY), + nrfx_gpiote_out_task_address_get( + CONFIG_MPSL_PIN_DEBUG_RADIO_READY_AND_DISABLED_PIN)); + + nrfx_gppi_channel_endpoints_setup( + ppi_chan_radio_disabled, + nrf_radio_event_address_get(NRF_RADIO, NRF_RADIO_EVENT_DISABLED), + nrfx_gpiote_out_task_address_get( + CONFIG_MPSL_PIN_DEBUG_RADIO_READY_AND_DISABLED_PIN)); + + nrfx_gppi_channel_endpoints_setup( + ppi_chan_radio_address, + nrf_radio_event_address_get(NRF_RADIO, NRF_RADIO_EVENT_ADDRESS), + nrfx_gpiote_out_task_address_get(CONFIG_MPSL_PIN_DEBUG_RADIO_ADDRESS_AND_END_PIN)); + + nrfx_gppi_channel_endpoints_setup( + ppi_chan_radio_end, nrf_radio_event_address_get(NRF_RADIO, NRF_RADIO_EVENT_END), + nrfx_gpiote_out_task_address_get(CONFIG_MPSL_PIN_DEBUG_RADIO_ADDRESS_AND_END_PIN)); + + if (nrfx_ppi_channel_enable(ppi_chan_radio_ready) != NRFX_SUCCESS) { + LOG_ERR("Failed enabling channel"); + return -ENOMEM; + } + if (nrfx_ppi_channel_enable(ppi_chan_radio_address) != NRFX_SUCCESS) { + LOG_ERR("Failed enabling channel"); + return -ENOMEM; + } + if (nrfx_ppi_channel_enable(ppi_chan_radio_end) != NRFX_SUCCESS) { + LOG_ERR("Failed enabling channel"); + return -ENOMEM; + } + if (nrfx_ppi_channel_enable(ppi_chan_radio_disabled) != NRFX_SUCCESS) { + LOG_ERR("Failed enabling channel"); + return -ENOMEM; + } + +#elif defined(DPPI_PRESENT) + /* Radio events are published on predefined channels. + */ + uint8_t ppi_chan_radio_ready = MPSL_DPPI_RADIO_PUBLISH_READY_CHANNEL_IDX; + uint8_t ppi_chan_radio_address = MPSL_DPPI_RADIO_PUBLISH_ADDRESS_CHANNEL_IDX; + uint8_t ppi_chan_radio_end = MPSL_DPPI_RADIO_PUBLISH_END_CHANNEL_IDX; + uint8_t ppi_chan_radio_disabled = MPSL_DPPI_RADIO_PUBLISH_DISABLED_CH_IDX; + + /* Because the GPIOTE needs to subscribe to only two DPPI channels, + * we use an EGU to route events together. + */ + uint8_t dppi_chan_ready_disabled; + uint8_t dppi_chan_address_end; + + if (nrfx_dppi_channel_alloc(&dppi_chan_ready_disabled) != NRFX_SUCCESS) { + LOG_ERR("Failed allocating DPPI chan"); + return -ENOMEM; + } + + if (nrfx_dppi_channel_alloc(&dppi_chan_address_end) != NRFX_SUCCESS) { + LOG_ERR("Failed allocating DPPI chan"); + return -ENOMEM; + } + nrf_egu_subscribe_set(NRF_EGU0, NRF_EGU_TASK_TRIGGER0, ppi_chan_radio_ready); + nrf_egu_subscribe_set(NRF_EGU0, NRF_EGU_TASK_TRIGGER1, ppi_chan_radio_disabled); + nrf_egu_subscribe_set(NRF_EGU0, NRF_EGU_TASK_TRIGGER2, ppi_chan_radio_address); + nrf_egu_subscribe_set(NRF_EGU0, NRF_EGU_TASK_TRIGGER3, ppi_chan_radio_end); + + nrf_egu_publish_set(NRF_EGU0, NRF_EGU_EVENT_TRIGGERED0, dppi_chan_ready_disabled); + nrf_egu_publish_set(NRF_EGU0, NRF_EGU_EVENT_TRIGGERED1, dppi_chan_ready_disabled); + nrf_egu_publish_set(NRF_EGU0, NRF_EGU_EVENT_TRIGGERED2, dppi_chan_address_end); + nrf_egu_publish_set(NRF_EGU0, NRF_EGU_EVENT_TRIGGERED3, dppi_chan_address_end); + + nrfx_gppi_task_endpoint_setup(dppi_chan_ready_disabled, + nrfx_gpiote_out_task_address_get( + CONFIG_MPSL_PIN_DEBUG_RADIO_READY_AND_DISABLED_PIN)); + + nrfx_gppi_task_endpoint_setup( + dppi_chan_address_end, + nrfx_gpiote_out_task_address_get(CONFIG_MPSL_PIN_DEBUG_RADIO_ADDRESS_AND_END_PIN)); + + if (nrfx_dppi_channel_enable(dppi_chan_ready_disabled) != NRFX_SUCCESS) { + LOG_ERR("Failed enabling channel"); + return -ENOMEM; + } + + if (nrfx_dppi_channel_enable(dppi_chan_address_end) != NRFX_SUCCESS) { + LOG_ERR("Failed enabling channel"); + return -ENOMEM; + } +#else +#error "Expect either PPI or DPPI to be present." +#endif + + return 0; +} + +static int mpsl_radio_pin_debug_init(void) +{ + uint8_t radio_ready_radio_disabled_gpiote_channel; + uint8_t radio_address_radio_end_gpiote_channel; + + const nrfx_gpiote_output_config_t gpiote_output_cfg = NRFX_GPIOTE_DEFAULT_OUTPUT_CONFIG; + + if (nrfx_gpiote_channel_alloc(&radio_ready_radio_disabled_gpiote_channel) != NRFX_SUCCESS) { + LOG_ERR("Failed allocating GPIOTE chan"); + return -ENOMEM; + } + + if (nrfx_gpiote_channel_alloc(&radio_address_radio_end_gpiote_channel) != NRFX_SUCCESS) { + LOG_ERR("Failed allocating GPIOTE chan"); + return -ENOMEM; + } + + const nrfx_gpiote_task_config_t task_cfg_ready_disabled = { + .task_ch = radio_ready_radio_disabled_gpiote_channel, + .polarity = NRF_GPIOTE_POLARITY_TOGGLE, + .init_val = NRF_GPIOTE_INITIAL_VALUE_LOW, + }; + + if (nrfx_gpiote_output_configure(CONFIG_MPSL_PIN_DEBUG_RADIO_READY_AND_DISABLED_PIN, + &gpiote_output_cfg, + &task_cfg_ready_disabled) != NRFX_SUCCESS) { + LOG_ERR("Failed configuring GPIOTE chan"); + return -ENOMEM; + } + + const nrfx_gpiote_task_config_t task_cfg_address_end = { + .task_ch = radio_address_radio_end_gpiote_channel, + .polarity = NRF_GPIOTE_POLARITY_TOGGLE, + .init_val = NRF_GPIOTE_INITIAL_VALUE_LOW, + }; + + if (nrfx_gpiote_output_configure(CONFIG_MPSL_PIN_DEBUG_RADIO_ADDRESS_AND_END_PIN, + &gpiote_output_cfg, + &task_cfg_address_end) != NRFX_SUCCESS) { + LOG_ERR("Failed configuring GPIOTE chan"); + return -ENOMEM; + } + + if (m_ppi_config() != 0) { + return -ENOMEM; + } + + nrfx_gpiote_out_task_enable(CONFIG_MPSL_PIN_DEBUG_RADIO_READY_AND_DISABLED_PIN); + nrfx_gpiote_out_task_enable(CONFIG_MPSL_PIN_DEBUG_RADIO_ADDRESS_AND_END_PIN); + + return 0; +} + +SYS_INIT(mpsl_radio_pin_debug_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);