diff --git a/include/debug/ppi_trace.h b/include/debug/ppi_trace.h index bba9c97139dc..76c82cab4c83 100644 --- a/include/debug/ppi_trace.h +++ b/include/debug/ppi_trace.h @@ -6,6 +6,8 @@ #ifndef __PPI_TRACE_H #define __PPI_TRACE_H +#include + #ifdef __cplusplus extern "C" { #endif @@ -45,6 +47,25 @@ void *ppi_trace_config(uint32_t pin, uint32_t evt); */ void *ppi_trace_pair_config(uint32_t pin, uint32_t start_evt, uint32_t stop_evt); +/** @brief Configure and enable a PPI trace pin for tracing a DPPI channel. + * + * This function allows to trace DPPI triggers without knowing any events being the source of the + * trigger. Configuration of events so that they publish to the given DPPI and enabling the DPPI is + * out of scope of this function and must be done externally. + * This function allows also to trace DPPI channels which are triggered by multiple events or + * the set of events publishing to the DPPI channel changes in run-time. + * + * @note Supported only on platforms equipped with DPPI. + * + * @param pin Pin to use for tracing. + * @param dppi_ch DPPI channel number to be traced on the pin. + * + * @retval 0 The configuration succeeded. + * @retval -ENOMEM The configuration failed, due to lack of necessary resources. + * @retval -ENOTSUP The function is not supported on current hardware platform. + */ +int ppi_trace_dppi_ch_trace(uint32_t pin, uint32_t dppi_ch); + /** @brief Enable PPI trace pin. * * @param handle Handle. diff --git a/modules/nrfxlib/nrf_802154/sl/platform/nrf_802154_platform_sl_lptimer_zephyr.c b/modules/nrfxlib/nrf_802154/sl/platform/nrf_802154_platform_sl_lptimer_zephyr.c index 9878ad2118ca..d2d97a5abbf7 100644 --- a/modules/nrfxlib/nrf_802154/sl/platform/nrf_802154_platform_sl_lptimer_zephyr.c +++ b/modules/nrfxlib/nrf_802154/sl/platform/nrf_802154_platform_sl_lptimer_zephyr.c @@ -11,12 +11,35 @@ #include #include +#include +#include #include #include "platform/nrf_802154_clock.h" #include "nrf_802154_sl_utils.h" #define RTC_CHAN_INVALID (-1) +#if defined(CONFIG_SOC_NRF5340_CPUNET) + +BUILD_ASSERT(CONFIG_MPSL); + +#define HW_TASK_RTC NRF_RTC0 +#define HW_TASK_RTC_CHAN (3) + +#define RTC_COUNTER_BIT_WIDTH 24U +#define RTC_COUNTER_SPAN BIT(RTC_COUNTER_BIT_WIDTH) +#define RTC_COUNTER_MAX (RTC_COUNTER_SPAN - 1U) +#define RTC_COUNTER_HALF_SPAN (RTC_COUNTER_SPAN / 2U) + +#define RTC_MIN_CYCLES_FROM_NOW 3 +#endif + +/** @brief Macro for creating the interrupt bitmask for the specified compare channel. */ +#define NRF_RTC_CHANNEL_INT_MASK(ch) ((uint32_t)(NRF_RTC_INT_COMPARE0_MASK) << (ch)) + +/** @brief Macro for obtaining the compare event for the specified channel. */ +#define NRF_RTC_CHANNEL_EVENT_ADDR(ch) \ + (nrf_rtc_event_t)((NRF_RTC_EVENT_COMPARE_0) + (ch) * sizeof(uint32_t)) struct timer_desc { z_nrf_rtc_timer_compare_handler_t handler; @@ -98,40 +121,152 @@ static void timer_start_at(struct timer_desc *timer, uint64_t target_time) nrf_802154_sl_mcu_critical_exit(state); } +#if defined(CONFIG_SOC_NRF5340_CPUNET) +static inline uint32_t rtc_counter_diff(uint32_t a, uint32_t b) +{ + return (a - b) & RTC_COUNTER_MAX; +} +#endif + static bool hw_task_state_set(enum hw_task_state_type expected_state, enum hw_task_state_type new_state) { return atomic_cas(&m_hw_task.state, expected_state, new_state); } -static void cc_bind_to_ppi(int32_t cc_num, uint32_t ppi_num) +static inline uint32_t hw_task_rtc_get_compare_evt_address(int32_t cc_num) { - uint32_t event_address = z_nrf_rtc_timer_compare_evt_address_get(cc_num); +#if defined(CONFIG_SOC_NRF5340_CPUNET) + return nrf_rtc_event_address_get(HW_TASK_RTC, nrf_rtc_compare_event_get(cc_num)); +#else + return z_nrf_rtc_timer_compare_evt_address_get(cc_num); +#endif +} + +static void hw_task_rtc_cc_bind_to_ppi(int32_t cc_num, uint32_t ppi_num) +{ + uint32_t event_address = hw_task_rtc_get_compare_evt_address(cc_num); nrfx_gppi_event_endpoint_setup(ppi_num, event_address); } -static void cc_unbind(int32_t cc_num, uint32_t ppi_num) +static void hw_task_rtc_cc_unbind(int32_t cc_num, uint32_t ppi_num) { if (ppi_num != NRF_802154_SL_HW_TASK_PPI_INVALID) { - uint32_t event_address = z_nrf_rtc_timer_compare_evt_address_get(cc_num); + uint32_t event_address = hw_task_rtc_get_compare_evt_address(cc_num); nrfx_gppi_event_endpoint_clear(ppi_num, event_address); } } -static bool cc_event_check(int32_t cc_num) +static bool hw_task_rtc_cc_event_check(int32_t cc_num) { - uint32_t event_address = z_nrf_rtc_timer_compare_evt_address_get(cc_num); + uint32_t event_address = hw_task_rtc_get_compare_evt_address(cc_num); return *(volatile uint32_t *)event_address; } +static void hw_task_rtc_timer_abort(void) +{ +#if defined(CONFIG_SOC_NRF5340_CPUNET) + /* No interrupt disabling/clearing is needed, as HW task does not use interrupts*/ + nrf_rtc_event_disable(HW_TASK_RTC, NRF_RTC_CHANNEL_INT_MASK(m_hw_task.chan)); + nrf_rtc_event_clear(HW_TASK_RTC, NRF_RTC_CHANNEL_EVENT_ADDR(m_hw_task.chan)); +#else + z_nrf_rtc_timer_abort(m_hw_task.chan); +#endif +} + +#if defined(CONFIG_SOC_NRF5340_CPUNET) +static uint32_t zephyr_rtc_ticks_to_hw_task_rtc_counter(uint64_t ticks) +{ + uint64_t zephyr_rtc_counter_now = 0; + uint32_t hw_task_rtc_counter_now = 0; + uint32_t hw_task_rtc_counter_now_2 = 0; + + /** + * The RTC0 counter is read twice - once before and once after reading RTC1. + * If the two reads are different, the procedure is repeated. + * This is to make sure that no RTC tick occurred between reading RTC0 and + * RTC1 and so the calculated difference between the timers is correct. + */ + do { + hw_task_rtc_counter_now = nrf_rtc_counter_get(HW_TASK_RTC); + zephyr_rtc_counter_now = z_nrf_rtc_timer_read(); + barrier_dmem_fence_full(); + hw_task_rtc_counter_now_2 = nrf_rtc_counter_get(HW_TASK_RTC); + + } while (hw_task_rtc_counter_now != hw_task_rtc_counter_now_2); + + /* This function can only be called in close proximity of ticks */ + assert(ticks >= zephyr_rtc_counter_now + || zephyr_rtc_counter_now - ticks < RTC_COUNTER_HALF_SPAN); + assert(ticks <= zephyr_rtc_counter_now + || ticks - zephyr_rtc_counter_now < RTC_COUNTER_HALF_SPAN); + + uint32_t diff = rtc_counter_diff(hw_task_rtc_counter_now, + (uint32_t) zephyr_rtc_counter_now % RTC_COUNTER_SPAN); + + return (uint32_t) ((ticks + diff) % RTC_COUNTER_SPAN); +} + +static int hw_task_rtc_counter_compare_set(uint32_t cc_value) +{ + uint32_t current_counter_value = nrf_rtc_counter_get(HW_TASK_RTC); + + /* As the HW tasks are setup only shortly before they are triggered, + * it is certain that the required fire time is not further away + * than one half of the RTC counter span. + * If it is it means that the trigger time is already in the past. + */ + if (rtc_counter_diff(cc_value, current_counter_value) > RTC_COUNTER_HALF_SPAN) { + return -EINVAL; + } + + nrf_rtc_event_disable(HW_TASK_RTC, NRF_RTC_CHANNEL_INT_MASK(m_hw_task.chan)); + nrf_rtc_event_clear(HW_TASK_RTC, NRF_RTC_CHANNEL_EVENT_ADDR(m_hw_task.chan)); + + nrf_rtc_cc_set(HW_TASK_RTC, m_hw_task.chan, cc_value); + + nrf_rtc_event_enable(HW_TASK_RTC, NRF_RTC_CHANNEL_INT_MASK(m_hw_task.chan)); + + current_counter_value = nrf_rtc_counter_get(HW_TASK_RTC); + + if (rtc_counter_diff(cc_value, current_counter_value + RTC_MIN_CYCLES_FROM_NOW) + > (RTC_COUNTER_HALF_SPAN - RTC_MIN_CYCLES_FROM_NOW)) { + nrf_rtc_event_disable(HW_TASK_RTC, NRF_RTC_CHANNEL_INT_MASK(m_hw_task.chan)); + nrf_rtc_event_clear(HW_TASK_RTC, NRF_RTC_CHANNEL_EVENT_ADDR(m_hw_task.chan)); + return -EINVAL; + } + + return 0; +} +#endif + +static int hw_task_rtc_timer_set(uint64_t fire_lpticks) +{ +#if defined(CONFIG_SOC_NRF5340_CPUNET) + uint32_t hw_task_rtc_counter_ticks = zephyr_rtc_ticks_to_hw_task_rtc_counter(fire_lpticks); + + return hw_task_rtc_counter_compare_set(hw_task_rtc_counter_ticks); +#else + return z_nrf_rtc_timer_exact_set(m_hw_task.chan, fire_lpticks, NULL, NULL); +#endif +} + void nrf_802154_platform_sl_lp_timer_init(void) { m_in_critical_section = false; m_hw_task.state = HW_TASK_STATE_IDLE; - m_hw_task.chan = RTC_CHAN_INVALID; +#if defined(CONFIG_SOC_NRF5340_CPUNET) + m_hw_task.chan = HW_TASK_RTC_CHAN; +#else + m_hw_task.chan = z_nrf_rtc_timer_chan_alloc(); + if (m_hw_task.chan < 0) { + assert(false); + return; + } +#endif m_hw_task.ppi = NRF_802154_SL_HW_TASK_PPI_INVALID; m_timer.handler = timer_handler; m_sync_timer.handler = sync_timer_handler; @@ -159,7 +294,9 @@ void nrf_802154_platform_sl_lp_timer_deinit(void) z_nrf_rtc_timer_chan_free(m_sync_timer.chan); if (m_hw_task.chan != RTC_CHAN_INVALID) { +#if !defined(CONFIG_SOC_NRF5340_CPUNET) z_nrf_rtc_timer_chan_free(m_hw_task.chan); +#endif m_hw_task.chan = RTC_CHAN_INVALID; } } @@ -270,30 +407,18 @@ nrf_802154_sl_lptimer_platform_result_t nrf_802154_platform_sl_lptimer_hw_task_p return NRF_802154_SL_LPTIMER_PLATFORM_NO_RESOURCES; } - /* Allocate the channel if not already done. */ - if (m_hw_task.chan == RTC_CHAN_INVALID) { - /* The channel allocation cannot take place during module - * initialization, because for nRF53 it would run - * out of resources - some other module temporarily needs - * an rtc channel to initialize. For this reason, this is where - * the allocation is made. - * Once a channel has been successfully allocated, it will be held - * until nrf_802154_platform_sl_lp_timer_deinit is called. - */ - m_hw_task.chan = z_nrf_rtc_timer_chan_alloc(); - if (m_hw_task.chan < 0) { - m_hw_task.chan = RTC_CHAN_INVALID; - hw_task_state_set(HW_TASK_STATE_SETTING_UP, HW_TASK_STATE_IDLE); - return NRF_802154_SL_LPTIMER_PLATFORM_NO_RESOURCES; - } - } - - if (z_nrf_rtc_timer_set(m_hw_task.chan, fire_lpticks, NULL, NULL) != 0) { + if (hw_task_rtc_timer_set(fire_lpticks) != 0) { hw_task_state_set(HW_TASK_STATE_SETTING_UP, HW_TASK_STATE_IDLE); - return NRF_802154_SL_LPTIMER_PLATFORM_TOO_DISTANT; + uint64_t now = z_nrf_rtc_timer_read(); + + if ((fire_lpticks > now) && + (fire_lpticks - now > NRF_RTC_TIMER_MAX_SCHEDULE_SPAN/2)) { + return NRF_802154_SL_LPTIMER_PLATFORM_TOO_DISTANT; + } + return NRF_802154_SL_LPTIMER_PLATFORM_TOO_LATE; } - evt_address = z_nrf_rtc_timer_compare_evt_address_get(m_hw_task.chan); + evt_address = hw_task_rtc_get_compare_evt_address(m_hw_task.chan); nrf_802154_sl_mcu_critical_enter(mcu_cs_state); @@ -301,9 +426,9 @@ nrf_802154_sl_lptimer_platform_result_t nrf_802154_platform_sl_lptimer_hw_task_p if ((z_nrf_rtc_timer_read() + 2) > fire_lpticks) { /* it is too late */ nrf_802154_sl_mcu_critical_exit(mcu_cs_state); - cc_unbind(m_hw_task.chan, ppi_channel); + hw_task_rtc_cc_unbind(m_hw_task.chan, ppi_channel); m_hw_task.ppi = NRF_802154_SL_HW_TASK_PPI_INVALID; - z_nrf_rtc_timer_abort(m_hw_task.chan); + hw_task_rtc_timer_abort(); hw_task_state_set(HW_TASK_STATE_SETTING_UP, HW_TASK_STATE_IDLE); return NRF_802154_SL_LPTIMER_PLATFORM_TOO_LATE; } @@ -324,9 +449,9 @@ nrf_802154_sl_lptimer_platform_result_t nrf_802154_platform_sl_lptimer_hw_task_c return NRF_802154_SL_LPTIMER_PLATFORM_WRONG_STATE; } - z_nrf_rtc_timer_abort(m_hw_task.chan); + hw_task_rtc_timer_abort(); - cc_unbind(m_hw_task.chan, m_hw_task.ppi); + hw_task_rtc_cc_unbind(m_hw_task.chan, m_hw_task.ppi); m_hw_task.ppi = NRF_802154_SL_HW_TASK_PPI_INVALID; hw_task_state_set(HW_TASK_STATE_CLEANING, HW_TASK_STATE_IDLE); @@ -347,10 +472,10 @@ nrf_802154_sl_lptimer_platform_result_t nrf_802154_platform_sl_lptimer_hw_task_u nrf_802154_sl_mcu_critical_enter(mcu_cs_state); - cc_bind_to_ppi(m_hw_task.chan, ppi_channel); + hw_task_rtc_cc_bind_to_ppi(m_hw_task.chan, ppi_channel); m_hw_task.ppi = ppi_channel; - cc_triggered = cc_event_check(m_hw_task.chan); + cc_triggered = hw_task_rtc_cc_event_check(m_hw_task.chan); if (z_nrf_rtc_timer_read() >= m_hw_task.fire_lpticks) { cc_triggered = true; } diff --git a/samples/nrf5340/multiprotocol_rpmsg/prj.conf b/samples/nrf5340/multiprotocol_rpmsg/prj.conf index 0ac36bed354d..ef12069ce6c4 100644 --- a/samples/nrf5340/multiprotocol_rpmsg/prj.conf +++ b/samples/nrf5340/multiprotocol_rpmsg/prj.conf @@ -23,5 +23,5 @@ CONFIG_DEBUG_INFO=y CONFIG_EXCEPTION_STACK_TRACE=y CONFIG_NRF_802154_SER_RADIO=y -CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=3 +CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=2 CONFIG_IPC_SERVICE_BACKEND_RPMSG=y diff --git a/samples/peripheral/802154_phy_test/boards/nrf5340dk_nrf5340_cpunet.conf b/samples/peripheral/802154_phy_test/boards/nrf5340dk_nrf5340_cpunet.conf index 959584867a5d..c13e99e80c29 100644 --- a/samples/peripheral/802154_phy_test/boards/nrf5340dk_nrf5340_cpunet.conf +++ b/samples/peripheral/802154_phy_test/boards/nrf5340dk_nrf5340_cpunet.conf @@ -1,2 +1,4 @@ # Include empty image in the APP core CONFIG_NCS_SAMPLE_EMPTY_APP_CORE_CHILD_IMAGE=y + +CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=2 diff --git a/samples/zigbee/light_switch/child_image/multiprotocol_rpmsg/boards/nrf5340dk_nrf5340_cpunet_fota.conf b/samples/zigbee/light_switch/child_image/multiprotocol_rpmsg/boards/nrf5340dk_nrf5340_cpunet_fota.conf index 772e394e3fa0..bb3baf56c83c 100644 --- a/samples/zigbee/light_switch/child_image/multiprotocol_rpmsg/boards/nrf5340dk_nrf5340_cpunet_fota.conf +++ b/samples/zigbee/light_switch/child_image/multiprotocol_rpmsg/boards/nrf5340dk_nrf5340_cpunet_fota.conf @@ -29,5 +29,5 @@ CONFIG_DEBUG_INFO=y CONFIG_EXCEPTION_STACK_TRACE=y CONFIG_NRF_802154_SER_RADIO=y -CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=3 +CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=2 CONFIG_IPC_SERVICE_BACKEND_RPMSG=y diff --git a/subsys/debug/ppi_trace/ppi_trace.c b/subsys/debug/ppi_trace/ppi_trace.c index f2b312cec268..ea14563203c6 100644 --- a/subsys/debug/ppi_trace/ppi_trace.c +++ b/subsys/debug/ppi_trace/ppi_trace.c @@ -196,6 +196,33 @@ void *ppi_trace_pair_config(uint32_t pin, uint32_t start_evt, uint32_t stop_evt) #endif } +int ppi_trace_dppi_ch_trace(uint32_t pin, uint32_t dppi_ch) +{ +#ifdef DPPI_PRESENT + uint32_t task; + int gpiote_ch; + nrf_gpiote_task_t task_id; + + gpiote_ch = gpiote_channel_alloc(pin); + if (gpiote_ch < 0) { + LOG_ERR("Failed to allocate GPIOTE channel."); + return -ENOMEM; + } + + task_id = offsetof(NRF_GPIOTE_Type, TASKS_OUT[gpiote_ch]); + task = nrf_gpiote_task_address_get(NRF_GPIOTE, task_id); + + *SUBSCRIBE_ADDR(task) = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | dppi_ch; + + return 0; +#else + (void)pin; + (void)dppi_ch; + + return -ENOTSUP; +#endif +} + static uint32_t ppi_channel_mask_get(void *handle) { return IS_PAIR(handle) ? diff --git a/subsys/mpsl/init/mpsl_init.c b/subsys/mpsl/init/mpsl_init.c index 8f958d825964..0015e258fa40 100644 --- a/subsys/mpsl/init/mpsl_init.c +++ b/subsys/mpsl/init/mpsl_init.c @@ -26,6 +26,8 @@ LOG_MODULE_REGISTER(mpsl_init, CONFIG_MPSL_LOG_LEVEL); const uint32_t z_mpsl_used_nrf_ppi_channels = MPSL_RESERVED_PPI_CHANNELS; const uint32_t z_mpsl_used_nrf_ppi_groups; +extern void rtc_pretick_rtc0_isr_hook(void); + #if IS_ENABLED(CONFIG_SOC_COMPATIBLE_NRF52X) #define MPSL_LOW_PRIO_IRQn SWI5_IRQn #elif IS_ENABLED(CONFIG_SOC_SERIES_NRF53X) @@ -87,6 +89,11 @@ static void mpsl_rtc0_isr_wrapper(const void *args) { ARG_UNUSED(args); + if (IS_ENABLED(CONFIG_SOC_NRF53_RTC_PRETICK) && + IS_ENABLED(CONFIG_SOC_NRF5340_CPUNET)) { + rtc_pretick_rtc0_isr_hook(); + } + MPSL_IRQ_RTC0_Handler(); ISR_DIRECT_PM(); @@ -139,6 +146,10 @@ ISR_DIRECT_DECLARE(mpsl_timer0_isr_wrapper) ISR_DIRECT_DECLARE(mpsl_rtc0_isr_wrapper) { + if (IS_ENABLED(CONFIG_SOC_NRF53_RTC_PRETICK) && + IS_ENABLED(CONFIG_SOC_NRF5340_CPUNET)) { + rtc_pretick_rtc0_isr_hook(); + } MPSL_IRQ_RTC0_Handler(); ISR_DIRECT_PM(); diff --git a/west.yml b/west.yml index 47feb2e720ab..344b48a40b9d 100644 --- a/west.yml +++ b/west.yml @@ -59,7 +59,7 @@ manifest: # https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/guides/modules.html - name: zephyr repo-path: sdk-zephyr - revision: v3.3.99-ncs1-2 + revision: pull/1958/head import: # In addition to the zephyr repository itself, NCS also # imports the contents of zephyr/west.yml at the above @@ -131,7 +131,7 @@ manifest: - name: nrfxlib repo-path: sdk-nrfxlib path: nrfxlib - revision: v2.4.3 + revision: pull/1442/head - name: trusted-firmware-m repo-path: sdk-trusted-firmware-m path: modules/tee/tf-m/trusted-firmware-m