You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
518 lines
21 KiB
C
518 lines
21 KiB
C
/***************************************************************************//**
|
|
* @file
|
|
* @brief Radio coexistence directional priority priority(DP)
|
|
* @details Use the coexistence priority GPIO to communicate to the coexistence
|
|
* master device whether the request is for an RX or TX. In the case of an
|
|
* RX, the priority GPIO will be pulsed for a configurable period of time.
|
|
* In the case of a TX, the priority GPIO will be held through out the
|
|
* duration of the request.
|
|
*******************************************************************************
|
|
* # License
|
|
* <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
|
|
*******************************************************************************
|
|
*
|
|
* The licensor of this software is Silicon Laboratories Inc. Your use of this
|
|
* software is governed by the terms of Silicon Labs Master Software License
|
|
* Agreement (MSLA) available at
|
|
* www.silabs.com/about-us/legal/master-software-license-agreement. This
|
|
* software is distributed to you in Source Code format and is governed by the
|
|
* sections of the MSLA applicable to Source Code.
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include "em_cmu.h"
|
|
#include "em_timer.h"
|
|
#include "em_prs.h"
|
|
#include "coexistence-hal.h"
|
|
|
|
#if SL_RAIL_UTIL_COEX_DP_ENABLED
|
|
#ifndef STATIC_ASSERT
|
|
#ifdef __ICCARM__
|
|
#define STATIC_ASSERT(__condition, __errorstr) \
|
|
static_assert(__condition, __errorstr)
|
|
#elif defined(__GNUC__)
|
|
#define STATIC_ASSERT(__condition, __errorstr) \
|
|
_Static_assert(__condition, __errorstr)
|
|
#else
|
|
#define STATIC_ASSERT(__condition, __errorstr)
|
|
#endif
|
|
#endif //!defined(STATIC_ASSERT)
|
|
#ifdef PLATFORM_HEADER
|
|
#include PLATFORM_HEADER
|
|
#endif //PLATFORM_HEADER
|
|
#ifdef SL_RAIL_UTIL_COEX_PWM_REQ_PORT
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER_CC0_INTNO SL_RAIL_UTIL_COEX_PWM_REQ_INTNO
|
|
#ifdef _SILICON_LABS_32B_SERIES_1
|
|
STATIC_ASSERT(SL_RAIL_UTIL_COEX_DP_TIMER_CC0_PORT == SL_RAIL_UTIL_COEX_PWM_REQ_PORT, "SL_RAIL_UTIL_COEX_DP_TIMER_CC0_PORT must match SL_RAIL_UTIL_COEX_PWM_REQ_PORT");
|
|
STATIC_ASSERT(SL_RAIL_UTIL_COEX_DP_TIMER_CC0_PIN == SL_RAIL_UTIL_COEX_PWM_REQ_PIN, "SL_RAIL_UTIL_COEX_DP_TIMER_CC0_PIN must match SL_RAIL_UTIL_COEX_PWM_REQ_PIN");
|
|
#else //!_SILICON_LABS_32B_SERIES_1
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER_CC0_PORT (SL_RAIL_UTIL_COEX_PWM_REQ_PORT)
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER_CC0_PIN (SL_RAIL_UTIL_COEX_PWM_REQ_PIN)
|
|
#endif //_SILICON_LABS_32B_SERIES_1
|
|
#else //!SL_RAIL_UTIL_COEX_PWM_REQ_PORT
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER_CC0_INTNO SL_RAIL_UTIL_COEX_REQ_INTNO
|
|
#ifdef _SILICON_LABS_32B_SERIES_1
|
|
STATIC_ASSERT(SL_RAIL_UTIL_COEX_DP_TIMER_CC0_PORT == SL_RAIL_UTIL_COEX_REQ_PORT, "SL_RAIL_UTIL_COEX_DP_TIMER_CC0_PORT must match SL_RAIL_UTIL_COEX_REQ_PORT");
|
|
STATIC_ASSERT(SL_RAIL_UTIL_COEX_DP_TIMER_CC0_PIN == SL_RAIL_UTIL_COEX_REQ_PIN, "SL_RAIL_UTIL_COEX_DP_TIMER_CC0_PIN must match SL_RAIL_UTIL_COEX_REQ_PIN");
|
|
#else //!_SILICON_LABS_32B_SERIES_1
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER_CC0_PORT (SL_RAIL_UTIL_COEX_REQ_PORT)
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER_CC0_PIN (SL_RAIL_UTIL_COEX_REQ_PIN)
|
|
#endif //_SILICON_LABS_32B_SERIES_1
|
|
#endif //SL_RAIL_UTIL_COEX_PWM_REQ_PORT
|
|
#if SL_RAIL_UTIL_COEX_PRI_ASSERT_LEVEL == 0
|
|
#error "Directional priority does not support active low priority(SL_RAIL_UTIL_COEX_PRI_ASSERT_LEVEL == 0)"
|
|
#endif //SL_RAIL_UTIL_COEX_PRI_ASSERT_LEVEL == 0
|
|
#if SL_RAIL_UTIL_COEX_REQ_ASSERT_LEVEL == 0
|
|
#error "Directional priority does not support active low request(SL_RAIL_UTIL_COEX_REQ_ASSERT_LEVEL == 0)"
|
|
#endif //SL_RAIL_UTIL_COEX_REQ_ASSERT_LEVEL == 0
|
|
|
|
#define cmuClock_TIMER_DP GET_TIMER_REG(cmuClock, _SL_RAIL_UTIL_COEX_DP_TIMER)
|
|
#ifdef _SILICON_LABS_32B_SERIES_1
|
|
#define TIMER_DIVISOR 16
|
|
#define TIMER_PRESC_DIV_PREFIX TIMER_CTRL_PRESC_DIV
|
|
#define PRS_CH_CTRL_SOURCESEL_TIMER_DP GET_TIMER_REG(PRS_CH_CTRL_SOURCESEL, _SL_RAIL_UTIL_COEX_DP_TIMER)
|
|
#define PRS_CH_CTRL_SIGSEL_TIMER_DP GET_TIMER_REG(PRS_CH_CTRL_SIGSEL, _SL_RAIL_UTIL_COEX_DP_TIMER)
|
|
#define PRS_CH_CTRL_SIGSEL_TIMERCC0_DP GET_TIMER_REG(PRS_CH_CTRL_SIGSEL_TIMER_DP, CC0)
|
|
#else //!_SILICON_LABS_32B_SERIES_1
|
|
#define TIMER_DIVISOR 2
|
|
#define TIMER_PRESC_DIV_PREFIX TIMER_CFG_PRESC_DIV
|
|
#define PRS_CH_CTRL_SIGSEL_TIMER_DP GET_TIMER_REG(PRS_ASYNC, _SL_RAIL_UTIL_COEX_DP_TIMER)
|
|
#define PRS_CH_CTRL_SIGSEL_TIMERCC0_DP GET_TIMER_REG(PRS_CH_CTRL_SIGSEL_TIMER_DP, _CC0)
|
|
#endif //_SILICON_LABS_32B_SERIES_1
|
|
#define GET_TIMER_REG(reg, timer) GET_TIMER_REG_(reg, timer)
|
|
#define GET_TIMER_REG_(reg, timer) reg ## timer
|
|
|
|
#if SL_RAIL_UTIL_COEX_PRI_SHARED
|
|
#define SL_RAIL_UTIL_COEX_DP_MODE gpioModeWiredOr
|
|
#else //!SL_RAIL_UTIL_COEX_PRI_SHARED
|
|
#define SL_RAIL_UTIL_COEX_DP_MODE gpioModePushPull
|
|
#endif //SL_RAIL_UTIL_COEX_PRI_SHARED
|
|
|
|
#ifdef HAL_CONFIG
|
|
#if defined(TIMER0) && SL_RAIL_UTIL_COEX_DP_TIMER == HAL_TIMER_TIMER0
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _TIMER0
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER (TIMER0)
|
|
#elif defined(TIMER1) && SL_RAIL_UTIL_COEX_DP_TIMER == HAL_TIMER_TIMER1
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _TIMER1
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER (TIMER1)
|
|
#elif defined(TIMER2) && SL_RAIL_UTIL_COEX_DP_TIMER == HAL_TIMER_TIMER2
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _TIMER2
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER (TIMER2)
|
|
#elif defined(TIMER3) && SL_RAIL_UTIL_COEX_DP_TIMER == HAL_TIMER_TIMER3
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _TIMER3
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER (TIMER3)
|
|
#elif defined(TIMER4) && SL_RAIL_UTIL_COEX_DP_TIMER == HAL_TIMER_TIMER4
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _TIMER4
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER (TIMER4)
|
|
#elif defined(TIMER5) && SL_RAIL_UTIL_COEX_DP_TIMER == HAL_TIMER_TIMER5
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _TIMER5
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER (TIMER5)
|
|
#elif defined(TIMER6) && SL_RAIL_UTIL_COEX_DP_TIMER == HAL_TIMER_TIMER6
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _TIMER6
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER (TIMER6)
|
|
#elif defined(WTIMER0) && SL_RAIL_UTIL_COEX_DP_TIMER == HAL_TIMER_WTIMER0
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _WTIMER0
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER (WTIMER0)
|
|
#elif defined(WTIMER1) && SL_RAIL_UTIL_COEX_DP_TIMER == HAL_TIMER_WTIMER1
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _WTIMER1
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER (WTIMER1)
|
|
#elif defined(WTIMER2) && SL_RAIL_UTIL_COEX_DP_TIMER == HAL_TIMER_WTIMER2
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _WTIMER2
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER (WTIMER2)
|
|
#elif defined(WTIMER3) && SL_RAIL_UTIL_COEX_DP_TIMER == HAL_TIMER_WTIMER3
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _WTIMER3
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER (WTIMER3)
|
|
#else
|
|
#error "Unrecognized timer selection!"
|
|
#endif
|
|
#else //!HAL_CONFIG
|
|
#define __STRIP_TYPECAST(x)
|
|
#define _STRIP_TYPECAST(x) __STRIP_TYPECAST x
|
|
#define STRIP_TYPECAST(x) _STRIP_TYPECAST x
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER_ADDR STRIP_TYPECAST(SL_RAIL_UTIL_COEX_DP_TIMER_PERIPHERAL)
|
|
|
|
#if defined(TIMER0_BASE) && SL_RAIL_UTIL_COEX_DP_TIMER_ADDR == TIMER0_BASE
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _TIMER0
|
|
#elif defined(TIMER1_BASE) && SL_RAIL_UTIL_COEX_DP_TIMER_ADDR == TIMER1_BASE
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _TIMER1
|
|
#elif defined(TIMER2_BASE) && SL_RAIL_UTIL_COEX_DP_TIMER_ADDR == TIMER2_BASE
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _TIMER2
|
|
#elif defined(TIMER3_BASE) && SL_RAIL_UTIL_COEX_DP_TIMER_ADDR == TIMER3_BASE
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _TIMER3
|
|
#elif defined(TIMER4_BASE) && SL_RAIL_UTIL_COEX_DP_TIMER_ADDR == TIMER4_BASE
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _TIMER4
|
|
#elif defined(TIMER5_BASE) && SL_RAIL_UTIL_COEX_DP_TIMER_ADDR == TIMER5_BASE
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _TIMER5
|
|
#elif defined(TIMER6_BASE) && SL_RAIL_UTIL_COEX_DP_TIMER_ADDR == TIMER6_BASE
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _TIMER6
|
|
#elif defined(WTIMER0_BASE) && SL_RAIL_UTIL_COEX_DP_TIMER_ADDR == WTIMER0_BASE
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _WTIMER0
|
|
#elif defined(WTIMER1_BASE) && SL_RAIL_UTIL_COEX_DP_TIMER_ADDR == WTIMER1_BASE
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _WTIMER1
|
|
#elif defined(WTIMER2_BASE) && SL_RAIL_UTIL_COEX_DP_TIMER_ADDR == WTIMER2_BASE
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _WTIMER2
|
|
#elif defined(WTIMER3_BASE) && SL_RAIL_UTIL_COEX_DP_TIMER_ADDR == WTIMER3_BASE
|
|
#define _SL_RAIL_UTIL_COEX_DP_TIMER _WTIMER3
|
|
#else
|
|
#error "Unrecognized timer selection!"
|
|
#endif
|
|
#define SL_RAIL_UTIL_COEX_DP_TIMER SL_RAIL_UTIL_COEX_DP_TIMER_PERIPHERAL
|
|
#endif //HAL_CONFIG
|
|
|
|
#define PRS_GPIO_SIGNAL(pin) ((pin) & 7U)
|
|
|
|
#ifdef _SILICON_LABS_32B_SERIES_1
|
|
#define PRS_GPIO_SOURCE(pin) \
|
|
(((pin) > 7U) ? PRS_CH_CTRL_SOURCESEL_GPIOH \
|
|
: PRS_CH_CTRL_SOURCESEL_GPIOL)
|
|
#define PRS_CHANNEL_SOURCE(ch) \
|
|
(((ch) > 7U) ? PRS_CH_CTRL_SOURCESEL_PRSH \
|
|
: PRS_CH_CTRL_SOURCESEL_PRSL)
|
|
#else //!_SILICON_LABS_32B_SERIES_1
|
|
#define PRS_GPIO_SOURCE(pin) (PRS_ASYNC_CH_CTRL_SOURCESEL_GPIO)
|
|
#endif //_SILICON_LABS_32B_SERIES_1
|
|
|
|
#define PRS_CHANNEL_SIGNAL(ch) ((ch) & 7U)
|
|
|
|
static uint8_t directionalPriorityPulseWidthUs;
|
|
static bool directionalPriorityInitialized = false;
|
|
|
|
typedef struct PRS_ChannelConfig {
|
|
uint32_t source;
|
|
uint32_t signal;
|
|
uint32_t ctrl;
|
|
uint32_t channel;
|
|
} PRS_ChannelConfig_t;
|
|
|
|
#define TIMER_PRESC_DIV GET_TIMER_REG(TIMER_PRESC_DIV_PREFIX, TIMER_DIVISOR)
|
|
#define TIMER_FREQUENCY (CMU_ClockFreqGet(cmuClock_TIMER_DP) / TIMER_DIVISOR)
|
|
#define MICROSECONDS_PER_SECOND (1000000UL)
|
|
|
|
/** Map TIMER reference to index of device. */
|
|
#define TIMER_DEVICE_ID(timer) ( \
|
|
(timer) == TIMER0 ? 0 \
|
|
: (timer) == TIMER1 ? 1 \
|
|
: (timer) == TIMER2 ? 2 \
|
|
: (timer) == TIMER3 ? 3 \
|
|
: -1)
|
|
|
|
static bool configDpTimer(uint8_t pulseWidthUs)
|
|
{
|
|
uint32_t ticks = (pulseWidthUs * TIMER_FREQUENCY) / MICROSECONDS_PER_SECOND;
|
|
// Setup TIMER for ONE-SHOT Triggers by REQUEST rising edge-----------------
|
|
CMU_ClockEnable(cmuClock_TIMER_DP, true); // turn on clock to TIMER
|
|
|
|
// Reset compare output at start, run off HFPERCLK / 16, run in debug, count up,
|
|
// Reload on rising edge, use one-shot mode
|
|
// set PRS to track CC out level, set on start, clear on compare, PWM
|
|
#ifdef _SILICON_LABS_32B_SERIES_1
|
|
TIMER_Enable(SL_RAIL_UTIL_COEX_DP_TIMER, false); // stop TIMER
|
|
|
|
SL_RAIL_UTIL_COEX_DP_TIMER->CTRL = TIMER_CTRL_OSMEN
|
|
| TIMER_CTRL_DEBUGRUN
|
|
| TIMER_CTRL_RISEA_RELOADSTART
|
|
| TIMER_PRESC_DIV
|
|
| TIMER_CTRL_RSSCOIST;
|
|
SL_RAIL_UTIL_COEX_DP_TIMER->CC[0].CTRL = TIMER_CC_CTRL_MODE_PWM
|
|
| TIMER_CC_CTRL_OUTINV
|
|
| TIMER_CC_CTRL_CMOA_SET
|
|
| TIMER_CC_CTRL_PRSCONF;
|
|
|
|
// Setup REQUEST GPIO as TIMx_CC0 trigger input
|
|
// Configure TX/RX PRS output to selected channel and location
|
|
// The TIMER_CC0 GPIO selected in HWCONF must match the selected
|
|
// SL_RAIL_UTIL_COEX_REQ GPIO(or SL_RAIL_UTIL_COEX_PWM_REQ GPIO if available)
|
|
BUS_RegMaskedClear(&SL_RAIL_UTIL_COEX_DP_TIMER->ROUTELOC0, _TIMER_ROUTELOC0_CC0LOC_MASK);
|
|
BUS_RegMaskedSet(&SL_RAIL_UTIL_COEX_DP_TIMER->ROUTELOC0, SL_RAIL_UTIL_COEX_DP_TIMER_CC0_LOC);
|
|
#else // !_SILICON_LABS_32B_SERIES_1
|
|
SL_RAIL_UTIL_COEX_DP_TIMER->EN_CLR = TIMER_EN_EN;
|
|
SL_RAIL_UTIL_COEX_DP_TIMER->CFG = TIMER_CFG_OSMEN
|
|
| TIMER_CFG_DEBUGRUN
|
|
| TIMER_PRESC_DIV
|
|
| TIMER_CFG_RSSCOIST;
|
|
SL_RAIL_UTIL_COEX_DP_TIMER->CC[0].CFG = TIMER_CC_CFG_MODE_PWM
|
|
| TIMER_CC_CFG_PRSCONF;
|
|
SL_RAIL_UTIL_COEX_DP_TIMER->EN_SET = TIMER_EN_EN;
|
|
|
|
SL_RAIL_UTIL_COEX_DP_TIMER->CTRL = TIMER_CTRL_RISEA_RELOADSTART;
|
|
SL_RAIL_UTIL_COEX_DP_TIMER->CC[0].CTRL = TIMER_CC_CTRL_OUTINV
|
|
| TIMER_CC_CTRL_CMOA_SET;
|
|
GPIO->TIMERROUTE[TIMER_DEVICE_ID(SL_RAIL_UTIL_COEX_DP_TIMER)].CC0ROUTE = (SL_RAIL_UTIL_COEX_DP_TIMER_CC0_PORT << _GPIO_TIMER_CC0ROUTE_PORT_SHIFT)
|
|
| (SL_RAIL_UTIL_COEX_DP_TIMER_CC0_PIN
|
|
<< _GPIO_TIMER_CC0ROUTE_PIN_SHIFT);
|
|
#endif // _SILICON_LABS_32B_SERIES_1
|
|
// pulse => CEIL(1200kHz*PULSE-1)
|
|
TIMER_TopBufSet(SL_RAIL_UTIL_COEX_DP_TIMER, ticks);
|
|
TIMER_TopSet(SL_RAIL_UTIL_COEX_DP_TIMER, ticks);
|
|
// reset count
|
|
TIMER_CounterSet(SL_RAIL_UTIL_COEX_DP_TIMER, 0);
|
|
|
|
// pulse => CEIL(1200kHz*PULSE-1)
|
|
TIMER_CompareBufSet(SL_RAIL_UTIL_COEX_DP_TIMER, 0, ticks);
|
|
TIMER_CompareSet(SL_RAIL_UTIL_COEX_DP_TIMER, 0, ticks);
|
|
TIMER_Enable(SL_RAIL_UTIL_COEX_DP_TIMER, true); // start TIMER
|
|
|
|
return true;
|
|
}
|
|
|
|
__STATIC_INLINE void configPrsChain(PRS_ChannelConfig_t *prsConfig,
|
|
unsigned int channelCount)
|
|
{
|
|
for (unsigned int ch = 0; ch < channelCount; ++ch) {
|
|
#ifdef _SILICON_LABS_32B_SERIES_1
|
|
PRS->CH[prsConfig[ch].channel].CTRL = 0U;
|
|
#endif //_SILICON_LABS_32B_SERIES_1
|
|
PRS_SourceAsyncSignalSet(prsConfig[ch].channel,
|
|
prsConfig[ch].source,
|
|
prsConfig[ch].signal);
|
|
#ifdef _SILICON_LABS_32B_SERIES_1
|
|
PRS->CH[prsConfig[ch].channel].CTRL |= prsConfig[ch].ctrl;
|
|
#else //!_SILICON_LABS_32B_SERIES_1
|
|
PRS_Combine(prsConfig[ch].channel,
|
|
WRAP_PRS_ASYNC(prsConfig[ch].channel - 1),
|
|
(PRS_Logic_t)prsConfig[ch].ctrl);
|
|
#endif //_SILICON_LABS_32B_SERIES_1
|
|
}
|
|
}
|
|
|
|
#define CONFIG_PRS_CHAIN(prsChain) (configPrsChain(prsChain, \
|
|
sizeof(prsChain) / sizeof(prsChain[0])))
|
|
|
|
PRS_ChannelConfig_t prsChainOff[] = {
|
|
#ifdef SL_RAIL_UTIL_COEX_PRI_INTNO
|
|
{
|
|
.source = PRS_GPIO_SOURCE(SL_RAIL_UTIL_COEX_PRI_INTNO),
|
|
.signal = PRS_GPIO_SIGNAL(SL_RAIL_UTIL_COEX_PRI_INTNO),
|
|
#ifndef _SILICON_LABS_32B_SERIES_1
|
|
.ctrl = prsLogic_A,
|
|
#endif
|
|
.channel = SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL
|
|
}
|
|
#elif defined(_SILICON_LABS_32B_SERIES_1) //!defined(SL_RAIL_UTIL_COEX_PRI_INTNO)
|
|
{
|
|
.source = PRS_CHANNEL_SOURCE(SL_RAIL_UTIL_COEX_DP_REQUEST_INV_CHANNEL),
|
|
.signal = PRS_CHANNEL_SIGNAL(SL_RAIL_UTIL_COEX_DP_REQUEST_INV_CHANNEL),
|
|
.ctrl = PRS_CH_CTRL_INV,
|
|
.channel = WRAP_PRS_ASYNC(SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL - 2)
|
|
},
|
|
{
|
|
.source = PRS_CHANNEL_SOURCE(SL_RAIL_UTIL_COEX_DP_REQUEST_INV_CHANNEL),
|
|
.signal = PRS_CHANNEL_SIGNAL(SL_RAIL_UTIL_COEX_DP_REQUEST_INV_CHANNEL),
|
|
.ctrl = PRS_CH_CTRL_ORPREV | PRS_CH_CTRL_INV,
|
|
.channel = WRAP_PRS_ASYNC(SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL - 1)
|
|
},
|
|
{
|
|
.source = PRS_CHANNEL_SOURCE(SL_RAIL_UTIL_COEX_DP_REQUEST_INV_CHANNEL),
|
|
.signal = PRS_CHANNEL_SIGNAL(SL_RAIL_UTIL_COEX_DP_REQUEST_INV_CHANNEL),
|
|
.ctrl = PRS_CH_CTRL_ORPREV | PRS_CH_CTRL_INV,
|
|
.channel = SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL
|
|
},
|
|
#else //!(defined(_SILICON_LABS_32B_SERIES_1) || defined(SL_RAIL_UTIL_COEX_PRI_INTNO))
|
|
{
|
|
.source = PRS_GPIO_SOURCE(SL_RAIL_UTIL_COEX_DP_TIMER_CC0_INTNO),
|
|
.signal = PRS_GPIO_SIGNAL(SL_RAIL_UTIL_COEX_DP_TIMER_CC0_INTNO),
|
|
.ctrl = prsLogic_A,
|
|
.channel = WRAP_PRS_ASYNC(SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL - 2)
|
|
},
|
|
{
|
|
.source = PRS_GPIO_SOURCE(SL_RAIL_UTIL_COEX_DP_TIMER_CC0_INTNO),
|
|
.signal = PRS_GPIO_SIGNAL(SL_RAIL_UTIL_COEX_DP_TIMER_CC0_INTNO),
|
|
.ctrl = prsLogic_A,
|
|
.channel = WRAP_PRS_ASYNC(SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL - 1)
|
|
},
|
|
{
|
|
.source = PRS_GPIO_SOURCE(SL_RAIL_UTIL_COEX_DP_TIMER_CC0_INTNO),
|
|
.signal = PRS_GPIO_SIGNAL(SL_RAIL_UTIL_COEX_DP_TIMER_CC0_INTNO),
|
|
.ctrl = prsLogic_A_AND_NOT_B,
|
|
.channel = SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL
|
|
}
|
|
#endif //SL_RAIL_UTIL_COEX_PRI_INTNO
|
|
};
|
|
|
|
#ifdef PRS_RACL_PAEN
|
|
#define PRS_RAC_PAEN PRS_RACL_PAEN
|
|
#endif
|
|
|
|
#ifndef _SILICON_LABS_32B_SERIES_1
|
|
PRS_ChannelConfig_t prsChainOn[] = {
|
|
#ifdef SL_RAIL_UTIL_COEX_PRI_INTNO
|
|
{
|
|
.source = PRS_GPIO_SOURCE(SL_RAIL_UTIL_COEX_PRI_INTNO),
|
|
.signal = PRS_GPIO_SIGNAL(SL_RAIL_UTIL_COEX_PRI_INTNO),
|
|
.ctrl = prsLogic_A,
|
|
.channel = WRAP_PRS_ASYNC(SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL - 3)
|
|
},
|
|
{
|
|
.signal = PRS_CH_CTRL_SIGSEL_TIMERCC0_DP,
|
|
.ctrl = prsLogic_NOT_A_AND_B,
|
|
.channel = WRAP_PRS_ASYNC(SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL - 2)
|
|
},
|
|
{
|
|
.signal = PRS_RAC_PAEN,
|
|
.ctrl = prsLogic_A_NOR_B,
|
|
.channel = WRAP_PRS_ASYNC(SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL - 1)
|
|
},
|
|
#else //!SL_RAIL_UTIL_COEX_PRI_INTNO
|
|
{
|
|
.signal = PRS_CH_CTRL_SIGSEL_TIMERCC0_DP,
|
|
.ctrl = prsLogic_NOT_A,
|
|
.channel = WRAP_PRS_ASYNC(SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL - 2)
|
|
},
|
|
{
|
|
.signal = PRS_RAC_PAEN,
|
|
.ctrl = prsLogic_NOT_A,
|
|
.channel = WRAP_PRS_ASYNC(SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL - 1)
|
|
},
|
|
#endif //SL_RAIL_UTIL_COEX_PRI_INTNO
|
|
{
|
|
.source = PRS_GPIO_SOURCE(SL_RAIL_UTIL_COEX_DP_TIMER_CC0_INTNO),
|
|
.signal = PRS_GPIO_SIGNAL(SL_RAIL_UTIL_COEX_DP_TIMER_CC0_INTNO),
|
|
.ctrl = prsLogic_A_AND_NOT_B,
|
|
.channel = SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL
|
|
}
|
|
};
|
|
#else
|
|
PRS_ChannelConfig_t prsChainOn[] = {
|
|
{
|
|
.source = PRS_GPIO_SOURCE(SL_RAIL_UTIL_COEX_DP_TIMER_CC0_INTNO),
|
|
.signal = PRS_GPIO_SIGNAL(SL_RAIL_UTIL_COEX_DP_TIMER_CC0_INTNO),
|
|
.ctrl = PRS_CH_CTRL_INV,
|
|
.channel = SL_RAIL_UTIL_COEX_DP_REQUEST_INV_CHANNEL
|
|
},
|
|
#ifdef SL_RAIL_UTIL_COEX_PRI_INTNO
|
|
{
|
|
.source = PRS_GPIO_SOURCE(SL_RAIL_UTIL_COEX_PRI_INTNO),
|
|
.signal = PRS_GPIO_SIGNAL(SL_RAIL_UTIL_COEX_PRI_INTNO),
|
|
.ctrl = PRS_CH_CTRL_INV,
|
|
.channel = WRAP_PRS_ASYNC(SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL - 3)
|
|
},
|
|
{
|
|
.source = PRS_CH_CTRL_SOURCESEL_TIMER_DP,
|
|
.signal = PRS_CH_CTRL_SIGSEL_TIMERCC0_DP,
|
|
.ctrl = PRS_CH_CTRL_ORPREV | PRS_CH_CTRL_INV,
|
|
.channel = WRAP_PRS_ASYNC(SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL - 2)
|
|
},
|
|
{
|
|
.signal = PRS_RAC_PAEN,
|
|
.ctrl = PRS_CH_CTRL_ORPREV | PRS_CH_CTRL_INV,
|
|
.channel = WRAP_PRS_ASYNC(SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL - 1)
|
|
},
|
|
#else //!SL_RAIL_UTIL_COEX_PRI_INTNO
|
|
{
|
|
.source = PRS_CH_CTRL_SOURCESEL_TIMER_DP,
|
|
.signal = PRS_CH_CTRL_SIGSEL_TIMERCC0_DP,
|
|
.ctrl = PRS_CH_CTRL_INV,
|
|
.channel = WRAP_PRS_ASYNC(SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL - 2)
|
|
},
|
|
{
|
|
.signal = PRS_RAC_PAEN,
|
|
.ctrl = PRS_CH_CTRL_INV,
|
|
.channel = WRAP_PRS_ASYNC(SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL - 1)
|
|
},
|
|
#endif //SL_RAIL_UTIL_COEX_PRI_INTNO
|
|
{
|
|
.source = PRS_CHANNEL_SOURCE(SL_RAIL_UTIL_COEX_DP_REQUEST_INV_CHANNEL),
|
|
.signal = PRS_CHANNEL_SIGNAL(SL_RAIL_UTIL_COEX_DP_REQUEST_INV_CHANNEL),
|
|
.ctrl = PRS_CH_CTRL_ORPREV | PRS_CH_CTRL_INV,
|
|
.channel = SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL
|
|
}
|
|
};
|
|
#endif
|
|
|
|
bool COEX_HAL_ConfigDp(uint8_t pulseWidthUs)
|
|
{
|
|
// Common PRS setup (clock enable, REQUEST and PRIORITY GPIO INT PRS sources)
|
|
// enable clock to PRS
|
|
CMU_ClockEnable(cmuClock_PRS, true);
|
|
|
|
#ifdef SL_RAIL_UTIL_COEX_PRI_PORT
|
|
// Disable priority and request interrupts
|
|
GPIO_ExtIntConfig(SL_RAIL_UTIL_COEX_PRI_PORT,
|
|
SL_RAIL_UTIL_COEX_PRI_PIN,
|
|
SL_RAIL_UTIL_COEX_PRI_INTNO,
|
|
false,
|
|
false,
|
|
false);
|
|
#endif //SL_RAIL_UTIL_COEX_PRI_PORT
|
|
GPIO_ExtIntConfig(SL_RAIL_UTIL_COEX_DP_TIMER_CC0_PORT,
|
|
SL_RAIL_UTIL_COEX_DP_TIMER_CC0_PIN,
|
|
SL_RAIL_UTIL_COEX_DP_TIMER_CC0_INTNO,
|
|
false,
|
|
false,
|
|
false);
|
|
// Common PRS wrap-up (enable PRIORITY GPIO, route PRS output to GPIO)
|
|
// enable PRIORITY output pin with initial value of 0
|
|
GPIO_PinModeSet(SL_RAIL_UTIL_COEX_DP_OUT_PORT,
|
|
SL_RAIL_UTIL_COEX_DP_OUT_PIN,
|
|
SL_RAIL_UTIL_COEX_DP_MODE,
|
|
0);
|
|
#ifdef _SILICON_LABS_32B_SERIES_1
|
|
volatile uint32_t * routeRegister;
|
|
// Configure directional priority PRS output to selected channel and location
|
|
if (SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL < 4) {
|
|
routeRegister = &PRS->ROUTELOC0;
|
|
} else if (SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL < 8) {
|
|
routeRegister = &PRS->ROUTELOC1;
|
|
} else if (SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL < 12) {
|
|
routeRegister = &PRS->ROUTELOC2;
|
|
} else {
|
|
return false; // error
|
|
}
|
|
// Route PRS CH/LOC to PRIORITY GPIO output
|
|
BUS_RegMaskedClear(routeRegister, 0xFFU << ((SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL & 3) * 8));
|
|
BUS_RegMaskedSet(routeRegister, SL_RAIL_UTIL_COEX_DP_OUT_LOC << ((SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL & 3) * 8));
|
|
BUS_RegMaskedSet(&PRS->ROUTEPEN, (1 << SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL));
|
|
#else //!_SILICON_LABS_32B_SERIES_1
|
|
PRS_PinOutput(SL_RAIL_UTIL_COEX_DP_OUT_CHANNEL, prsTypeAsync, SL_RAIL_UTIL_COEX_DP_OUT_PORT, SL_RAIL_UTIL_COEX_DP_OUT_PIN);
|
|
#endif //_SILICON_LABS_32B_SERIES_1
|
|
return COEX_HAL_SetDpPulseWidth(pulseWidthUs);
|
|
}
|
|
|
|
bool COEX_HAL_SetDpPulseWidth(uint8_t pulseWidthUs)
|
|
{
|
|
if (directionalPriorityInitialized
|
|
&& directionalPriorityPulseWidthUs == pulseWidthUs) {
|
|
return true;
|
|
}
|
|
directionalPriorityInitialized = true;
|
|
directionalPriorityPulseWidthUs = pulseWidthUs;
|
|
if (pulseWidthUs == 0) {
|
|
#ifndef _SILICON_LABS_32B_SERIES_1
|
|
SL_RAIL_UTIL_COEX_DP_TIMER->EN_SET = TIMER_EN_EN;
|
|
#endif //!_SILICON_LABS_32B_SERIES_1
|
|
TIMER_Enable(SL_RAIL_UTIL_COEX_DP_TIMER, false);
|
|
CONFIG_PRS_CHAIN(prsChainOff);
|
|
return true;
|
|
}
|
|
if (!configDpTimer(directionalPriorityPulseWidthUs)) {
|
|
return false;
|
|
}
|
|
CONFIG_PRS_CHAIN(prsChainOn);
|
|
return true;
|
|
}
|
|
|
|
uint8_t COEX_HAL_GetDpPulseWidth(void)
|
|
{
|
|
return directionalPriorityPulseWidthUs;
|
|
}
|
|
|
|
#else //!SL_RAIL_UTIL_COEX_DP_ENABLED
|
|
|
|
bool COEX_HAL_ConfigDp(uint8_t pulseWidthUs)
|
|
{
|
|
(void)pulseWidthUs;
|
|
return false;
|
|
}
|
|
|
|
uint8_t COEX_HAL_GetDpPulseWidth(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
bool COEX_HAL_SetDpPulseWidth(uint8_t pulseWidthUs)
|
|
{
|
|
(void)pulseWidthUs;
|
|
return false;
|
|
}
|
|
#endif //SL_RAIL_UTIL_COEX_DP_ENABLED
|