Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP][DNM] KRKNWK-19361 v2.4 branch yoda fixes v2 #16924

21 changes: 21 additions & 0 deletions include/debug/ppi_trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#ifndef __PPI_TRACE_H
#define __PPI_TRACE_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,35 @@
#include <zephyr/kernel.h>

#include <zephyr/drivers/timer/nrf_rtc_timer.h>
#include <zephyr/sys/barrier.h>
#include <hal/nrf_rtc.h>
#include <helpers/nrfx_gppi.h>

#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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -270,40 +407,28 @@ 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);

/* For triggering to take place a safe margin is 2 lpticks from `now`. */
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;
}
Expand All @@ -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);
Expand All @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion samples/nrf5340/multiprotocol_rpmsg/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
27 changes: 27 additions & 0 deletions subsys/debug/ppi_trace/ppi_trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) ?
Expand Down
Loading
Loading