2689 lines
82 KiB
C
2689 lines
82 KiB
C
/*
|
|
* Copyright (c) 2019 - 2023, Nordic Semiconductor ASA
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
|
|
* contributors may be used to endorse or promote products derived from this
|
|
* software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
#define NRF_802154_MODULE_ID NRF_802154_DRV_MODULE_ID_TRX
|
|
|
|
#include "nrf_802154_trx.h"
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
#include "nrf_802154_config.h"
|
|
#include "nrf_802154_const.h"
|
|
#include "nrf_802154_peripherals.h"
|
|
#include "nrf_802154_pib.h"
|
|
#include "nrf_802154_rssi.h"
|
|
#include "nrf_802154_swi.h"
|
|
#include "nrf_802154_trx_ppi_api.h"
|
|
#include "nrf_802154_utils.h"
|
|
|
|
#include "hal/nrf_egu.h"
|
|
#include "hal/nrf_radio.h"
|
|
#include "hal/nrf_timer.h"
|
|
#if defined(NRF53_SERIES)
|
|
#include "hal/nrf_vreqctrl.h"
|
|
#endif
|
|
|
|
#include "nrf_802154_procedures_duration.h"
|
|
#include "nrf_802154_critical_section.h"
|
|
#include "mpsl_fem_config_common.h"
|
|
#include "platform/nrf_802154_irq.h"
|
|
#include "protocol/mpsl_fem_protocol_api.h"
|
|
|
|
#include "nrf_802154_sl_ant_div.h"
|
|
|
|
#ifdef NRF_802154_USE_INTERNAL_INCLUDES
|
|
#include "nrf_802154_trx_internal.h"
|
|
#endif
|
|
|
|
#define EGU_SYNC_EVENT NRF_EGU_EVENT_TRIGGERED3
|
|
#define EGU_SYNC_TASK NRF_EGU_TASK_TRIGGER3
|
|
#define EGU_SYNC_INTMASK NRF_EGU_INT_TRIGGERED3
|
|
|
|
#if defined(NRF52840_XXAA) || \
|
|
defined(NRF52833_XXAA)
|
|
#define PPI_CCAIDLE_FEM NRF_802154_PPI_RADIO_CCAIDLE_TO_FEM_GPIOTE ///< PPI that connects RADIO CCAIDLE event with GPIOTE tasks used by FEM
|
|
#define PPI_CHGRP_ABORT NRF_802154_PPI_ABORT_GROUP ///< PPI group used to disable PPIs when async event aborting radio operation is propagated through the system
|
|
#define RADIO_BASE NRF_RADIO_BASE
|
|
#elif defined(NRF5340_XXAA)
|
|
#define PPI_CCAIDLE_FEM 0
|
|
#define RADIO_BASE NRF_RADIO_NS_BASE
|
|
#define FICR_BASE NRF_FICR_NS_BASE
|
|
#endif
|
|
|
|
#define SHORT_ADDRESS_BCSTART NRF_RADIO_SHORT_ADDRESS_BCSTART_MASK
|
|
|
|
/// Value set to SHORTS register when no shorts should be enabled.
|
|
#define SHORTS_IDLE 0
|
|
|
|
/// Value set to SHORTS register for RX operation.
|
|
#define SHORTS_RX (NRF_RADIO_SHORT_ADDRESS_RSSISTART_MASK | \
|
|
NRF_RADIO_SHORT_END_DISABLE_MASK | \
|
|
SHORT_ADDRESS_BCSTART)
|
|
|
|
#define SHORTS_RX_FREE_BUFFER (NRF_RADIO_SHORT_RXREADY_START_MASK)
|
|
|
|
#define SHORTS_TX_ACK (NRF_RADIO_SHORT_TXREADY_START_MASK | \
|
|
NRF_RADIO_SHORT_PHYEND_DISABLE_MASK)
|
|
|
|
#define SHORTS_CCA_TX (NRF_RADIO_SHORT_RXREADY_CCASTART_MASK | \
|
|
NRF_RADIO_SHORT_CCABUSY_DISABLE_MASK | \
|
|
NRF_RADIO_SHORT_CCAIDLE_TXEN_MASK | \
|
|
NRF_RADIO_SHORT_TXREADY_START_MASK | \
|
|
NRF_RADIO_SHORT_PHYEND_DISABLE_MASK)
|
|
|
|
#define SHORTS_TX (NRF_RADIO_SHORT_TXREADY_START_MASK | \
|
|
NRF_RADIO_SHORT_PHYEND_DISABLE_MASK)
|
|
|
|
#define SHORTS_RX_ACK (NRF_RADIO_SHORT_ADDRESS_RSSISTART_MASK | \
|
|
NRF_RADIO_SHORT_END_DISABLE_MASK)
|
|
|
|
#define SHORTS_MOD_CARRIER (NRF_RADIO_SHORT_TXREADY_START_MASK | \
|
|
NRF_RADIO_SHORT_PHYEND_START_MASK)
|
|
|
|
#define SHORTS_ED (NRF_RADIO_SHORT_READY_EDSTART_MASK)
|
|
|
|
#define SHORTS_CCA (NRF_RADIO_SHORT_RXREADY_CCASTART_MASK | \
|
|
NRF_RADIO_SHORT_CCABUSY_DISABLE_MASK)
|
|
|
|
#define CRC_LENGTH 2 ///< Length of CRC in 802.15.4 frames [bytes]
|
|
#define CRC_POLYNOMIAL 0x011021 ///< Polynomial used for CRC calculation in 802.15.4 frames
|
|
|
|
#define TXRU_TIME 40 ///< Transmitter ramp up time [us]
|
|
#define EVENT_LAT 23 ///< END event latency [us]
|
|
#define MAX_RXRAMPDOWN_CYCLES 32 ///< Maximum number of cycles that RX ramp-down might take
|
|
|
|
#define RSSI_SETTLE_TIME_US 15 ///< Time required for RSSI measurements to become valid after signal level change.
|
|
|
|
#if NRF_802154_INTERNAL_RADIO_IRQ_HANDLING
|
|
void nrf_802154_radio_irq_handler(void); ///< Prototype required by internal RADIO IRQ handler
|
|
#endif // NRF_802154_INTERNAL_RADIO_IRQ_HANDLING
|
|
|
|
#ifndef NRF_802154_TRX_ENABLE_INTERNAL
|
|
#define NRF_802154_TRX_ENABLE_INTERNAL() \
|
|
do \
|
|
{ \
|
|
} \
|
|
while (0)
|
|
#endif
|
|
|
|
#ifndef NRF_802154_TRX_RADIO_RESET_INTERNAL
|
|
#define NRF_802154_TRX_RADIO_RESET_INTERNAL() \
|
|
do \
|
|
{ \
|
|
} \
|
|
while (0)
|
|
#endif
|
|
|
|
#ifndef NRF_802154_TRX_TEST_MODE_ALLOW_LATE_TX_ACK
|
|
#define NRF_802154_TRX_TEST_MODE_ALLOW_LATE_TX_ACK 0
|
|
#endif
|
|
|
|
/// Common parameters for the FEM handling.
|
|
static const mpsl_fem_event_t m_activate_rx_cc0 =
|
|
{
|
|
.type = MPSL_FEM_EVENT_TYPE_TIMER,
|
|
.event.timer =
|
|
{
|
|
.p_timer_instance = NRF_802154_TIMER_INSTANCE,
|
|
.compare_channel_mask = ((1 << NRF_TIMER_CC_CHANNEL0) | (1 << NRF_TIMER_CC_CHANNEL2)),
|
|
.counter_period = {
|
|
.end = RX_RAMP_UP_TIME
|
|
},
|
|
},
|
|
};
|
|
|
|
static const mpsl_fem_event_t m_activate_tx_cc0 =
|
|
{
|
|
.type = MPSL_FEM_EVENT_TYPE_TIMER,
|
|
.event.timer =
|
|
{
|
|
.p_timer_instance = NRF_802154_TIMER_INSTANCE,
|
|
.compare_channel_mask = ((1 << NRF_TIMER_CC_CHANNEL0) | (1 << NRF_TIMER_CC_CHANNEL2)),
|
|
.counter_period = {
|
|
.end = TX_RAMP_UP_TIME
|
|
},
|
|
},
|
|
};
|
|
|
|
static const mpsl_fem_event_t m_ccaidle =
|
|
{
|
|
.type = MPSL_FEM_EVENT_TYPE_GENERIC,
|
|
#if defined(NRF52_SERIES)
|
|
.override_ppi = true,
|
|
.ppi_ch_id = PPI_CCAIDLE_FEM,
|
|
.event.generic.event = ((uint32_t)RADIO_BASE + (uint32_t)NRF_RADIO_EVENT_CCAIDLE)
|
|
#elif defined(NRF53_SERIES)
|
|
.event.generic.event = NRF_802154_DPPI_RADIO_CCAIDLE
|
|
#endif
|
|
};
|
|
|
|
/**@brief Fal event used by @ref nrf_802154_trx_transmit_ack and @ref txack_finish */
|
|
static mpsl_fem_event_t m_activate_tx_cc0_timeshifted;
|
|
|
|
static volatile trx_state_t m_trx_state;
|
|
|
|
typedef struct
|
|
{
|
|
bool psdu_being_received; ///< If PSDU is currently being received.
|
|
bool missing_receive_buffer; ///!< If trx entered receive state without receive buffer
|
|
bool rxstarted_notif_en;
|
|
bool ccastarted_notif_en;
|
|
bool tx_started; ///< If the requested transmission has started.
|
|
bool rssi_started;
|
|
volatile bool rssi_settled;
|
|
} nrf_802154_flags_t;
|
|
|
|
static nrf_802154_flags_t m_flags; ///< Flags used to store the current driver state.
|
|
|
|
/** @brief Value of TIMER internal counter from which the counting is resumed on RADIO.EVENTS_END event. */
|
|
static volatile uint32_t m_timer_value_on_radio_end_event;
|
|
static volatile bool m_transmit_with_cca;
|
|
|
|
static void timer_frequency_set_1mhz(void);
|
|
|
|
static void rxframe_finish_disable_ppis(void);
|
|
static void rxack_finish_disable_ppis(void);
|
|
static void txframe_finish_disable_ppis(bool cca);
|
|
|
|
static void go_idle_abort(void);
|
|
static void receive_frame_abort(void);
|
|
static void receive_ack_abort(void);
|
|
static void transmit_frame_abort(void);
|
|
static void transmit_ack_abort(void);
|
|
static void standalone_cca_abort(void);
|
|
|
|
#if NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
static void continuous_carrier_abort(void);
|
|
static void modulated_carrier_abort(void);
|
|
|
|
#endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
static void energy_detection_abort(void);
|
|
|
|
/** Clear flags describing frame being received. */
|
|
void rx_flags_clear(void)
|
|
{
|
|
m_flags.missing_receive_buffer = false;
|
|
m_flags.psdu_being_received = false;
|
|
}
|
|
|
|
static void * volatile mp_receive_buffer;
|
|
|
|
static void txpower_set(nrf_radio_txpower_t txpower)
|
|
{
|
|
#ifdef NRF53_SERIES
|
|
bool radio_high_voltage_enable = false;
|
|
|
|
if ((int8_t)txpower > 0)
|
|
{
|
|
/* To get higher than 0dBm raise operating voltage of the radio, giving 3dBm power boost */
|
|
radio_high_voltage_enable = true;
|
|
txpower -= 3;
|
|
}
|
|
nrf_vreqctrl_radio_high_voltage_set(NRF_VREQCTRL_NS, radio_high_voltage_enable);
|
|
#endif
|
|
nrf_radio_txpower_set(NRF_RADIO, txpower);
|
|
}
|
|
|
|
/** Initialize TIMER peripheral used by the driver. */
|
|
void nrf_timer_init(void)
|
|
{
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
nrf_timer_mode_set(NRF_802154_TIMER_INSTANCE, NRF_TIMER_MODE_TIMER);
|
|
nrf_timer_bit_width_set(NRF_802154_TIMER_INSTANCE, NRF_TIMER_BIT_WIDTH_32);
|
|
timer_frequency_set_1mhz();
|
|
}
|
|
|
|
#if defined(NRF53_SERIES)
|
|
/** Implement the YOPAN-158 workaround. */
|
|
static void yopan_158_workaround(void)
|
|
{
|
|
#define RADIO_ADDRESS_MASK 0xFFFFF000UL
|
|
#define FICR_TRIM_REGISTERS_COUNT 32UL
|
|
/* This is a workaround for an issue reported in YOPAN-158.
|
|
*
|
|
* After RADIO peripheral reset with RADIO.POWER register the trim-values, loaded from FICR at
|
|
* network core boot time by MDK, are lost. The trim-values are not preserved and re-applied by
|
|
* hardware.
|
|
*
|
|
* Only selected trim-values are restored, those that apply to RADIO peripheral. The check
|
|
* is done based on destination address.
|
|
*/
|
|
|
|
/* Copy all the trimming values from FICR into the target addresses. Trim until one ADDR
|
|
is not initialized. */
|
|
for (uint32_t index = 0; index < FICR_TRIM_REGISTERS_COUNT; index++)
|
|
{
|
|
if (((volatile uint32_t *)((volatile uintptr_t)NRF_FICR_NS->TRIMCNF[index].ADDR &
|
|
(uintptr_t)RADIO_ADDRESS_MASK) == (uint32_t *)NRF_RADIO))
|
|
{
|
|
*((volatile uint32_t *)NRF_FICR_NS->TRIMCNF[index].ADDR) =
|
|
NRF_FICR_NS->TRIMCNF[index].DATA;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif /* NRF53_SERIES */
|
|
|
|
/** Sets the frequency of 1 MHz for NRF_802154_TIMER_INSTANCE. */
|
|
static void timer_frequency_set_1mhz(void)
|
|
{
|
|
uint32_t base_frequency = NRF_TIMER_BASE_FREQUENCY_GET(NRF_802154_TIMER_INSTANCE);
|
|
uint32_t prescaler = 31 - NRF_CLZ(base_frequency / 1000000);
|
|
|
|
nrf_timer_prescaler_set(NRF_802154_TIMER_INSTANCE, prescaler);
|
|
}
|
|
|
|
/** Reset radio peripheral. */
|
|
static void nrf_radio_reset(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
#if defined(RADIO_POWER_POWER_Msk)
|
|
nrf_radio_power_set(NRF_RADIO, false);
|
|
nrf_radio_power_set(NRF_RADIO, true);
|
|
#endif
|
|
|
|
NRF_802154_TRX_RADIO_RESET_INTERNAL();
|
|
|
|
#if defined(NRF53_SERIES)
|
|
yopan_158_workaround();
|
|
#endif /* NRF53_SERIES */
|
|
|
|
nrf_802154_log_global_event(NRF_802154_LOG_VERBOSITY_LOW,
|
|
NRF_802154_LOG_GLOBAL_EVENT_ID_RADIO_RESET,
|
|
0U);
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
static void channel_set(uint8_t channel)
|
|
{
|
|
assert(channel >= 11U && channel <= 26U);
|
|
|
|
nrf_radio_frequency_set(NRF_RADIO, 2405U + 5U * (channel - 11U));
|
|
}
|
|
|
|
static void cca_configuration_update(void)
|
|
{
|
|
nrf_802154_cca_cfg_t cca_cfg;
|
|
|
|
nrf_802154_pib_cca_cfg_get(&cca_cfg);
|
|
nrf_radio_cca_configure(NRF_RADIO,
|
|
cca_cfg.mode,
|
|
nrf_802154_rssi_cca_ed_threshold_corrected_get(cca_cfg.ed_threshold),
|
|
cca_cfg.corr_threshold,
|
|
cca_cfg.corr_limit);
|
|
}
|
|
|
|
/** Initialize interrupts for radio peripheral. */
|
|
static void irq_init(void)
|
|
{
|
|
#if NRF_802154_INTERNAL_RADIO_IRQ_HANDLING
|
|
nrf_802154_irq_init(nrfx_get_irq_number(NRF_RADIO),
|
|
NRF_802154_IRQ_PRIORITY,
|
|
nrf_802154_radio_irq_handler);
|
|
#endif
|
|
nrf_802154_irq_enable(nrfx_get_irq_number(NRF_RADIO));
|
|
}
|
|
|
|
static void trigger_disable_to_start_rampup(void)
|
|
{
|
|
if (!nrf_802154_trx_ppi_for_ramp_up_was_triggered())
|
|
{
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_DISABLED);
|
|
}
|
|
}
|
|
|
|
/** Configure FEM to set LNA at appropriate time. */
|
|
static void fem_for_lna_set(void)
|
|
{
|
|
if (mpsl_fem_lna_configuration_set(&m_activate_rx_cc0, NULL) == 0)
|
|
{
|
|
nrf_timer_shorts_enable(m_activate_rx_cc0.event.timer.p_timer_instance,
|
|
NRF_TIMER_SHORT_COMPARE0_STOP_MASK);
|
|
|
|
nrf_802154_trx_ppi_for_fem_set();
|
|
}
|
|
}
|
|
|
|
/** Reset FEM configuration for LNA. */
|
|
static void fem_for_lna_reset(void)
|
|
{
|
|
mpsl_fem_lna_configuration_clear();
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
nrf_timer_shorts_disable(NRF_802154_TIMER_INSTANCE, NRF_TIMER_SHORT_COMPARE0_STOP_MASK);
|
|
nrf_802154_trx_ppi_for_fem_clear();
|
|
/* There is no need to explicitly deactivate LNA pin during reset as mpsl_fem_abort_set is used
|
|
* to provide a deactivation mechanism on DISABLED event.
|
|
*/
|
|
}
|
|
|
|
#if NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
|
|
/** Configure FEM to set PA at appropriate time.
|
|
*
|
|
* @note This function must be called before ramp up PPIs are configured.
|
|
*/
|
|
static void fem_for_pa_set(const mpsl_fem_gain_t * p_fem_gain_data)
|
|
{
|
|
(void)mpsl_fem_pa_gain_set(p_fem_gain_data);
|
|
if (mpsl_fem_pa_configuration_set(&m_activate_tx_cc0, NULL) == 0)
|
|
{
|
|
nrf_timer_shorts_enable(m_activate_tx_cc0.event.timer.p_timer_instance,
|
|
NRF_TIMER_SHORT_COMPARE0_STOP_MASK);
|
|
nrf_802154_trx_ppi_for_fem_set();
|
|
}
|
|
}
|
|
|
|
/** Reset FEM configuration for PA.
|
|
*
|
|
* @note This function must be called before ramp up PPIs are configured.
|
|
*/
|
|
static void fem_for_pa_reset(void)
|
|
{
|
|
mpsl_fem_pa_configuration_clear();
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
nrf_802154_trx_ppi_for_fem_clear();
|
|
mpsl_fem_deactivate_now(MPSL_FEM_PA);
|
|
}
|
|
|
|
#endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
|
|
/** Configure FEM for TX procedure.
|
|
*
|
|
* @note This function must be called before ramp up PPIs are configured.
|
|
*/
|
|
static void fem_for_tx_set(bool cca, const mpsl_fem_gain_t * p_fem_gain_data)
|
|
{
|
|
bool success;
|
|
|
|
(void)mpsl_fem_pa_gain_set(p_fem_gain_data);
|
|
|
|
if (cca)
|
|
{
|
|
bool pa_set = false;
|
|
bool lna_set = false;
|
|
|
|
if (mpsl_fem_lna_configuration_set(&m_activate_rx_cc0, &m_ccaidle) == 0)
|
|
{
|
|
lna_set = true;
|
|
}
|
|
|
|
if (mpsl_fem_pa_configuration_set(&m_ccaidle, NULL) == 0)
|
|
{
|
|
pa_set = true;
|
|
}
|
|
|
|
success = pa_set || lna_set;
|
|
|
|
}
|
|
else
|
|
{
|
|
success = (mpsl_fem_pa_configuration_set(&m_activate_tx_cc0, NULL) == 0);
|
|
}
|
|
|
|
if (success)
|
|
{
|
|
nrf_timer_shorts_enable(NRF_802154_TIMER_INSTANCE, NRF_TIMER_SHORT_COMPARE0_STOP_MASK);
|
|
nrf_802154_trx_ppi_for_fem_set();
|
|
}
|
|
}
|
|
|
|
static void fem_for_tx_reset(bool cca)
|
|
{
|
|
nrf_timer_shorts_disable(NRF_802154_TIMER_INSTANCE, NRF_TIMER_SHORT_COMPARE0_STOP_MASK);
|
|
|
|
if (cca)
|
|
{
|
|
mpsl_fem_lna_configuration_clear();
|
|
mpsl_fem_pa_configuration_clear();
|
|
}
|
|
else
|
|
{
|
|
mpsl_fem_pa_configuration_clear();
|
|
}
|
|
|
|
nrf_802154_trx_ppi_for_fem_clear();
|
|
nrf_802154_trx_ppi_for_ramp_up_propagation_delay_wait();
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
}
|
|
|
|
#if defined(NRF52840_XXAA) || \
|
|
defined(NRF52833_XXAA)
|
|
/** @brief Applies DEVICE-CONFIG-254.
|
|
*
|
|
* Shall be called after every RADIO peripheral reset.
|
|
*/
|
|
static void device_config_254_apply_tx(void)
|
|
{
|
|
uint32_t ficr_reg1 = *(volatile uint32_t *)0x10000330UL;
|
|
uint32_t ficr_reg2 = *(volatile uint32_t *)0x10000334UL;
|
|
uint32_t ficr_reg3 = *(volatile uint32_t *)0x10000338UL;
|
|
|
|
/* Check if the device is fixed by testing every FICR register's value separately. */
|
|
if (ficr_reg1 != 0xffffffffUL)
|
|
{
|
|
volatile uint32_t * p_radio_reg1 = (volatile uint32_t *)0x4000174cUL;
|
|
|
|
*p_radio_reg1 = ficr_reg1;
|
|
}
|
|
|
|
if (ficr_reg2 != 0xffffffffUL)
|
|
{
|
|
volatile uint32_t * p_radio_reg2 = (volatile uint32_t *)0x40001584UL;
|
|
|
|
*p_radio_reg2 = ficr_reg2;
|
|
}
|
|
|
|
if (ficr_reg3 != 0xffffffffUL)
|
|
{
|
|
volatile uint32_t * p_radio_reg3 = (volatile uint32_t *)0x40001588UL;
|
|
|
|
*p_radio_reg3 = ficr_reg3;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/** @brief Applies ERRATA-117
|
|
*
|
|
* Shall be called after setting RADIO mode to NRF_RADIO_MODE_IEEE802154_250KBIT.
|
|
*/
|
|
#if defined(NRF5340_XXAA)
|
|
static void errata_117_apply(void)
|
|
{
|
|
/* Register at 0x01FF0084. */
|
|
uint32_t ficr_reg = *(volatile uint32_t *)(FICR_BASE + 0x84UL);
|
|
/* Register at 0x41008588. */
|
|
volatile uint32_t * p_radio_reg = (volatile uint32_t *)(RADIO_BASE + 0x588UL);
|
|
|
|
*p_radio_reg = ficr_reg;
|
|
}
|
|
|
|
#endif
|
|
|
|
static inline void wait_until_radio_is_disabled(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
bool radio_is_disabled = false;
|
|
|
|
// RADIO should enter DISABLED state after no longer than RX ramp-down time, which is equal
|
|
// approximately 0.5us. Taking a bold assumption that a single iteration of the loop takes
|
|
// one cycle to complete, 32 iterations would amount to exactly 0.5 us of execution time.
|
|
// Please note that this approach ignores software latency completely, i.e. RADIO should
|
|
// have changed state already before entering this function due to ISR processing delays.
|
|
for (uint32_t i = 0; i < MAX_RXRAMPDOWN_CYCLES; i++)
|
|
{
|
|
if (nrf_radio_state_get(NRF_RADIO) == NRF_RADIO_STATE_DISABLED)
|
|
{
|
|
radio_is_disabled = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert(radio_is_disabled);
|
|
(void)radio_is_disabled;
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
void nrf_802154_trx_module_reset(void)
|
|
{
|
|
m_trx_state = TRX_STATE_DISABLED;
|
|
m_timer_value_on_radio_end_event = 0;
|
|
m_transmit_with_cca = false;
|
|
mp_receive_buffer = NULL;
|
|
|
|
memset(&m_flags, 0, sizeof(m_flags));
|
|
}
|
|
|
|
void nrf_802154_trx_init(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
nrf_802154_trx_module_reset();
|
|
|
|
#if defined(RADIO_INTENSET_SYNC_Msk)
|
|
nrf_802154_swi_init();
|
|
#endif
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
void nrf_802154_trx_enable(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
assert(m_trx_state == TRX_STATE_DISABLED);
|
|
|
|
nrf_timer_init();
|
|
nrf_radio_reset();
|
|
|
|
#if defined(NRF52840_XXAA) || \
|
|
defined(NRF52833_XXAA)
|
|
// Apply DEVICE-CONFIG-254 if needed.
|
|
if (mpsl_fem_device_config_254_apply_get())
|
|
{
|
|
device_config_254_apply_tx();
|
|
}
|
|
#endif
|
|
|
|
nrf_radio_packet_conf_t packet_conf;
|
|
|
|
nrf_radio_mode_set(NRF_RADIO, NRF_RADIO_MODE_IEEE802154_250KBIT);
|
|
|
|
#if defined(NRF5340_XXAA)
|
|
// Apply ERRATA-117 after setting RADIO mode to NRF_RADIO_MODE_IEEE802154_250KBIT.
|
|
errata_117_apply();
|
|
#endif
|
|
|
|
memset(&packet_conf, 0, sizeof(packet_conf));
|
|
packet_conf.lflen = 8;
|
|
packet_conf.plen = NRF_RADIO_PREAMBLE_LENGTH_32BIT_ZERO;
|
|
packet_conf.crcinc = true;
|
|
packet_conf.maxlen = MAX_PACKET_SIZE;
|
|
nrf_radio_packet_configure(NRF_RADIO, &packet_conf);
|
|
|
|
NRF_802154_TRX_ENABLE_INTERNAL();
|
|
|
|
#if defined(RADIO_MODECNF0_RU_Msk)
|
|
nrf_radio_modecnf0_set(NRF_RADIO, true, 0);
|
|
#endif
|
|
|
|
// Configure CRC
|
|
nrf_radio_crc_configure(NRF_RADIO, CRC_LENGTH, NRF_RADIO_CRC_ADDR_IEEE802154, CRC_POLYNOMIAL);
|
|
|
|
nrf_802154_trx_ppi_for_enable();
|
|
|
|
// Configure CCA
|
|
cca_configuration_update();
|
|
|
|
// Set channel
|
|
channel_set(nrf_802154_pib_channel_get());
|
|
|
|
// Custom initialization operations
|
|
nrf_802154_custom_part_of_radio_init();
|
|
|
|
irq_init();
|
|
|
|
assert(nrf_radio_shorts_get(NRF_RADIO) == SHORTS_IDLE);
|
|
|
|
#if defined(NRF52840_XXAA) || \
|
|
defined(NRF52833_XXAA)
|
|
mpsl_fem_abort_set(nrf_radio_event_address_get(NRF_RADIO, NRF_RADIO_EVENT_DISABLED),
|
|
PPI_CHGRP_ABORT);
|
|
#elif defined(NRF53_SERIES)
|
|
mpsl_fem_abort_set(NRF_802154_DPPI_RADIO_DISABLED,
|
|
0U); /* The group parameter is ignored by FEM for nRF53 */
|
|
#endif
|
|
|
|
mpsl_fem_deactivate_now(MPSL_FEM_ALL);
|
|
|
|
m_trx_state = TRX_STATE_IDLE;
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
static void ppi_all_clear(void)
|
|
{
|
|
switch (m_trx_state)
|
|
{
|
|
case TRX_STATE_IDLE:
|
|
case TRX_STATE_GOING_IDLE:
|
|
case TRX_STATE_RXFRAME_FINISHED:
|
|
case TRX_STATE_FINISHED:
|
|
// Intentionally empty. PPIs are not configured in this state.
|
|
break;
|
|
|
|
case TRX_STATE_RXFRAME:
|
|
rxframe_finish_disable_ppis();
|
|
break;
|
|
|
|
case TRX_STATE_RXACK:
|
|
rxack_finish_disable_ppis();
|
|
nrf_802154_trx_ppi_for_fem_clear();
|
|
break;
|
|
|
|
case TRX_STATE_TXFRAME:
|
|
txframe_finish_disable_ppis(m_transmit_with_cca);
|
|
nrf_802154_trx_ppi_for_fem_clear();
|
|
break;
|
|
|
|
case TRX_STATE_TXACK:
|
|
nrf_802154_trx_ppi_for_ack_tx_clear();
|
|
// FEM PPIs are not configured for this state. TIMER was started in TRX_STATE_RXFRAME
|
|
// and PPIs starting timer were cleared when exiting TRX_STATE_RXFRAME.
|
|
break;
|
|
|
|
case TRX_STATE_STANDALONE_CCA:
|
|
nrf_802154_trx_ppi_for_ramp_up_clear(NRF_RADIO_TASK_RXEN, false);
|
|
nrf_802154_trx_ppi_for_fem_clear();
|
|
break;
|
|
|
|
#if NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
case TRX_STATE_CONTINUOUS_CARRIER:
|
|
nrf_802154_trx_ppi_for_ramp_up_clear(NRF_RADIO_TASK_TXEN, false);
|
|
nrf_802154_trx_ppi_for_fem_clear();
|
|
break;
|
|
|
|
case TRX_STATE_MODULATED_CARRIER:
|
|
nrf_802154_trx_ppi_for_ramp_up_clear(NRF_RADIO_TASK_TXEN, false);
|
|
nrf_802154_trx_ppi_for_fem_clear();
|
|
break;
|
|
#endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
|
|
case TRX_STATE_ENERGY_DETECTION:
|
|
nrf_802154_trx_ppi_for_ramp_up_clear(NRF_RADIO_TASK_RXEN, false);
|
|
nrf_802154_trx_ppi_for_fem_clear();
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
}
|
|
nrf_802154_trx_ppi_for_disable();
|
|
}
|
|
|
|
static void fem_power_down_now(void)
|
|
{
|
|
mpsl_fem_deactivate_now(MPSL_FEM_ALL);
|
|
mpsl_fem_disable();
|
|
}
|
|
|
|
void nrf_802154_trx_disable(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
if (m_trx_state != TRX_STATE_DISABLED)
|
|
{
|
|
#if defined(RADIO_POWER_POWER_Msk)
|
|
nrf_radio_power_set(NRF_RADIO, false);
|
|
#endif
|
|
nrf_802154_irq_clear_pending(nrfx_get_irq_number(NRF_RADIO));
|
|
|
|
/* While the RADIO is powered off deconfigure any PPIs used directly by trx module */
|
|
ppi_all_clear();
|
|
|
|
#if !defined(RADIO_POWER_POWER_Msk)
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
|
|
wait_until_radio_is_disabled();
|
|
nrf_radio_reset();
|
|
#endif
|
|
|
|
#if defined(RADIO_INTENSET_SYNC_Msk)
|
|
nrf_egu_int_disable(NRF_802154_EGU_INSTANCE, EGU_SYNC_INTMASK);
|
|
nrf_egu_event_clear(NRF_802154_EGU_INSTANCE, EGU_SYNC_EVENT);
|
|
#endif
|
|
|
|
/* Stop & deconfigure timer */
|
|
nrf_timer_shorts_disable(NRF_802154_TIMER_INSTANCE,
|
|
NRF_TIMER_SHORT_COMPARE0_STOP_MASK |
|
|
NRF_TIMER_SHORT_COMPARE1_STOP_MASK);
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
|
|
#if defined(RADIO_POWER_POWER_Msk)
|
|
nrf_radio_power_set(NRF_RADIO, true);
|
|
#endif
|
|
|
|
mpsl_fem_lna_configuration_clear();
|
|
mpsl_fem_pa_configuration_clear();
|
|
mpsl_fem_abort_clear();
|
|
|
|
if (m_trx_state != TRX_STATE_IDLE)
|
|
{
|
|
fem_power_down_now();
|
|
}
|
|
|
|
m_flags.psdu_being_received = false;
|
|
m_flags.missing_receive_buffer = false;
|
|
m_flags.rssi_started = false;
|
|
m_flags.tx_started = false;
|
|
|
|
m_trx_state = TRX_STATE_DISABLED;
|
|
|
|
nrf_802154_log_global_event(NRF_802154_LOG_VERBOSITY_LOW,
|
|
NRF_802154_LOG_GLOBAL_EVENT_ID_RADIO_RESET,
|
|
0U);
|
|
}
|
|
else
|
|
{
|
|
// Intentionally empty
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
static void rx_automatic_antenna_handle(void)
|
|
{
|
|
switch (m_trx_state)
|
|
{
|
|
case TRX_STATE_RXFRAME:
|
|
case TRX_STATE_RXFRAME_FINISHED:
|
|
nrf_802154_sl_ant_div_rx_started_notify();
|
|
break;
|
|
|
|
case TRX_STATE_ENERGY_DETECTION:
|
|
// Intentionally empty - notification is called from core when requesting energy detection.
|
|
// This is done due to possibility of nrf_802154_trx_energy_detection being called multiple times
|
|
// during one energy detection from the point of view of application, if the entire procedure does not
|
|
// fit in single timeslot.
|
|
break;
|
|
|
|
case TRX_STATE_TXACK:
|
|
nrf_802154_sl_ant_div_txack_notify();
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates the antenna for reception, according to antenna diversity configuration.
|
|
*/
|
|
static void rx_antenna_update(void)
|
|
{
|
|
bool result = true;
|
|
nrf_802154_sl_ant_div_mode_t mode = nrf_802154_sl_ant_div_cfg_mode_get(
|
|
NRF_802154_SL_ANT_DIV_OP_RX);
|
|
|
|
switch (mode)
|
|
{
|
|
case NRF_802154_SL_ANT_DIV_MODE_DISABLED:
|
|
break;
|
|
|
|
case NRF_802154_SL_ANT_DIV_MODE_MANUAL:
|
|
result = nrf_802154_sl_ant_div_antenna_set(
|
|
nrf_802154_sl_ant_div_cfg_antenna_get(NRF_802154_SL_ANT_DIV_OP_RX));
|
|
break;
|
|
|
|
case NRF_802154_SL_ANT_DIV_MODE_AUTO:
|
|
rx_automatic_antenna_handle();
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
|
|
assert(result);
|
|
(void)result;
|
|
}
|
|
|
|
/**
|
|
* Updates the antenna for transmission, according to antenna diversity configuration.
|
|
*
|
|
* Antenna diversity for tx is not currently supported. If antenna diversity is not
|
|
* in disabled state, default antenna will always be used for transmission.
|
|
*/
|
|
static void tx_antenna_update(void)
|
|
{
|
|
bool result = true;
|
|
nrf_802154_sl_ant_div_mode_t mode = nrf_802154_sl_ant_div_cfg_mode_get(
|
|
NRF_802154_SL_ANT_DIV_OP_TX);
|
|
|
|
switch (mode)
|
|
{
|
|
case NRF_802154_SL_ANT_DIV_MODE_DISABLED:
|
|
/* Intentionally empty. */
|
|
break;
|
|
|
|
case NRF_802154_SL_ANT_DIV_MODE_MANUAL:
|
|
result = nrf_802154_sl_ant_div_antenna_set(
|
|
nrf_802154_sl_ant_div_cfg_antenna_get(NRF_802154_SL_ANT_DIV_OP_TX));
|
|
break;
|
|
|
|
case NRF_802154_SL_ANT_DIV_MODE_AUTO:
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
|
|
if (!result)
|
|
{
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
void nrf_802154_trx_antenna_update(void)
|
|
{
|
|
assert(m_trx_state != TRX_STATE_DISABLED);
|
|
|
|
switch (m_trx_state)
|
|
{
|
|
case TRX_STATE_RXFRAME:
|
|
case TRX_STATE_RXFRAME_FINISHED:
|
|
case TRX_STATE_ENERGY_DETECTION:
|
|
case TRX_STATE_TXACK:
|
|
rx_antenna_update();
|
|
break;
|
|
|
|
case TRX_STATE_STANDALONE_CCA:
|
|
case TRX_STATE_RXACK:
|
|
case TRX_STATE_TXFRAME:
|
|
#if NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
case TRX_STATE_CONTINUOUS_CARRIER:
|
|
case TRX_STATE_MODULATED_CARRIER:
|
|
#endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
tx_antenna_update();
|
|
break;
|
|
|
|
default:
|
|
/* Intentionally empty */
|
|
break;
|
|
}
|
|
}
|
|
|
|
void nrf_802154_trx_channel_set(uint8_t channel)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
channel_set(channel);
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
void nrf_802154_trx_cca_configuration_update(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
cca_configuration_update();
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
/** Check if PSDU is currently being received.
|
|
*
|
|
* @returns True if radio is receiving PSDU, false otherwise.
|
|
*/
|
|
bool nrf_802154_trx_psdu_is_being_received(void)
|
|
{
|
|
return m_flags.psdu_being_received;
|
|
}
|
|
|
|
bool nrf_802154_trx_receive_is_buffer_missing(void)
|
|
{
|
|
switch (m_trx_state)
|
|
{
|
|
case TRX_STATE_RXFRAME:
|
|
/* no break */
|
|
case TRX_STATE_RXACK:
|
|
return m_flags.missing_receive_buffer;
|
|
|
|
default:
|
|
assert(!m_flags.missing_receive_buffer);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static void receive_buffer_missing_buffer_set(void * p_receive_buffer)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
uint32_t shorts = SHORTS_IDLE;
|
|
|
|
switch (m_trx_state)
|
|
{
|
|
case TRX_STATE_RXFRAME:
|
|
shorts = SHORTS_RX | SHORTS_RX_FREE_BUFFER;
|
|
break;
|
|
|
|
case TRX_STATE_RXACK:
|
|
shorts = SHORTS_RX_ACK | SHORTS_RX_FREE_BUFFER;
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
}
|
|
|
|
m_flags.missing_receive_buffer = false;
|
|
|
|
nrf_radio_packetptr_set(NRF_RADIO, p_receive_buffer);
|
|
|
|
nrf_radio_shorts_set(NRF_RADIO, shorts);
|
|
|
|
if (nrf_radio_state_get(NRF_RADIO) == NRF_RADIO_STATE_RXIDLE)
|
|
{
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_START);
|
|
}
|
|
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
bool nrf_802154_trx_receive_buffer_set(void * p_receive_buffer)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
bool result = false;
|
|
|
|
mp_receive_buffer = p_receive_buffer;
|
|
|
|
if ((p_receive_buffer != NULL) && m_flags.missing_receive_buffer)
|
|
{
|
|
receive_buffer_missing_buffer_set(p_receive_buffer);
|
|
result = true;
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
return result;
|
|
}
|
|
|
|
void nrf_802154_trx_receive_frame(uint8_t bcc,
|
|
nrf_802154_trx_ramp_up_trigger_mode_t rampup_trigg_mode,
|
|
nrf_802154_trx_receive_notifications_t notifications_mask,
|
|
const nrf_802154_fal_tx_power_split_t * p_ack_tx_power)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
uint32_t ints_to_enable = 0U;
|
|
uint32_t shorts = SHORTS_RX;
|
|
|
|
// Force the TIMER to be stopped and count from 0.
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
|
|
m_trx_state = TRX_STATE_RXFRAME;
|
|
|
|
// Clear filtering flag
|
|
rx_flags_clear();
|
|
|
|
m_flags.rxstarted_notif_en = (notifications_mask & TRX_RECEIVE_NOTIFICATION_STARTED) != 0U;
|
|
|
|
// Clear the RSSI measurement flag.
|
|
m_flags.rssi_started = false;
|
|
|
|
m_flags.rssi_settled = false;
|
|
|
|
txpower_set(p_ack_tx_power->radio_tx_power);
|
|
|
|
if (mp_receive_buffer != NULL)
|
|
{
|
|
m_flags.missing_receive_buffer = false;
|
|
nrf_radio_packetptr_set(NRF_RADIO, mp_receive_buffer);
|
|
shorts |= SHORTS_RX_FREE_BUFFER;
|
|
}
|
|
else
|
|
{
|
|
m_flags.missing_receive_buffer = true;
|
|
}
|
|
|
|
// Set shorts
|
|
nrf_radio_shorts_set(NRF_RADIO, shorts);
|
|
|
|
// Set BCC
|
|
assert(bcc != 0U);
|
|
nrf_radio_bcc_set(NRF_RADIO, bcc * 8U);
|
|
|
|
// Enable IRQs
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CRCERROR);
|
|
ints_to_enable |= NRF_RADIO_INT_CRCERROR_MASK;
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_BCMATCH);
|
|
ints_to_enable |= NRF_RADIO_INT_BCMATCH_MASK;
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CRCOK);
|
|
ints_to_enable |= NRF_RADIO_INT_CRCOK_MASK;
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_ADDRESS);
|
|
ints_to_enable |= NRF_RADIO_INT_ADDRESS_MASK;
|
|
|
|
if (rampup_trigg_mode == TRX_RAMP_UP_HW_TRIGGER)
|
|
{
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_READY);
|
|
ints_to_enable |= NRF_RADIO_INT_READY_MASK;
|
|
}
|
|
|
|
bool allow_sync_swi = false;
|
|
|
|
#ifdef RADIO_INTENSET_SYNC_Msk
|
|
if (((notifications_mask & TRX_RECEIVE_NOTIFICATION_PRESTARTED) != 0U) ||
|
|
(NRF_802154_SL_ANT_DIV_MODE_DISABLED !=
|
|
nrf_802154_sl_ant_div_cfg_mode_get(NRF_802154_SL_ANT_DIV_OP_RX)))
|
|
{
|
|
allow_sync_swi = true;
|
|
}
|
|
#endif
|
|
|
|
if (allow_sync_swi)
|
|
{
|
|
#if !defined(RADIO_INTENSET_SYNC_Msk)
|
|
assert(false);
|
|
#else
|
|
// The RADIO can't generate interrupt on EVENT_SYNC. Path to generate interrupt:
|
|
// RADIO.EVENT_SYNC -> PPI_RADIO_SYNC_EGU_SYNC -> EGU.TASK_SYNC -> EGU.EVENT_SYNC ->
|
|
// SWI_IRQHandler (in nrf_802154_swi.c), calls nrf_802154_trx_swi_irq_handler
|
|
nrf_802154_trx_ppi_for_radio_sync_set(EGU_SYNC_TASK);
|
|
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_SYNC);
|
|
nrf_egu_event_clear(NRF_802154_EGU_INSTANCE, EGU_SYNC_EVENT);
|
|
nrf_egu_int_enable(NRF_802154_EGU_INSTANCE, EGU_SYNC_INTMASK);
|
|
#endif
|
|
}
|
|
|
|
nrf_radio_int_enable(NRF_RADIO, ints_to_enable);
|
|
|
|
// Set FEM
|
|
uint32_t delta_time;
|
|
|
|
if (mpsl_fem_lna_configuration_set(&m_activate_rx_cc0, NULL) == 0)
|
|
{
|
|
delta_time = nrf_timer_cc_get(NRF_802154_TIMER_INSTANCE,
|
|
NRF_TIMER_CC_CHANNEL0);
|
|
}
|
|
else
|
|
{
|
|
delta_time = 1;
|
|
nrf_timer_cc_set(NRF_802154_TIMER_INSTANCE, NRF_TIMER_CC_CHANNEL0, delta_time);
|
|
}
|
|
|
|
// Set FEM PA gain for ACK transmission
|
|
mpsl_fem_pa_gain_set(&p_ack_tx_power->fem);
|
|
|
|
m_timer_value_on_radio_end_event = delta_time;
|
|
|
|
// Select antenna
|
|
nrf_802154_trx_antenna_update();
|
|
|
|
// Let the TIMER stop on last event required by a FEM
|
|
nrf_timer_shorts_enable(NRF_802154_TIMER_INSTANCE,
|
|
NRF_TIMER_SHORT_COMPARE0_STOP_MASK);
|
|
|
|
// Set PPIs
|
|
nrf_802154_trx_ppi_for_ramp_up_set(NRF_RADIO_TASK_RXEN, rampup_trigg_mode, true);
|
|
|
|
if (rampup_trigg_mode == TRX_RAMP_UP_SW_TRIGGER)
|
|
{
|
|
trigger_disable_to_start_rampup();
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
void nrf_802154_trx_receive_ack(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
uint32_t shorts = SHORTS_RX_ACK;
|
|
uint32_t ints_to_enable = 0U;
|
|
|
|
m_trx_state = TRX_STATE_RXACK;
|
|
|
|
if (mp_receive_buffer != NULL)
|
|
{
|
|
m_flags.missing_receive_buffer = false;
|
|
nrf_radio_packetptr_set(NRF_RADIO, mp_receive_buffer);
|
|
shorts |= SHORTS_RX_FREE_BUFFER;
|
|
}
|
|
else
|
|
{
|
|
m_flags.missing_receive_buffer = true;
|
|
}
|
|
|
|
nrf_radio_shorts_set(NRF_RADIO, shorts);
|
|
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_ADDRESS);
|
|
ints_to_enable |= NRF_RADIO_INT_ADDRESS_MASK;
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CRCOK);
|
|
ints_to_enable |= NRF_RADIO_INT_CRCOK_MASK;
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CRCERROR);
|
|
ints_to_enable |= NRF_RADIO_INT_CRCERROR_MASK;
|
|
|
|
nrf_radio_int_enable(NRF_RADIO, ints_to_enable);
|
|
|
|
fem_for_lna_set();
|
|
nrf_802154_trx_antenna_update();
|
|
nrf_802154_trx_ppi_for_ramp_up_set(NRF_RADIO_TASK_RXEN, TRX_RAMP_UP_SW_TRIGGER, false);
|
|
|
|
trigger_disable_to_start_rampup();
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
bool nrf_802154_trx_rssi_measure(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
bool result = false;
|
|
|
|
if (m_trx_state == TRX_STATE_RXFRAME)
|
|
{
|
|
// When TRX is in RXFRAME the RADIO may be also ramping down after previous operation or still ramping up
|
|
nrf_radio_state_t radio_state = nrf_radio_state_get(NRF_RADIO);
|
|
|
|
if ((radio_state == RADIO_STATE_STATE_RxIdle) || (radio_state == RADIO_STATE_STATE_Rx))
|
|
{
|
|
if (!m_flags.rssi_settled)
|
|
{
|
|
// This operation is requested first time after nrf_802154_trx_receive_frame has been called
|
|
// Radio is ramped up, but we need to wait RSSISETTLE time.
|
|
// Precisely, we need to wait NRF_RADIO_EVENT_RSSIEND between READY->START short worked
|
|
// and RSSI_START task is triggered. Due to limited resources we assume worst case and
|
|
// wait whole time when rssi_measure is requested first time after nrf_802154_trx_receive_frame.
|
|
nrf_802154_delay_us(RSSI_SETTLE_TIME_US);
|
|
m_flags.rssi_settled = true;
|
|
}
|
|
|
|
#if defined(RADIO_EVENTS_RSSIEND_EVENTS_RSSIEND_Msk)
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_RSSIEND);
|
|
#endif
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_RSSISTART);
|
|
m_flags.rssi_started = true;
|
|
|
|
result = true;
|
|
}
|
|
else
|
|
{
|
|
// The RADIO may be:
|
|
// - still ramping down after transmit
|
|
// - ramping up for receive
|
|
// - ramping down after frame is received (shorts)
|
|
}
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
return result;
|
|
}
|
|
|
|
bool nrf_802154_trx_rssi_measure_is_started(void)
|
|
{
|
|
return m_flags.rssi_started;
|
|
}
|
|
|
|
uint8_t nrf_802154_trx_rssi_last_sample_get(void)
|
|
{
|
|
return nrf_radio_rssi_sample_get(NRF_RADIO);
|
|
}
|
|
|
|
bool nrf_802154_trx_rssi_sample_is_available(void)
|
|
{
|
|
#if defined(RADIO_EVENTS_RSSIEND_EVENTS_RSSIEND_Msk)
|
|
return nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_RSSIEND);
|
|
#else
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
void nrf_802154_trx_transmit_frame(const void * p_transmit_buffer,
|
|
nrf_802154_trx_ramp_up_trigger_mode_t rampup_trigg_mode,
|
|
bool cca,
|
|
const nrf_802154_fal_tx_power_split_t * p_tx_power,
|
|
nrf_802154_trx_transmit_notifications_t notifications_mask)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
uint32_t ints_to_enable = 0U;
|
|
|
|
// Force the TIMER to be stopped and count from 0.
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
|
|
m_trx_state = TRX_STATE_TXFRAME;
|
|
m_transmit_with_cca = cca;
|
|
|
|
m_flags.ccastarted_notif_en = false;
|
|
|
|
txpower_set(p_tx_power->radio_tx_power);
|
|
|
|
nrf_radio_packetptr_set(NRF_RADIO, p_transmit_buffer);
|
|
|
|
// Set shorts
|
|
if (cca)
|
|
{
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_CCA_TX);
|
|
}
|
|
else
|
|
{
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_TX);
|
|
}
|
|
|
|
// Enable IRQs
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_PHYEND);
|
|
ints_to_enable |= NRF_RADIO_INT_PHYEND_MASK;
|
|
|
|
if (rampup_trigg_mode == TRX_RAMP_UP_HW_TRIGGER)
|
|
{
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_READY);
|
|
ints_to_enable |= NRF_RADIO_INT_READY_MASK;
|
|
}
|
|
|
|
if (cca)
|
|
{
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CCABUSY);
|
|
|
|
ints_to_enable |= NRF_RADIO_INT_CCABUSY_MASK;
|
|
|
|
if ((notifications_mask & TRX_TRANSMIT_NOTIFICATION_CCAIDLE) != 0U)
|
|
{
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CCAIDLE);
|
|
ints_to_enable |= NRF_RADIO_INT_CCAIDLE_MASK;
|
|
}
|
|
|
|
if ((notifications_mask & TRX_TRANSMIT_NOTIFICATION_CCASTARTED) != 0U)
|
|
{
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_READY);
|
|
ints_to_enable |= NRF_RADIO_INT_READY_MASK;
|
|
m_flags.ccastarted_notif_en = true;
|
|
}
|
|
}
|
|
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_ADDRESS);
|
|
ints_to_enable |= NRF_RADIO_INT_ADDRESS_MASK;
|
|
m_flags.tx_started = false;
|
|
|
|
nrf_radio_int_enable(NRF_RADIO, ints_to_enable);
|
|
|
|
fem_for_tx_set(cca, &p_tx_power->fem);
|
|
nrf_802154_trx_antenna_update();
|
|
nrf_802154_trx_ppi_for_ramp_up_set(cca ? NRF_RADIO_TASK_RXEN : NRF_RADIO_TASK_TXEN,
|
|
rampup_trigg_mode,
|
|
false);
|
|
|
|
if (rampup_trigg_mode == TRX_RAMP_UP_SW_TRIGGER)
|
|
{
|
|
trigger_disable_to_start_rampup();
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
bool nrf_802154_trx_transmit_ack(const void * p_transmit_buffer, uint32_t delay_us)
|
|
{
|
|
/* Assumptions on peripherals
|
|
* TIMER is running, is counting from value saved in m_timer_value_on_radio_end_event,
|
|
* which trigered on END event, which happened EVENT_LAT us after frame on air receive was finished.
|
|
* RADIO is DISABLED
|
|
* PPIs are DISABLED
|
|
*/
|
|
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
bool result = false;
|
|
|
|
assert(m_trx_state == TRX_STATE_RXFRAME_FINISHED);
|
|
assert(p_transmit_buffer != NULL);
|
|
|
|
m_trx_state = TRX_STATE_TXACK;
|
|
|
|
// Set TIMER's CC to the moment when ramp-up should occur.
|
|
if (delay_us <= TXRU_TIME + EVENT_LAT)
|
|
{
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
return result;
|
|
}
|
|
|
|
uint32_t timer_cc_ramp_up_start = m_timer_value_on_radio_end_event + delay_us - TXRU_TIME -
|
|
EVENT_LAT;
|
|
|
|
nrf_timer_cc_set(NRF_802154_TIMER_INSTANCE,
|
|
NRF_TIMER_CC_CHANNEL1,
|
|
timer_cc_ramp_up_start);
|
|
|
|
nrf_radio_packetptr_set(NRF_RADIO, p_transmit_buffer);
|
|
|
|
// Set shorts
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_TX_ACK);
|
|
|
|
// Clear TXREADY event to detect if PPI worked
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_TXREADY);
|
|
|
|
// Set FEM
|
|
// Note: the TIMER is running, ramp up will start in timer_cc_ramp_up_start tick
|
|
// Assumption here is that FEM activation takes no more than TXRU_TIME.
|
|
m_activate_tx_cc0_timeshifted = m_activate_tx_cc0;
|
|
|
|
// Set the moment for FEM at which real transmission starts.
|
|
m_activate_tx_cc0_timeshifted.event.timer.counter_period.end = timer_cc_ramp_up_start +
|
|
TXRU_TIME;
|
|
|
|
if (mpsl_fem_pa_configuration_set(&m_activate_tx_cc0_timeshifted, NULL) == 0)
|
|
{
|
|
// FEM scheduled its operations on timer, so the timer must be running until last
|
|
// operation scheduled by the FEM (TIMER's CC0), which is later than radio ramp up
|
|
nrf_timer_shorts_enable(NRF_802154_TIMER_INSTANCE, NRF_TIMER_SHORT_COMPARE0_STOP_MASK);
|
|
}
|
|
else
|
|
{
|
|
// FEM didn't schedule anything on timer, so the timer may be stopped when radio ramp-up
|
|
// is triggered
|
|
nrf_timer_shorts_enable(NRF_802154_TIMER_INSTANCE, NRF_TIMER_SHORT_COMPARE1_STOP_MASK);
|
|
}
|
|
|
|
// Select antenna
|
|
nrf_802154_trx_antenna_update();
|
|
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_PHYEND);
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_ADDRESS);
|
|
|
|
// Set PPIs
|
|
nrf_802154_trx_ppi_for_ack_tx_set();
|
|
|
|
// Since this point the transmission is armed on TIMER's CC1
|
|
|
|
// Detect if PPI will work in future or has just worked.
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_CAPTURE3);
|
|
uint32_t timer_cc_now = nrf_timer_cc_get(NRF_802154_TIMER_INSTANCE,
|
|
NRF_TIMER_CC_CHANNEL3);
|
|
uint32_t timer_cc_fem_start = nrf_timer_cc_get(NRF_802154_TIMER_INSTANCE,
|
|
NRF_TIMER_CC_CHANNEL0);
|
|
|
|
// When external PA uses a timer, it should be configured to a time later than ramp up time. In
|
|
// such case, the timer stops with shorts on PA timer. But if external PA does not use a timer,
|
|
// FEM time is set to a value in the past that was used by LNA. After the timer overflows,
|
|
// the timer stops with a short on the past value used by LNA. We have to detect if the current
|
|
// timer value is after the overflow.
|
|
if ((timer_cc_now < timer_cc_ramp_up_start) &&
|
|
((timer_cc_fem_start >= timer_cc_ramp_up_start) || (timer_cc_now > timer_cc_fem_start)))
|
|
{
|
|
result = true;
|
|
}
|
|
else
|
|
{
|
|
nrf_802154_trx_ppi_for_ramp_up_propagation_delay_wait();
|
|
|
|
if (nrf_radio_state_get(NRF_RADIO) == NRF_RADIO_STATE_TXRU)
|
|
{
|
|
result = true;
|
|
}
|
|
else if (nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_TXREADY))
|
|
{
|
|
result = true;
|
|
}
|
|
else
|
|
{
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
if (result)
|
|
{
|
|
uint32_t ints_to_enable = NRF_RADIO_INT_PHYEND_MASK | NRF_RADIO_INT_ADDRESS_MASK;
|
|
|
|
nrf_radio_int_enable(NRF_RADIO, ints_to_enable);
|
|
}
|
|
else
|
|
{
|
|
#if !NRF_802154_TRX_TEST_MODE_ALLOW_LATE_TX_ACK
|
|
/* We were to late with setting up PPI_TIMER_ACK, ack transmission was not triggered and
|
|
* will not be triggered in future.
|
|
*/
|
|
nrf_802154_trx_ppi_for_ack_tx_clear();
|
|
|
|
/* As the timer was running during operation, it is possible we were able to configure
|
|
* FEM thus it may trigger in future or may started PA activation.
|
|
*/
|
|
mpsl_fem_pa_configuration_clear();
|
|
mpsl_fem_deactivate_now(MPSL_FEM_PA);
|
|
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
|
|
/* No callbacks will be called */
|
|
#else // !NRF_802154_TRX_TEST_MODE_ALLOW_LATE_TX_ACK
|
|
uint32_t ints_to_enable = NRF_RADIO_INT_PHYEND_MASK | NRF_RADIO_INT_ADDRESS_MASK;
|
|
|
|
nrf_radio_int_enable(NRF_RADIO, ints_to_enable);
|
|
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_TXEN);
|
|
|
|
result = true;
|
|
#endif // !NRF_802154_TRX_TEST_MODE_ALLOW_LATE_TX_ACK
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
return result;
|
|
}
|
|
|
|
static void rxframe_finish_disable_ppis(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
nrf_802154_trx_ppi_for_ramp_up_clear(NRF_RADIO_TASK_RXEN, true);
|
|
#if defined(RADIO_INTENSET_SYNC_Msk)
|
|
nrf_802154_trx_ppi_for_radio_sync_clear(EGU_SYNC_TASK);
|
|
#endif
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void rxframe_finish_disable_fem_activation(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
// Disable LNA activation
|
|
mpsl_fem_lna_configuration_clear();
|
|
// Disable short used by LNA activation
|
|
nrf_timer_shorts_disable(NRF_802154_TIMER_INSTANCE,
|
|
NRF_TIMER_SHORT_COMPARE0_STOP_MASK);
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void rxframe_finish_disable_ints(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
uint32_t ints_to_disable = NRF_RADIO_INT_READY_MASK |
|
|
NRF_RADIO_INT_ADDRESS_MASK |
|
|
NRF_RADIO_INT_CRCOK_MASK;
|
|
|
|
ints_to_disable |= NRF_RADIO_INT_CRCERROR_MASK;
|
|
ints_to_disable |= NRF_RADIO_INT_BCMATCH_MASK;
|
|
nrf_radio_int_disable(NRF_RADIO, ints_to_disable);
|
|
|
|
#if defined(RADIO_INTENSET_SYNC_Msk)
|
|
nrf_egu_int_disable(NRF_802154_EGU_INSTANCE, EGU_SYNC_INTMASK);
|
|
#endif
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void rxframe_finish_psdu_is_not_being_received(void)
|
|
{
|
|
m_flags.psdu_being_received = false;
|
|
}
|
|
|
|
static void rxframe_finish(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
/* Note that CRCOK/CRCERROR event is generated several cycles before END event.
|
|
*
|
|
* Below shown what is happening in the hardware
|
|
*
|
|
* TIMER is started by path:
|
|
* RADIO.SHORT_END_DISABLE -> RADIO.TASKS_DISABLE -> RADIO.EVENTS_DISABLED ->
|
|
* PPI_DISABLED_EGU -> EGU.TASKS_TRIGGER -> EGU.EVENTS_TRIGGERED -> PPI_EGU_TIMER_START -> TIMER.TASKS_START
|
|
*
|
|
* FEM's LNA mode is disabled by path:
|
|
* RADIO.SHORT_END_DISABLE -> RADIO.TASKS_DISABLE -> RADIO.EVENTS_DISABLED -> (FEM's PPI triggering disable LNA operation,
|
|
* see mpsl_fem_abort_set() )
|
|
*
|
|
* RADIO will not ramp up, as PPI_EGU_RAMP_UP channel is self-disabling, and
|
|
* it was disabled when receive ramp-up was started.
|
|
*/
|
|
wait_until_radio_is_disabled(); // This includes waiting since CRCOK/CRCERROR (several cycles) event until END
|
|
// and then during RXDISABLE state (0.5us)
|
|
|
|
nrf_802154_trx_ppi_for_ramp_up_propagation_delay_wait();
|
|
|
|
/* Now it is guaranteed, that:
|
|
* - FEM operation to disable LNA mode is triggered through FEM's PPIs
|
|
* - TIMER is started again allowing operation of nrf_802154_trx_transmit_ack
|
|
*/
|
|
|
|
rxframe_finish_disable_ppis();
|
|
rxframe_finish_disable_fem_activation();
|
|
rxframe_finish_psdu_is_not_being_received();
|
|
rxframe_finish_disable_ints();
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_IDLE);
|
|
m_flags.missing_receive_buffer = false;
|
|
|
|
/* Current state of peripherals:
|
|
* RADIO is DISABLED
|
|
* FEM is powered but LNA mode has just been turned off
|
|
* TIMER is running, counting from the value stored in m_timer_value_on_radio_end_event
|
|
* All PPIs used by receive operation are disabled, forks are cleared, PPI groups that were used are cleared
|
|
* RADIO.SHORTS are cleared
|
|
*/
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
void nrf_802154_trx_abort(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
switch (m_trx_state)
|
|
{
|
|
case TRX_STATE_DISABLED:
|
|
case TRX_STATE_IDLE:
|
|
case TRX_STATE_FINISHED:
|
|
/* Nothing to do, intentionally empty */
|
|
break;
|
|
|
|
case TRX_STATE_GOING_IDLE:
|
|
go_idle_abort();
|
|
break;
|
|
|
|
case TRX_STATE_RXFRAME:
|
|
receive_frame_abort();
|
|
break;
|
|
|
|
case TRX_STATE_RXFRAME_FINISHED:
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
break;
|
|
|
|
case TRX_STATE_RXACK:
|
|
receive_ack_abort();
|
|
break;
|
|
|
|
case TRX_STATE_TXFRAME:
|
|
transmit_frame_abort();
|
|
break;
|
|
|
|
case TRX_STATE_TXACK:
|
|
transmit_ack_abort();
|
|
break;
|
|
|
|
case TRX_STATE_STANDALONE_CCA:
|
|
standalone_cca_abort();
|
|
break;
|
|
|
|
#if NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
case TRX_STATE_CONTINUOUS_CARRIER:
|
|
continuous_carrier_abort();
|
|
break;
|
|
|
|
case TRX_STATE_MODULATED_CARRIER:
|
|
modulated_carrier_abort();
|
|
break;
|
|
#endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
|
|
case TRX_STATE_ENERGY_DETECTION:
|
|
energy_detection_abort();
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
trx_state_t nrf_802154_trx_state_get(void)
|
|
{
|
|
return m_trx_state;
|
|
}
|
|
|
|
uint32_t nrf_802154_trx_ramp_up_ppi_channel_get(void)
|
|
{
|
|
return nrf_802154_trx_ppi_for_ramp_up_channel_id_get();
|
|
}
|
|
|
|
static void go_idle_from_state_finished(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
m_trx_state = TRX_STATE_GOING_IDLE;
|
|
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_DISABLED);
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
|
|
|
|
nrf_radio_int_enable(NRF_RADIO, NRF_RADIO_INT_DISABLED_MASK);
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
bool nrf_802154_trx_go_idle(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
bool result = false;
|
|
|
|
switch (m_trx_state)
|
|
{
|
|
case TRX_STATE_DISABLED:
|
|
assert(false);
|
|
break;
|
|
|
|
case TRX_STATE_IDLE:
|
|
/* There will be no callout */
|
|
break;
|
|
|
|
case TRX_STATE_GOING_IDLE:
|
|
/* There will be callout */
|
|
result = true;
|
|
break;
|
|
|
|
case TRX_STATE_RXFRAME_FINISHED:
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
/* Fallthrough */
|
|
|
|
case TRX_STATE_FINISHED:
|
|
go_idle_from_state_finished();
|
|
result = true;
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
return result;
|
|
}
|
|
|
|
static void go_idle_abort(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_INT_DISABLED_MASK);
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void receive_frame_abort(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
rxframe_finish_disable_ppis();
|
|
rxframe_finish_disable_fem_activation();
|
|
rxframe_finish_psdu_is_not_being_received();
|
|
rxframe_finish_disable_ints();
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_IDLE);
|
|
|
|
m_flags.missing_receive_buffer = false;
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
|
|
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void rxack_finish_disable_ppis(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
nrf_802154_trx_ppi_for_ramp_up_clear(NRF_RADIO_TASK_RXEN, false);
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void rxack_finish_disable_ints(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
nrf_radio_int_disable(NRF_RADIO,
|
|
NRF_RADIO_INT_ADDRESS_MASK | NRF_RADIO_INT_CRCERROR_MASK |
|
|
NRF_RADIO_INT_CRCOK_MASK);
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void rxack_finish_disable_fem_activation(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
// Disable LNA activation
|
|
mpsl_fem_lna_configuration_clear();
|
|
|
|
// Clear LNA PPIs
|
|
nrf_802154_trx_ppi_for_fem_clear();
|
|
|
|
// Disable short used by LNA activation
|
|
nrf_timer_shorts_disable(NRF_802154_TIMER_INSTANCE,
|
|
NRF_TIMER_SHORT_COMPARE0_STOP_MASK);
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void rxack_finish(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
rxack_finish_disable_ppis();
|
|
rxack_finish_disable_ints();
|
|
rxack_finish_disable_fem_activation();
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_IDLE);
|
|
m_flags.missing_receive_buffer = false;
|
|
|
|
/* Current state of peripherals
|
|
* RADIO is DISABLED
|
|
* FEM is powered but LNA mode has just been turned off
|
|
* TIMER is shutdown
|
|
* PPIs used by receive operation are disabled, forks are cleared, PPI groups used are cleared
|
|
* RADIO.SHORTS are cleared
|
|
*/
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void receive_ack_abort(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
rxack_finish_disable_ppis();
|
|
rxack_finish_disable_ints();
|
|
rxack_finish_disable_fem_activation();
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_IDLE);
|
|
m_flags.missing_receive_buffer = false;
|
|
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
|
|
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
void nrf_802154_trx_standalone_cca(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
assert((m_trx_state == TRX_STATE_IDLE) || (m_trx_state == TRX_STATE_FINISHED));
|
|
|
|
m_trx_state = TRX_STATE_STANDALONE_CCA;
|
|
|
|
// Set shorts
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_CCA);
|
|
|
|
// Enable IRQs
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CCABUSY);
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CCAIDLE);
|
|
nrf_radio_int_enable(NRF_RADIO, NRF_RADIO_INT_CCABUSY_MASK | NRF_RADIO_INT_CCAIDLE_MASK);
|
|
|
|
// Set FEM
|
|
fem_for_lna_set();
|
|
|
|
// Select antenna
|
|
nrf_802154_trx_antenna_update();
|
|
|
|
// Set PPIs
|
|
nrf_802154_trx_ppi_for_ramp_up_set(NRF_RADIO_TASK_RXEN, TRX_RAMP_UP_SW_TRIGGER, false);
|
|
|
|
trigger_disable_to_start_rampup();
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
static void standalone_cca_finish(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
nrf_802154_trx_ppi_for_ramp_up_clear(NRF_RADIO_TASK_RXEN, false);
|
|
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_IDLE);
|
|
|
|
fem_for_lna_reset();
|
|
|
|
nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_INT_CCABUSY_MASK | NRF_RADIO_INT_CCAIDLE_MASK);
|
|
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_CCASTOP);
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void standalone_cca_abort(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
standalone_cca_finish();
|
|
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
#if NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
|
|
void nrf_802154_trx_continuous_carrier(const nrf_802154_fal_tx_power_split_t * p_tx_power)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
assert((m_trx_state == TRX_STATE_IDLE) || (m_trx_state == TRX_STATE_FINISHED));
|
|
|
|
m_trx_state = TRX_STATE_CONTINUOUS_CARRIER;
|
|
|
|
// Set Tx Power
|
|
txpower_set(p_tx_power->radio_tx_power);
|
|
|
|
// Set FEM
|
|
fem_for_pa_set(&p_tx_power->fem);
|
|
|
|
// Select antenna
|
|
nrf_802154_trx_antenna_update();
|
|
|
|
// Set PPIs
|
|
nrf_802154_trx_ppi_for_ramp_up_set(NRF_RADIO_TASK_TXEN, TRX_RAMP_UP_SW_TRIGGER, false);
|
|
|
|
trigger_disable_to_start_rampup();
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
void nrf_802154_trx_continuous_carrier_restart(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
assert(m_trx_state == TRX_STATE_CONTINUOUS_CARRIER);
|
|
|
|
// Continuous carrier PPIs are configured without self-disabling
|
|
// Triggering RADIO.TASK_DISABLE causes ramp-down -> RADIO.EVENTS_DISABLED -> EGU.TASK -> EGU.EVENT ->
|
|
// RADIO.TASK_TXEN -> ramp_up -> new continous carrier
|
|
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
static void continuous_carrier_abort(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
nrf_802154_trx_ppi_for_ramp_up_clear(NRF_RADIO_TASK_TXEN, false);
|
|
|
|
fem_for_pa_reset();
|
|
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
|
|
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
void nrf_802154_trx_modulated_carrier(const void * p_transmit_buffer,
|
|
const nrf_802154_fal_tx_power_split_t * p_tx_power)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
assert((m_trx_state == TRX_STATE_IDLE) || (m_trx_state == TRX_STATE_FINISHED));
|
|
assert(p_transmit_buffer != NULL);
|
|
|
|
m_trx_state = TRX_STATE_MODULATED_CARRIER;
|
|
|
|
// Set Tx Power
|
|
txpower_set(p_tx_power->radio_tx_power);
|
|
|
|
// Set Tx buffer
|
|
nrf_radio_packetptr_set(NRF_RADIO, p_transmit_buffer);
|
|
|
|
// Set shorts
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_MOD_CARRIER);
|
|
|
|
// Set FEM
|
|
fem_for_pa_set(&p_tx_power->fem);
|
|
|
|
// Select antenna
|
|
nrf_802154_trx_antenna_update();
|
|
|
|
// Set PPIs
|
|
nrf_802154_trx_ppi_for_ramp_up_set(NRF_RADIO_TASK_TXEN, TRX_RAMP_UP_SW_TRIGGER, false);
|
|
|
|
trigger_disable_to_start_rampup();
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
void nrf_802154_trx_modulated_carrier_restart(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
assert(m_trx_state == TRX_STATE_MODULATED_CARRIER);
|
|
|
|
// Modulated carrier PPIs are configured without self-disabling
|
|
// Triggering RADIO.TASK_DISABLE causes ramp-down -> RADIO.EVENTS_DISABLED -> EGU.TASK -> EGU.EVENT ->
|
|
// RADIO.TASK_TXEN -> ramp_up -> new modulated carrier
|
|
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
static void modulated_carrier_abort()
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
nrf_802154_trx_ppi_for_ramp_up_clear(NRF_RADIO_TASK_TXEN, false);
|
|
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_IDLE);
|
|
|
|
fem_for_pa_reset();
|
|
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
|
|
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
#endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
|
|
void nrf_802154_trx_energy_detection(uint32_t ed_count)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
assert((m_trx_state == TRX_STATE_FINISHED) || (m_trx_state == TRX_STATE_IDLE));
|
|
|
|
m_trx_state = TRX_STATE_ENERGY_DETECTION;
|
|
|
|
ed_count--;
|
|
/* Check that vd_count will fit into defined bits of register */
|
|
#if defined(RADIO_EDCNT_EDCNT_Msk)
|
|
assert( (ed_count & (~RADIO_EDCNT_EDCNT_Msk)) == 0U);
|
|
#endif
|
|
|
|
nrf_radio_ed_loop_count_set(NRF_RADIO, ed_count);
|
|
|
|
// Set shorts
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_ED);
|
|
|
|
// Enable IRQs
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_EDEND);
|
|
nrf_radio_int_enable(NRF_RADIO, NRF_RADIO_INT_EDEND_MASK);
|
|
|
|
// Set FEM
|
|
fem_for_lna_set();
|
|
|
|
// Select antenna
|
|
nrf_802154_trx_antenna_update();
|
|
|
|
// Set PPIs
|
|
nrf_802154_trx_ppi_for_ramp_up_set(NRF_RADIO_TASK_RXEN, TRX_RAMP_UP_SW_TRIGGER, false);
|
|
|
|
trigger_disable_to_start_rampup();
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
static void energy_detection_finish(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
nrf_802154_trx_ppi_for_ramp_up_clear(NRF_RADIO_TASK_RXEN, false);
|
|
fem_for_lna_reset();
|
|
|
|
nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_INT_EDEND_MASK);
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_IDLE);
|
|
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_EDSTOP);
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void energy_detection_abort(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
energy_detection_finish();
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void irq_handler_ready(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_INT_READY_MASK);
|
|
|
|
nrf_802154_trx_ppi_for_ramp_up_reconfigure();
|
|
|
|
switch (m_trx_state)
|
|
{
|
|
case TRX_STATE_TXFRAME:
|
|
if (m_flags.ccastarted_notif_en)
|
|
{
|
|
nrf_802154_trx_transmit_frame_ccastarted();
|
|
}
|
|
break;
|
|
|
|
case TRX_STATE_RXFRAME:
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
static void irq_handler_address(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
// NRF_RADIO_TASK_DISABLE may have been triggered by (D)PPI, therefore event reg
|
|
// cleanup is required. It's done here
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_DISABLED);
|
|
|
|
switch (m_trx_state)
|
|
{
|
|
case TRX_STATE_RXFRAME:
|
|
if (m_flags.rxstarted_notif_en)
|
|
{
|
|
nrf_802154_trx_receive_frame_started();
|
|
}
|
|
break;
|
|
|
|
case TRX_STATE_RXACK:
|
|
m_flags.rssi_started = true;
|
|
nrf_802154_trx_receive_ack_started();
|
|
break;
|
|
|
|
case TRX_STATE_TXFRAME:
|
|
nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_INT_ADDRESS_MASK);
|
|
m_flags.tx_started = true;
|
|
nrf_802154_trx_transmit_frame_started();
|
|
break;
|
|
|
|
case TRX_STATE_TXACK:
|
|
nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_INT_ADDRESS_MASK);
|
|
nrf_802154_trx_transmit_ack_started();
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
static void irq_handler_bcmatch(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
uint8_t current_bcc;
|
|
uint8_t next_bcc;
|
|
|
|
assert(m_trx_state == TRX_STATE_RXFRAME);
|
|
|
|
m_flags.psdu_being_received = true;
|
|
|
|
// If CRCERROR event is set, it means that events are handled out of order due to software
|
|
// latency. Just skip this handler in this case - frame will be dropped.
|
|
if (nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_CRCERROR))
|
|
{
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
return;
|
|
}
|
|
|
|
current_bcc = nrf_radio_bcc_get(NRF_RADIO) / 8U;
|
|
|
|
next_bcc = nrf_802154_trx_receive_frame_bcmatched(current_bcc);
|
|
|
|
if (next_bcc > current_bcc)
|
|
{
|
|
/* Note: If we don't make it before given octet is received by RADIO bcmatch will not be triggered.
|
|
* The fact that filtering may be not completed at the call to nrf_802154_trx_receive_received handler
|
|
* should be handled by the handler.
|
|
*/
|
|
nrf_radio_bcc_set(NRF_RADIO, next_bcc * 8);
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
static void irq_handler_crcerror(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
switch (m_trx_state)
|
|
{
|
|
case TRX_STATE_RXFRAME:
|
|
rxframe_finish();
|
|
/* On crc error TIMER is not needed, no ACK may be sent */
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
nrf_802154_trx_receive_frame_crcerror();
|
|
break;
|
|
|
|
case TRX_STATE_RXACK:
|
|
rxack_finish();
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
nrf_802154_trx_receive_ack_crcerror();
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
static void irq_handler_crcok(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
switch (m_trx_state)
|
|
{
|
|
case TRX_STATE_RXFRAME:
|
|
m_flags.rssi_started = true;
|
|
rxframe_finish();
|
|
m_trx_state = TRX_STATE_RXFRAME_FINISHED;
|
|
nrf_802154_trx_receive_frame_received();
|
|
break;
|
|
|
|
case TRX_STATE_RXACK:
|
|
rxack_finish();
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
nrf_802154_trx_receive_ack_received();
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
static void txframe_finish_disable_ppis(bool cca)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
nrf_802154_trx_ppi_for_ramp_up_clear(cca ? NRF_RADIO_TASK_RXEN : NRF_RADIO_TASK_TXEN, false);
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void txframe_finish_disable_ints(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
nrf_radio_int_disable(NRF_RADIO,
|
|
NRF_RADIO_INT_PHYEND_MASK |
|
|
NRF_RADIO_INT_CCAIDLE_MASK |
|
|
NRF_RADIO_INT_CCABUSY_MASK |
|
|
NRF_RADIO_INT_ADDRESS_MASK |
|
|
NRF_RADIO_INT_READY_MASK);
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void txframe_finish(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
/* Below shown what is happening in the hardware
|
|
*
|
|
* Due to short RADIO.SHORT_PHYEND_DISABLE the RADIO is in TXDISABLE (currently ramping down for 21us) state or
|
|
* has already reached DISABLED state (if we entered into ISR with greater latency)
|
|
*
|
|
* Even if RADIO reaches state DISABLED (event DISABLED was triggered by short), no transmission will be triggered
|
|
* as PPI_EGU_RAMP_UP is self-disabling PPI channel.
|
|
*
|
|
* If FEM is in use the PPI_EGU_TIMER_START might be triggered if radio reached DISABLED state,
|
|
* so the TIMER may start counting from the value on which FEM activation finished. The TIMER's CC registers
|
|
* are set in the past so even if TIMER started no spurious FEM PA activation will occur.
|
|
* We need to disable PPI_EGU_TIMER_START and then shutdown TIMER as it is not used.
|
|
*/
|
|
txframe_finish_disable_ppis(m_transmit_with_cca);
|
|
|
|
fem_for_tx_reset(m_transmit_with_cca);
|
|
|
|
txframe_finish_disable_ints();
|
|
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_IDLE);
|
|
|
|
m_flags.tx_started = false;
|
|
m_flags.missing_receive_buffer = false;
|
|
|
|
/* Current state of peripherals
|
|
* RADIO is either in TXDISABLE or DISABLED
|
|
* FEM is powered but PA mode will be turned off on entry into DISABLED state or is already turned off
|
|
* TIMER is shutdown
|
|
* All PPIs that were used are disabled (forks are cleared if used)
|
|
* RADIO.SHORTS are cleared
|
|
*/
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void transmit_frame_abort(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
txframe_finish_disable_ppis(m_transmit_with_cca);
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_IDLE);
|
|
|
|
fem_for_tx_reset(m_transmit_with_cca);
|
|
|
|
txframe_finish_disable_ints();
|
|
|
|
m_flags.tx_started = false;
|
|
m_flags.missing_receive_buffer = false;
|
|
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_CCASTOP);
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
|
|
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void txack_finish(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
/* Below shown what is happening in the hardware
|
|
*
|
|
* Due to short RADIO.SHORT_PHYEND_DISABLE the RADIO is in TXDISABLE (currently ramping down for 21us) state or
|
|
* has already reached DISABLED state (if we entered into ISR with greater latency)
|
|
*
|
|
* Even if RADIO reaches state DISABLED (event DISABLED was triggered by short), no transmission will be triggered
|
|
* as only PPI_TIMER_TX_ACK was enabled.
|
|
*
|
|
* FEM will disable PA mode on RADIO.DISABLED event
|
|
*
|
|
* The TIMER was counting to trigger RADIO ramp up and FEM (if required). The TIMER is configured
|
|
* to trigger STOP task on one of these events (whichever is later). As we finished the TIMER is
|
|
* stopped now, and there is no PPIs starting it automatically by the hardware.
|
|
*/
|
|
nrf_802154_trx_ppi_for_ack_tx_clear();
|
|
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_IDLE);
|
|
|
|
mpsl_fem_pa_configuration_clear();
|
|
|
|
nrf_timer_shorts_disable(NRF_802154_TIMER_INSTANCE,
|
|
NRF_TIMER_SHORT_COMPARE0_STOP_MASK |
|
|
NRF_TIMER_SHORT_COMPARE1_STOP_MASK);
|
|
|
|
// Anomaly 78: use SHUTDOWN instead of STOP and CLEAR.
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
|
|
nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_INT_PHYEND_MASK | NRF_RADIO_INT_ADDRESS_MASK);
|
|
|
|
/* Current state of peripherals
|
|
* RADIO is either in TXDISABLE or DISABLED
|
|
* FEM is powered but PA mode will be turned off on entry into DISABLED state or is already turned off
|
|
* TIMER is shutdown
|
|
* All PPIs that were used are disabled (forks are cleared if used)
|
|
* RADIO.SHORTS are cleared
|
|
*/
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void transmit_ack_abort(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
nrf_802154_trx_ppi_for_ack_tx_clear();
|
|
|
|
nrf_radio_shorts_set(NRF_RADIO, SHORTS_IDLE);
|
|
|
|
mpsl_fem_pa_configuration_clear();
|
|
|
|
nrf_timer_shorts_disable(NRF_802154_TIMER_INSTANCE,
|
|
NRF_TIMER_SHORT_COMPARE0_STOP_MASK |
|
|
NRF_TIMER_SHORT_COMPARE1_STOP_MASK);
|
|
|
|
// Anomaly 78: use SHUTDOWN instead of STOP and CLEAR.
|
|
nrf_timer_task_trigger(NRF_802154_TIMER_INSTANCE, NRF_TIMER_TASK_SHUTDOWN);
|
|
|
|
nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_INT_PHYEND_MASK | NRF_RADIO_INT_ADDRESS_MASK);
|
|
|
|
nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
|
|
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void irq_handler_phyend(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
switch (m_trx_state)
|
|
{
|
|
case TRX_STATE_TXFRAME:
|
|
txframe_finish();
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
nrf_802154_trx_transmit_frame_transmitted();
|
|
break;
|
|
|
|
case TRX_STATE_TXACK:
|
|
txack_finish();
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
nrf_802154_trx_transmit_ack_transmitted();
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
static void go_idle_finish(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
|
|
nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_INT_DISABLED_MASK);
|
|
|
|
fem_power_down_now();
|
|
|
|
m_trx_state = TRX_STATE_IDLE;
|
|
|
|
nrf_802154_trx_go_idle_finished();
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_HIGH);
|
|
}
|
|
|
|
static void irq_handler_disabled(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
switch (m_trx_state)
|
|
{
|
|
case TRX_STATE_GOING_IDLE:
|
|
go_idle_finish();
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
static void irq_handler_ccaidle(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
switch (m_trx_state)
|
|
{
|
|
case TRX_STATE_STANDALONE_CCA:
|
|
standalone_cca_finish();
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
nrf_802154_trx_standalone_cca_finished(true);
|
|
break;
|
|
|
|
case TRX_STATE_TXFRAME:
|
|
nrf_802154_trx_transmit_frame_ccaidle();
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
static void irq_handler_ccabusy(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
switch (m_trx_state)
|
|
{
|
|
case TRX_STATE_TXFRAME:
|
|
assert(m_transmit_with_cca);
|
|
txframe_finish();
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
nrf_802154_trx_transmit_frame_ccabusy();
|
|
break;
|
|
|
|
case TRX_STATE_STANDALONE_CCA:
|
|
standalone_cca_finish();
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
nrf_802154_trx_standalone_cca_finished(false);
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
}
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
static void irq_handler_edend(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
assert(m_trx_state == TRX_STATE_ENERGY_DETECTION);
|
|
|
|
uint8_t ed_sample = nrf_radio_ed_sample_get(NRF_RADIO);
|
|
|
|
energy_detection_finish();
|
|
m_trx_state = TRX_STATE_FINISHED;
|
|
|
|
nrf_802154_trx_energy_detection_finished(ed_sample);
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
#if defined(RADIO_INTENSET_SYNC_Msk)
|
|
static void irq_handler_sync(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
assert(m_trx_state == TRX_STATE_RXFRAME);
|
|
|
|
nrf_802154_trx_receive_frame_prestarted();
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
#endif
|
|
|
|
void nrf_802154_radio_irq_handler(void)
|
|
{
|
|
nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
|
|
|
|
// Prevent interrupting of this handler by requests from higher priority code.
|
|
nrf_802154_critical_section_forcefully_enter();
|
|
|
|
#if defined(RADIO_INTENSET_SYNC_Msk)
|
|
// Note: For NRF_RADIO_EVENT_SYNC we enable interrupt through EGU.
|
|
// That's why we check here EGU's EGU_SYNC_INTMASK.
|
|
// The RADIO does not have interrupt from SYNC event.
|
|
if (nrf_egu_int_enable_check(NRF_802154_EGU_INSTANCE, EGU_SYNC_INTMASK) &&
|
|
nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_SYNC))
|
|
{
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_SYNC);
|
|
nrf_egu_event_clear(NRF_802154_EGU_INSTANCE, EGU_SYNC_EVENT);
|
|
|
|
irq_handler_sync();
|
|
}
|
|
#endif
|
|
|
|
if (nrf_radio_int_enable_check(NRF_RADIO, NRF_RADIO_INT_READY_MASK) &&
|
|
nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_READY))
|
|
{
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_READY);
|
|
|
|
irq_handler_ready();
|
|
}
|
|
|
|
if (nrf_radio_int_enable_check(NRF_RADIO, NRF_RADIO_INT_ADDRESS_MASK) &&
|
|
nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_ADDRESS))
|
|
{
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_ADDRESS);
|
|
|
|
irq_handler_address();
|
|
}
|
|
|
|
// Check MAC frame header.
|
|
if (nrf_radio_int_enable_check(NRF_RADIO, NRF_RADIO_INT_BCMATCH_MASK) &&
|
|
nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_BCMATCH))
|
|
{
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_BCMATCH);
|
|
|
|
irq_handler_bcmatch();
|
|
}
|
|
|
|
if (nrf_radio_int_enable_check(NRF_RADIO, NRF_RADIO_INT_CRCERROR_MASK) &&
|
|
nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_CRCERROR))
|
|
{
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CRCERROR);
|
|
|
|
irq_handler_crcerror();
|
|
}
|
|
|
|
if (nrf_radio_int_enable_check(NRF_RADIO, NRF_RADIO_INT_CRCOK_MASK) &&
|
|
nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_CRCOK))
|
|
{
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CRCOK);
|
|
|
|
irq_handler_crcok();
|
|
}
|
|
|
|
if (nrf_radio_int_enable_check(NRF_RADIO, NRF_RADIO_INT_PHYEND_MASK) &&
|
|
nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_PHYEND))
|
|
{
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_PHYEND);
|
|
|
|
irq_handler_phyend();
|
|
}
|
|
|
|
if (nrf_radio_int_enable_check(NRF_RADIO, NRF_RADIO_INT_DISABLED_MASK) &&
|
|
nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_DISABLED))
|
|
{
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_DISABLED);
|
|
|
|
irq_handler_disabled();
|
|
}
|
|
|
|
if (nrf_radio_int_enable_check(NRF_RADIO, NRF_RADIO_INT_CCAIDLE_MASK) &&
|
|
nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_CCAIDLE))
|
|
{
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CCAIDLE);
|
|
|
|
irq_handler_ccaidle();
|
|
}
|
|
|
|
if (nrf_radio_int_enable_check(NRF_RADIO, NRF_RADIO_INT_CCABUSY_MASK) &&
|
|
nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_CCABUSY))
|
|
{
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_CCABUSY);
|
|
|
|
irq_handler_ccabusy();
|
|
}
|
|
|
|
if (nrf_radio_int_enable_check(NRF_RADIO, NRF_RADIO_INT_EDEND_MASK) &&
|
|
nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_EDEND))
|
|
{
|
|
nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_EDEND);
|
|
|
|
irq_handler_edend();
|
|
}
|
|
|
|
nrf_802154_critical_section_exit();
|
|
|
|
nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
|
|
}
|
|
|
|
#if NRF_802154_INTERNAL_RADIO_IRQ_HANDLING
|
|
void RADIO_IRQHandler(void)
|
|
{
|
|
nrf_802154_radio_irq_handler();
|
|
}
|
|
|
|
#endif // NRF_802154_INTERNAL_RADIO_IRQ_HANDLING
|
|
|
|
#if defined(RADIO_INTENSET_SYNC_Msk)
|
|
void nrf_802154_trx_swi_irq_handler(void)
|
|
{
|
|
// If this handler is preempted by MARGIN, RADIO IRQ might be set to pending
|
|
// and executed after MARGIN processing is finished, i.e. after the end of a timeslot.
|
|
// To prevent that from happening, the handler is executed with disabled interrupts.
|
|
nrf_802154_mcu_critical_state_t mcu_crit_state;
|
|
|
|
nrf_802154_mcu_critical_enter(mcu_crit_state);
|
|
|
|
if (nrf_egu_int_enable_check(NRF_802154_EGU_INSTANCE, EGU_SYNC_INTMASK) &&
|
|
nrf_egu_event_check(NRF_802154_EGU_INSTANCE, EGU_SYNC_EVENT))
|
|
{
|
|
nrf_egu_event_clear(NRF_802154_EGU_INSTANCE, EGU_SYNC_EVENT);
|
|
|
|
// We are in SWI_IRQHandler, which priority is usually lower than RADIO_IRQHandler.
|
|
// To avoid problems with critical sections, trigger RADIO_IRQ manually.
|
|
// - If we are not in critical section, RADIO_IRQ will start shortly (calling
|
|
// nrf_802154_radio_irq_handler) preempting current SWI_IRQHandler. From
|
|
// nrf_802154_radio_irq_handler we acquire critical section and
|
|
// process sync event.
|
|
// If we are in critical section, the RADIO_IRQ is disabled on NVIC.
|
|
// Following will make it pending, and processing of RADIO_IRQ will start
|
|
// when critical section is left.
|
|
|
|
nrf_802154_irq_set_pending(nrfx_get_irq_number(NRF_RADIO));
|
|
}
|
|
|
|
nrf_802154_mcu_critical_exit(mcu_crit_state);
|
|
}
|
|
|
|
#endif
|
|
|
|
const nrf_802154_sl_event_handle_t * nrf_802154_trx_radio_end_event_handle_get(void)
|
|
{
|
|
static const nrf_802154_sl_event_handle_t r = {
|
|
#if defined(DPPI_PRESENT)
|
|
.event_addr = NRF_802154_DPPI_RADIO_END,
|
|
.shared = true
|
|
#else
|
|
.event_addr = (uint32_t)&NRF_RADIO->EVENTS_END
|
|
#endif
|
|
};
|
|
|
|
return &r;
|
|
}
|
|
|
|
const nrf_802154_sl_event_handle_t * nrf_802154_trx_radio_ready_event_handle_get(void)
|
|
{
|
|
static const nrf_802154_sl_event_handle_t r = {
|
|
#if defined(DPPI_PRESENT)
|
|
.event_addr = NRF_802154_DPPI_RADIO_READY,
|
|
.shared = true
|
|
#else
|
|
.event_addr = (uint32_t)&NRF_RADIO->EVENTS_READY
|
|
#endif
|
|
};
|
|
|
|
return &r;
|
|
}
|
|
|
|
const nrf_802154_sl_event_handle_t * nrf_802154_trx_radio_crcok_event_handle_get(void)
|
|
{
|
|
static const nrf_802154_sl_event_handle_t r = {
|
|
.event_addr = (uint32_t)&NRF_RADIO->EVENTS_CRCOK,
|
|
#if defined(DPPI_PRESENT)
|
|
.shared = false
|
|
#endif
|
|
};
|
|
|
|
return &r;
|
|
}
|
|
|
|
const nrf_802154_sl_event_handle_t * nrf_802154_trx_radio_phyend_event_handle_get(void)
|
|
{
|
|
static const nrf_802154_sl_event_handle_t r = {
|
|
#if defined(DPPI_PRESENT)
|
|
.event_addr = NRF_802154_DPPI_RADIO_PHYEND,
|
|
.shared = true
|
|
#else
|
|
.event_addr = (uint32_t)&NRF_RADIO->EVENTS_PHYEND
|
|
#endif
|
|
};
|
|
|
|
return &r;
|
|
}
|