Skip to content

Commit

Permalink
mpsl: Define CONFIG_MPSL_PIN_DEBUG
Browse files Browse the repository at this point in the history
Toggling pins on radio events is something that can be useful
for debugging purposes. By defining Kconfig entries,
this becomes simpler to setup.

The default configuration will setup two pins to toggle
on (RADIO->EVENTS_READY, RADIO->EVENTS_DISABLED) and
(RADIO->EVENTS_ADDRESS, RADIO->EVENTS_END).

The implementation may require code to be run on both the
application core and radio core.
As Kconfig entries are not propagated to child images,
this entry needs to be set for both cores.

For example like this:
```
west build -b nrf5340dk_nrf5340_cpuapp --
-DCONFIG_MPSL_PIN_DEBUG=y -Dhci_ipc_CONFIG_MPSL_PIN_DEBUG=y
```

The entry is marked as experimental because the implementation
is not necessarily stable nor tested properly.

Signed-off-by: Rubin Gerritsen <[email protected]>
  • Loading branch information
rugeGerritsen authored and rlubos committed Feb 2, 2024
1 parent 6ba10cb commit 7e318ac
Show file tree
Hide file tree
Showing 6 changed files with 290 additions and 0 deletions.
2 changes: 2 additions & 0 deletions subsys/mpsl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
1 change: 1 addition & 0 deletions subsys/mpsl/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ if !MPSL_FEM_ONLY

rsource "cx/Kconfig"
rsource "init/Kconfig"
rsource "pin_debug/Kconfig"

endif # !MPSL_FEM_ONLY

Expand Down
9 changes: 9 additions & 0 deletions subsys/mpsl/pin_debug/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
48 changes: 48 additions & 0 deletions subsys/mpsl/pin_debug/Kconfig
Original file line number Diff line number Diff line change
@@ -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.
31 changes: 31 additions & 0 deletions subsys/mpsl/pin_debug/mpsl_pin_debug_app_core.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#include <zephyr/init.h>
#include <zephyr/kernel.h>

/* 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);
199 changes: 199 additions & 0 deletions subsys/mpsl/pin_debug/mpsl_pin_debug_radio_core.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#include <zephyr/init.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <nrfx_gpiote.h>
#include <helpers/nrfx_gppi.h>
#include <hal/nrf_radio.h>

#ifdef PPI_PRESENT
#include <nrfx_ppi.h>
#elif defined(DPPI_PRESENT)
#include <nrfx_dppi.h>
#include <mpsl_dppi_protocol_api.h>
#include <hal/nrf_egu.h>
#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);

0 comments on commit 7e318ac

Please sign in to comment.