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.
490 lines
17 KiB
C
490 lines
17 KiB
C
/***************************************************************************//**
|
|
* @file
|
|
* @brief PA power conversion functions provided to the customer as source for
|
|
* highest level of customization.
|
|
* @details This file contains the curves and logic that convert PA power
|
|
* levels to dBm powers.
|
|
*******************************************************************************
|
|
* # License
|
|
* <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
|
|
*******************************************************************************
|
|
*
|
|
* SPDX-License-Identifier: Zlib
|
|
*
|
|
* The licensor of this software is Silicon Laboratories Inc.
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
* arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include "em_device.h"
|
|
#include "em_cmu.h"
|
|
#include "em_common.h"
|
|
#include "pa_conversions_efr32.h"
|
|
#include "rail.h"
|
|
|
|
static RAIL_TxPowerCurvesConfigAlt_t powerCurvesState;
|
|
|
|
#if defined(_SILICON_LABS_32B_SERIES_1) || defined(_SILICON_LAS_32B_SERIES_2_CONFIG_1)
|
|
#define PA_CONVERSION_MINIMUM_PWRLVL 1
|
|
#else
|
|
#define PA_CONVERSION_MINIMUM_PWRLVL 0
|
|
#endif
|
|
|
|
// This macro is defined when Silicon Labs builds this into the library as WEAK
|
|
// to ensure it can be overriden by customer versions of these functions. It
|
|
// should *not* be defined in a customer build.
|
|
#ifdef RAIL_PA_CONVERSIONS_WEAK
|
|
SL_WEAK
|
|
#endif
|
|
const RAIL_TxPowerCurves_t *RAIL_GetTxPowerCurve(RAIL_TxPowerMode_t mode)
|
|
{
|
|
static RAIL_TxPowerCurves_t powerCurves;
|
|
|
|
// Check for an invalid Tx power mode
|
|
if (mode >= RAIL_TX_POWER_MODE_NONE) {
|
|
return NULL;
|
|
}
|
|
|
|
// Check for *_HIGHEST invalid Tx power modes on series 2 chips
|
|
#if defined(RAIL_TX_POWER_MODE_2P4GIG_HIGHEST)
|
|
if (mode == RAIL_TX_POWER_MODE_2P4GIG_HIGHEST) {
|
|
return NULL;
|
|
}
|
|
#endif // RAIL_TX_POWER_MODE_2P4GIG_HIGHEST
|
|
#if defined(RAIL_TX_POWER_MODE_SUBGIG_HIGHEST)
|
|
if (mode == RAIL_TX_POWER_MODE_SUBGIG_HIGHEST) {
|
|
return NULL;
|
|
}
|
|
#endif // RAIL_TX_POWER_MODE_SUBGIG_HIGHEST
|
|
|
|
RAIL_TxPowerCurveAlt_t const *curve =
|
|
powerCurvesState.curves[mode].conversion.powerCurve;
|
|
|
|
// Check for an invalid power curve
|
|
if (curve == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
powerCurves.maxPower = curve->maxPower;
|
|
powerCurves.minPower = curve->minPower;
|
|
powerCurves.powerParams = &curve->powerParams[0];
|
|
return &powerCurves;
|
|
}
|
|
|
|
// This function will not be supported for any parts after efr32xg1x
|
|
#ifdef RAIL_PA_CONVERSIONS_WEAK
|
|
SL_WEAK
|
|
#endif
|
|
RAIL_Status_t RAIL_InitTxPowerCurves(const RAIL_TxPowerCurvesConfig_t *config)
|
|
{
|
|
#ifdef _SILICON_LABS_32B_SERIES_1
|
|
// First PA is 2.4 GHz high power, using a piecewise fit
|
|
RAIL_PaDescriptor_t *current =
|
|
&powerCurvesState.curves[RAIL_TX_POWER_MODE_2P4_HP];
|
|
current->algorithm = RAIL_PA_ALGORITHM_PIECEWISE_LINEAR;
|
|
current->segments = config->piecewiseSegments;
|
|
current->min = RAIL_TX_POWER_LEVEL_2P4_HP_MIN;
|
|
current->max = RAIL_TX_POWER_LEVEL_2P4_HP_MAX;
|
|
static RAIL_TxPowerCurveAlt_t txPower2p4 = {
|
|
.minPower = 0U,
|
|
.maxPower = 0U,
|
|
.powerParams = { // The current max number of piecewise segments is 8
|
|
{ 0U, 0U, 0U }, { 0U, 0U, 0U }, { 0U, 0U, 0U }, { 0U, 0U, 0U },
|
|
{ 0U, 0U, 0U }, { 0U, 0U, 0U }, { 0U, 0U, 0U }, { 0U, 0U, 0U },
|
|
}
|
|
};
|
|
txPower2p4.maxPower = config->txPowerSgCurves->maxPower;
|
|
txPower2p4.minPower = config->txPowerSgCurves->minPower;
|
|
memcpy(&txPower2p4.powerParams[0],
|
|
config->txPowerSgCurves->powerParams,
|
|
config->piecewiseSegments * sizeof(RAIL_TxPowerCurveSegment_t));
|
|
current->conversion.powerCurve = &txPower2p4;
|
|
|
|
// Second PA is 2.4 GHz low power, using a mapping table
|
|
current = &powerCurvesState.curves[RAIL_TX_POWER_MODE_2P4_LP];
|
|
current->algorithm = RAIL_PA_ALGORITHM_MAPPING_TABLE;
|
|
current->segments = 0U;
|
|
current->min = RAIL_TX_POWER_LEVEL_2P4_LP_MIN;
|
|
current->max = RAIL_TX_POWER_LEVEL_2P4_LP_MAX;
|
|
current->conversion.mappingTable = config->txPower24LpCurves;
|
|
|
|
// Third and final PA is Sub-GHz, using a piecewise fit
|
|
current = &powerCurvesState.curves[RAIL_TX_POWER_MODE_SUBGIG];
|
|
current->algorithm = RAIL_PA_ALGORITHM_PIECEWISE_LINEAR;
|
|
current->segments = config->piecewiseSegments;
|
|
current->min = RAIL_TX_POWER_LEVEL_SUBGIG_MIN;
|
|
current->max = RAIL_TX_POWER_LEVEL_SUBGIG_HP_MAX;
|
|
static RAIL_TxPowerCurveAlt_t txPowerSubGig = {
|
|
.minPower = 0U,
|
|
.maxPower = 0U,
|
|
.powerParams = { // The current max number of piecewise segments is 8
|
|
{ 0U, 0U, 0U }, { 0U, 0U, 0U }, { 0U, 0U, 0U }, { 0U, 0U, 0U },
|
|
{ 0U, 0U, 0U }, { 0U, 0U, 0U }, { 0U, 0U, 0U }, { 0U, 0U, 0U },
|
|
}
|
|
};
|
|
txPowerSubGig.maxPower = config->txPowerSgCurves->maxPower;
|
|
txPowerSubGig.minPower = config->txPowerSgCurves->minPower;
|
|
memcpy(&txPowerSubGig.powerParams[0],
|
|
config->txPowerSgCurves->powerParams,
|
|
config->piecewiseSegments * sizeof(RAIL_TxPowerCurveSegment_t));
|
|
current->conversion.powerCurve = &txPowerSubGig;
|
|
|
|
return RAIL_STATUS_NO_ERROR;
|
|
#else
|
|
(void) config;
|
|
return RAIL_STATUS_INVALID_CALL;
|
|
#endif
|
|
}
|
|
|
|
#ifdef RAIL_PA_CONVERSIONS_WEAK
|
|
SL_WEAK
|
|
#endif
|
|
RAIL_Status_t RAIL_InitTxPowerCurvesAlt(const RAIL_TxPowerCurvesConfigAlt_t *config)
|
|
{
|
|
RAIL_VerifyTxPowerCurves(config);
|
|
|
|
powerCurvesState = *config;
|
|
|
|
return RAIL_STATUS_NO_ERROR;
|
|
}
|
|
|
|
#ifdef RAIL_PA_CONVERSIONS_WEAK
|
|
SL_WEAK
|
|
#endif
|
|
RAIL_TxPowerLevel_t RAIL_ConvertDbmToRaw(RAIL_Handle_t railHandle,
|
|
RAIL_TxPowerMode_t mode,
|
|
RAIL_TxPower_t power)
|
|
{
|
|
uint32_t powerLevel;
|
|
int16_t powerIndex = 0;
|
|
uint32_t minPowerLevel;
|
|
|
|
(void)railHandle;
|
|
// This function is called internally from the RAIL library,
|
|
// so if the user never calls RAIL_InitTxPowerCurves - even
|
|
// if they never intend to use dBm values in their code -
|
|
// they'll always hit the assert below. Give the user a way
|
|
// to not have to call RAIL_InitTxPowerCurves if they don't
|
|
// care about dBm values by picking a dBm value that returns the
|
|
// highest RAIL_TxPowerLevel_t possible. In other words, when
|
|
// a channel dBm limitation greater than or equal to \ref RAIL_TX_POWER_MAX
|
|
// is converted to raw units, the max RAIL_TxPowerLevel_t will be
|
|
// returned. When compared to the current power level of the PA,
|
|
// it will always be greater, indicating that no power coercion
|
|
// is necessary to comply with channel limitations.
|
|
if (power >= RAIL_TX_POWER_MAX) {
|
|
return 255U;
|
|
}
|
|
|
|
// Check for an invalid Tx power mode
|
|
if (mode >= RAIL_TX_POWER_MODE_NONE) {
|
|
return 0U;
|
|
}
|
|
|
|
RAIL_PaDescriptor_t const *modeInfo = &powerCurvesState.curves[mode];
|
|
minPowerLevel = SL_MAX(modeInfo->min, PA_CONVERSION_MINIMUM_PWRLVL);
|
|
|
|
// If we're in low power mode, just use the simple lookup table
|
|
if (modeInfo->algorithm == RAIL_PA_ALGORITHM_MAPPING_TABLE) {
|
|
// Loop through the lookup table to find the closest power level
|
|
// without going over.
|
|
for (powerIndex = (int16_t)(modeInfo->max - minPowerLevel);
|
|
(powerIndex != 0) && (power < modeInfo->conversion.mappingTable[powerIndex]);
|
|
powerIndex--) {
|
|
// Searching...
|
|
}
|
|
return powerIndex + minPowerLevel;
|
|
}
|
|
|
|
// Here we know we're using the piecewise linear conversion
|
|
RAIL_TxPowerCurveSegment_t const *powerParams;
|
|
RAIL_TxPowerCurveAlt_t const *paParams = modeInfo->conversion.powerCurve;
|
|
|
|
// Check for valid paParams before using them
|
|
if (paParams == NULL) {
|
|
return 0U;
|
|
}
|
|
|
|
// Cap the power based on the PA settings.
|
|
if (power > paParams->maxPower) {
|
|
// If we go above the maximum dbm the chip supports
|
|
// Then provide maximum powerLevel
|
|
power = paParams->maxPower;
|
|
} else if (power < paParams->minPower) {
|
|
// If we go below the minimum we want included in the curve fit, force it.
|
|
power = paParams->minPower;
|
|
} else {
|
|
}
|
|
// Map the power value to a 0 - 7 powerIndex value
|
|
//There are 8 segments of step size of RAIL_TX_POWER_CURVE_INCREMENT in deci dBm
|
|
//starting from maximum RAIL_TX_POWER_CURVE_MAX in deci dBm
|
|
// These are just starting points to give the code
|
|
// a rough idea of which segment to use, based on
|
|
// how they were fit. Adjustments are made later on
|
|
// if this turns out to be incorrect.
|
|
RAIL_TxPower_t txPowerMax = RAIL_TX_POWER_CURVE_DEFAULT_MAX;
|
|
RAIL_TxPower_t txPowerIncrement = RAIL_TX_POWER_CURVE_DEFAULT_INCREMENT;
|
|
// if the first curve segment starts with RAIL_TX_POWER_LEVEL_INVALID
|
|
//It is an extra curve segment to depict the maxpower and increment
|
|
// (in deci-dBm) used while generating the curves.
|
|
// The extra segment is only present when curve segment is generated by
|
|
//using values different than the default - RAIL_TX_POWER_CURVE_DEFAULT_MAX
|
|
// and RAIL_TX_POWER_CURVE_DEFAULT_INCREMENT.
|
|
if ((paParams->powerParams[0].maxPowerLevel) == RAIL_TX_POWER_LEVEL_INVALID) {
|
|
powerIndex += 1;
|
|
txPowerMax = paParams->powerParams[0].slope;
|
|
txPowerIncrement = paParams->powerParams[0].intercept;
|
|
}
|
|
|
|
powerIndex += ((txPowerMax - power) / txPowerIncrement);
|
|
if (powerIndex > (int16_t)(modeInfo->segments - 1U)) {
|
|
powerIndex = (int16_t)(modeInfo->segments - 1U);
|
|
}
|
|
|
|
do {
|
|
// Select the correct piecewise segment to use for conversion.
|
|
powerParams = &paParams->powerParams[powerIndex];
|
|
|
|
// powerLevel can only go down to 0.
|
|
if (powerParams->intercept + powerParams->slope * power < 0) {
|
|
powerLevel = 0U;
|
|
} else {
|
|
powerLevel = powerParams->intercept + powerParams->slope * power;
|
|
}
|
|
|
|
// Add 500 to do rounding correctly, as opposed to just rounding towards 0
|
|
powerLevel = ((powerLevel + 500U) / 1000U);
|
|
|
|
// In case it turns out the resultant power level was too low and we have
|
|
// to recalculate with the next curve...
|
|
powerIndex++;
|
|
} while ((powerIndex < (int16_t)modeInfo->segments)
|
|
&& (powerLevel <= paParams->powerParams[powerIndex].maxPowerLevel));
|
|
|
|
// We already know that powerIndex is at most modeInfo->segments
|
|
if (powerLevel > paParams->powerParams[powerIndex - 1].maxPowerLevel) {
|
|
powerLevel = paParams->powerParams[powerIndex - 1].maxPowerLevel;
|
|
}
|
|
|
|
// If we go below the minimum we want included in the curve fit, force it.
|
|
if (powerLevel < minPowerLevel) {
|
|
powerLevel = minPowerLevel;
|
|
}
|
|
|
|
return (RAIL_TxPowerLevel_t)powerLevel;
|
|
}
|
|
|
|
#ifdef RAIL_PA_CONVERSIONS_WEAK
|
|
SL_WEAK
|
|
#endif
|
|
RAIL_TxPower_t RAIL_ConvertRawToDbm(RAIL_Handle_t railHandle,
|
|
RAIL_TxPowerMode_t mode,
|
|
RAIL_TxPowerLevel_t powerLevel)
|
|
{
|
|
(void)railHandle;
|
|
|
|
// Check for an invalid Tx power mode
|
|
if (mode >= RAIL_TX_POWER_MODE_NONE) {
|
|
return RAIL_TX_POWER_MIN;
|
|
}
|
|
|
|
RAIL_PaDescriptor_t const *modeInfo = &powerCurvesState.curves[mode];
|
|
|
|
if (modeInfo->algorithm == RAIL_PA_ALGORITHM_MAPPING_TABLE) {
|
|
// Limit the max power level
|
|
if (powerLevel > modeInfo->max) {
|
|
powerLevel = modeInfo->max;
|
|
}
|
|
|
|
// We 1-index low power PA power levels, but of course arrays are 0 indexed
|
|
powerLevel -= SL_MAX(modeInfo->min, PA_CONVERSION_MINIMUM_PWRLVL);
|
|
|
|
return modeInfo->conversion.mappingTable[powerLevel];
|
|
} else {
|
|
#if defined(_SILICON_LABS_32B_SERIES_1) || defined(_SILICON_LAS_32B_SERIES_2_CONFIG_1)
|
|
// Although 0 is a legitimate power on non-2.4 LP PA's and can be set via
|
|
// "RAIL_SetTxPower(railHandle, 0)" it is MUCH lower than power
|
|
// level 1 (approximately -50 dBm). Including it in the piecewise
|
|
// linear fit would skew the curve substantially, so we exclude it
|
|
// from the conversion.
|
|
if (powerLevel == 0U) {
|
|
return -500;
|
|
}
|
|
#endif
|
|
|
|
int32_t power;
|
|
|
|
RAIL_TxPowerCurveAlt_t const *powerCurve = modeInfo->conversion.powerCurve;
|
|
// Check for a valid powerCurve pointer before using it
|
|
if (powerCurve == NULL) {
|
|
return RAIL_TX_POWER_MIN;
|
|
}
|
|
|
|
RAIL_TxPowerCurveSegment_t const *powerParams = powerCurve->powerParams;
|
|
// Check for a valid powerParams pointer before using it
|
|
if (powerParams == NULL) {
|
|
return RAIL_TX_POWER_MIN;
|
|
}
|
|
|
|
// Hard code the extremes (i.e. don't use the curve fit) in order
|
|
// to make it clear that we are reaching the extent of the chip's
|
|
// capabilities
|
|
if (powerLevel <= powerCurve->minPower) {
|
|
return powerCurve->minPower;
|
|
} else if (powerLevel >= modeInfo->max) {
|
|
return powerCurve->maxPower;
|
|
} else {
|
|
}
|
|
|
|
// Figure out which parameter to use based on the power level
|
|
uint8_t x;
|
|
uint8_t upperBound = modeInfo->segments - 1U;
|
|
for (x = 0; x < upperBound; x++) {
|
|
if (powerParams[x + 1U].maxPowerLevel < powerLevel) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
power = ((1000 * (int32_t)(powerLevel)) - powerParams[x].intercept);
|
|
power = ((power + (powerParams[x].slope / 2)) / powerParams[x].slope);
|
|
|
|
if (power > powerCurve->maxPower) {
|
|
return powerCurve->maxPower;
|
|
} else if (power < powerCurve->minPower) {
|
|
return powerCurve->minPower;
|
|
} else {
|
|
return (RAIL_TxPower_t)power;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef RAIL_PA_CONVERSIONS_WEAK
|
|
SL_WEAK
|
|
#endif
|
|
RAIL_Status_t RAIL_GetTxPowerCurveLimits(RAIL_Handle_t railHandle,
|
|
RAIL_TxPowerMode_t mode,
|
|
RAIL_TxPower_t *maxPower,
|
|
RAIL_TxPower_t *increment)
|
|
{
|
|
(void)railHandle;
|
|
// Check for an invalid Tx power mode
|
|
if (mode >= RAIL_TX_POWER_MODE_NONE) {
|
|
return RAIL_STATUS_INVALID_PARAMETER;
|
|
}
|
|
//The power max info only for available Linear fit
|
|
RAIL_PaDescriptor_t const *modeInfo = &powerCurvesState.curves[mode];
|
|
if (modeInfo->algorithm == RAIL_PA_ALGORITHM_MAPPING_TABLE) {
|
|
return RAIL_STATUS_INVALID_CALL;
|
|
}
|
|
*maxPower = RAIL_TX_POWER_CURVE_DEFAULT_MAX;
|
|
*increment = RAIL_TX_POWER_CURVE_DEFAULT_INCREMENT;
|
|
RAIL_TxPowerCurveAlt_t const *paParams = modeInfo->conversion.powerCurve;
|
|
if ((paParams->powerParams[0].maxPowerLevel) == RAIL_TX_POWER_LEVEL_INVALID) {
|
|
*maxPower = paParams->powerParams[0].slope;
|
|
*increment = (RAIL_TxPower_t)paParams->powerParams[0].intercept;
|
|
}
|
|
return RAIL_STATUS_NO_ERROR;
|
|
}
|
|
|
|
// This macro is defined when Silicon Labs builds curves into the library as WEAK
|
|
// to ensure it can be overriden by customer versions of these functions. It
|
|
// should *not* be defined in a customer build.
|
|
#if !defined(RAIL_PA_CONVERSIONS_WEAK)
|
|
|
|
#include "sl_rail_util_pa_config.h"
|
|
|
|
void sl_rail_util_pa_init(void)
|
|
{
|
|
#if SL_RAIL_UTIL_PA_VOLTAGE_MV > 1800
|
|
(void)RAIL_InitTxPowerCurvesAlt(&RAIL_TxPowerCurvesVbat);
|
|
#else
|
|
(void)RAIL_InitTxPowerCurvesAlt(&RAIL_TxPowerCurvesDcdc);
|
|
#endif
|
|
#if SL_RAIL_UTIL_PA_CALIBRATION_ENABLE
|
|
RAIL_EnablePaCal(true);
|
|
#endif
|
|
}
|
|
|
|
static RAIL_TxPowerConfig_t txPowerConfig2p4Ghz = {
|
|
.mode = SL_RAIL_UTIL_PA_SELECTION_2P4GHZ,
|
|
.voltage = SL_RAIL_UTIL_PA_VOLTAGE_MV,
|
|
.rampTime = SL_RAIL_UTIL_PA_RAMP_TIME_US,
|
|
};
|
|
static RAIL_TxPowerConfig_t txPowerConfigSubGhz = {
|
|
.mode = SL_RAIL_UTIL_PA_SELECTION_SUBGHZ,
|
|
.voltage = SL_RAIL_UTIL_PA_VOLTAGE_MV,
|
|
.rampTime = SL_RAIL_UTIL_PA_RAMP_TIME_US,
|
|
};
|
|
RAIL_TxPowerConfig_t *sl_rail_util_pa_get_tx_power_config_2p4ghz(void)
|
|
{
|
|
return &txPowerConfig2p4Ghz;
|
|
}
|
|
RAIL_TxPowerConfig_t *sl_rail_util_pa_get_tx_power_config_subghz(void)
|
|
{
|
|
return &txPowerConfigSubGhz;
|
|
}
|
|
|
|
void sl_rail_util_pa_on_channel_config_change(RAIL_Handle_t rail_handle,
|
|
const RAIL_ChannelConfigEntry_t *entry)
|
|
{
|
|
if (!RAIL_IsPaAutoModeEnabled(rail_handle)) {
|
|
RAIL_TxPowerConfig_t currentTxPowerConfig;
|
|
RAIL_TxPowerConfig_t *newTxPowerConfigPtr;
|
|
RAIL_TxPower_t txPowerDeciDbm;
|
|
RAIL_Status_t status;
|
|
|
|
// Get current TX Power Config.
|
|
status = RAIL_GetTxPowerConfig(rail_handle, ¤tTxPowerConfig);
|
|
if (status != RAIL_STATUS_NO_ERROR) {
|
|
while (true) {
|
|
} // Error: Can't get TX Power Config
|
|
}
|
|
|
|
// Determine new TX Power Config.
|
|
if (entry->baseFrequency < 1000000000UL) {
|
|
newTxPowerConfigPtr = &txPowerConfigSubGhz;
|
|
} else {
|
|
newTxPowerConfigPtr = &txPowerConfig2p4Ghz;
|
|
}
|
|
|
|
// Call RAIL_ConfigTxPower only if TX Power Config mode has changed.
|
|
if (currentTxPowerConfig.mode != newTxPowerConfigPtr->mode) {
|
|
// Save current TX power before RAIL_ConfigTxPower (because not preserved).
|
|
if (currentTxPowerConfig.mode == RAIL_TX_POWER_MODE_NONE) {
|
|
txPowerDeciDbm = SL_RAIL_UTIL_PA_POWER_DECI_DBM;
|
|
} else {
|
|
txPowerDeciDbm = RAIL_GetTxPowerDbm(rail_handle);
|
|
}
|
|
|
|
// Apply new TX Power Config.
|
|
status = RAIL_ConfigTxPower(rail_handle, newTxPowerConfigPtr);
|
|
if (status != RAIL_STATUS_NO_ERROR) {
|
|
while (true) {
|
|
} // Error: Can't set TX Power Config
|
|
}
|
|
// Restore TX power after RAIL_ConfigTxPower.
|
|
status = RAIL_SetTxPowerDbm(rail_handle, txPowerDeciDbm);
|
|
if (status != RAIL_STATUS_NO_ERROR) {
|
|
while (true) {
|
|
} // Error: Can't set TX Power
|
|
}
|
|
}
|
|
} // !RAIL_IsPaAutoModeEnabled
|
|
}
|
|
#endif // !RAIL_PA_CONVERSIONS_WEAK
|