Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[DRAFT] Get rid of FEM gain #14553

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions include/fem_al/fem_al.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ enum fem_antenna {
FEM_ANTENNA_2
};

/**@brief Type holding Tx power control to be applied to front-end module.
*
* @note The value stored in this type is specific to the FEM type in use.
*/
typedef uint32_t fem_tx_power_control;

/**@brief Initialize the front-end module.
*
* @param[in] timer_instance Pointer to a 1-us resolution timer instance.
Expand Down Expand Up @@ -68,17 +74,17 @@ int fem_power_up(void);
*/
int fem_power_down(void);

/**@brief Configure Tx gain of the front-end module in arbitrary units.
/**@brief Configure Tx power control of the front-end module.
*
* @param[in] gain Tx gain in arbitrary units specific for used front-end module implementation.
* @param[in] tx_power_control Tx power control specific to the front-end module implementation.
* For nRF21540 GPIO/SPI, this is a register value.
* For nRF21540 GPIO, this is MODE pin value.
* Check your front-end module product specification for gain value range.
* Check your front-end module product specification for Tx power control value range.
*
* @retval 0 If the operation was successful.
* Otherwise, a (negative) error code is returned.
*/
int fem_tx_gain_set(uint32_t gain);
int fem_tx_power_control_set(fem_tx_power_control tx_power_control);

/**@brief Get the default radio ramp-up time for reception or transmission with a given data rate
* and modulation.
Expand Down Expand Up @@ -145,11 +151,11 @@ uint32_t fem_radio_tx_ramp_up_delay_get(bool fast, nrf_radio_mode_t mode);
*/
uint32_t fem_radio_rx_ramp_up_delay_get(bool fast, nrf_radio_mode_t mode);

/**@brief Set the front-end module gain and returns output power to be set on the radio peripheral
* to get requested output power.
/**@brief Set the front-end module Tx power control and returns output power
* to be set on the radio peripheral to get requested output power.
*
* This function calculates power value for RADIO peripheral register and
* sets front-end module gain value.
* sets front-end module Tx power control value.
*
* @note If the exact value of @p power cannot be achieved, this function attempts to use less
* power to not exceed the limits.
Expand Down Expand Up @@ -204,11 +210,11 @@ static inline int8_t fem_tx_output_power_max_get(uint16_t freq_mhz)
return fem_tx_output_power_check(INT8_MAX, freq_mhz, true);
}

/**@brief Get the front-end module default Tx gain.
/**@brief Get the front-end module default Tx output power.
*
* @return The front-end module default Tx gain value.
* @return The front-end module default Tx output power value.
*/
uint32_t fem_default_tx_gain_get(void);
int8_t fem_default_tx_output_power_get(void);

/**@brief Apply the workaround for the Errata 254, 255, 256, 257 when appropriate.
*
Expand Down
35 changes: 12 additions & 23 deletions lib/fem_al/fem_al.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,37 +198,26 @@ int fem_rx_configure(uint32_t ramp_up_time)
return 0;
}

int fem_tx_gain_set(uint32_t gain)
int fem_tx_power_control_set(fem_tx_power_control tx_power_control)
{
int32_t err;
mpsl_fem_gain_t fem_gain = { 0 };
mpsl_fem_pa_power_control_t fem_pa_power_control = { 0 };

/* Fallback to FEM specific function. It can be used for checking the valid output power
* range.
*/
if (fem_api->tx_gain_validate) {
err = fem_api->tx_gain_validate(gain);
if (fem_api->tx_power_control_validate) {
err = fem_api->tx_power_control_validate(tx_power_control);
if (err) {
return err;
}
}

if (!fem_api->tx_default_gain_get) {
/* Should not happen. */
__ASSERT(false, "Missing FEM specific function for getting default Tx gain");
return -EFAULT;
}

/* We need to pass valid gain db value for given front-end module to have possibility to set
* gain value directly in arbitrary value defined in your front-end module
* product specification. In this case the default Tx gain value will be used.
*/
fem_gain.gain_db = fem_api->tx_default_gain_get();
fem_gain.private_setting = gain;
fem_pa_power_control.private_setting = tx_power_control;

err = mpsl_fem_pa_gain_set(&fem_gain);
err = mpsl_fem_pa_power_control_set(&fem_pa_power_control);
if (err) {
printk("Failed to set front-end module gain (err %d)\n", err);
printk("Failed to set front-end module Tx power control (err %d)\n", err);
return -EINVAL;
}

Expand Down Expand Up @@ -268,10 +257,10 @@ int8_t fem_tx_output_power_prepare(int8_t power, int8_t *radio_tx_power, uint16_

*radio_tx_power = power_split.radio_tx_power;

err = mpsl_fem_pa_gain_set(&power_split.fem);
err = mpsl_fem_pa_power_control_set(&power_split.fem);
if (err) {
/* Should not happen */
printk("Failed to set front-end module gain (err %d)\n", err);
printk("Failed to set front-end module Tx power control (err %d)\n", err);
__ASSERT_NO_MSG(false);
}

Expand All @@ -285,10 +274,10 @@ int8_t fem_tx_output_power_check(int8_t power, uint16_t freq_mhz, bool tx_power_
return mpsl_fem_tx_power_split(power, &power_split, freq_mhz, tx_power_ceiling);
}

uint32_t fem_default_tx_gain_get(void)
int8_t fem_default_tx_output_power_get(void)
{
if (fem_api->tx_default_gain_get) {
return fem_api->tx_default_gain_get();
if (fem_api->default_tx_output_power_get) {
return fem_api->default_tx_output_power_get();
}

return 0;
Expand Down
4 changes: 2 additions & 2 deletions lib/fem_al/fem_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ extern "C" {
struct fem_interface_api {
int (*power_up)(void);
int (*power_down)(void);
int (*tx_gain_validate)(uint32_t gain);
uint32_t (*tx_default_gain_get)(void);
int (*tx_power_control_validate)(fem_tx_power_control tx_power_control);
int8_t (*default_tx_output_power_get)(void);
uint32_t (*default_active_delay_calculate)(bool rx, nrf_radio_mode_t mode);
int (*antenna_select)(enum fem_antenna ant);
};
Expand Down
4 changes: 2 additions & 2 deletions lib/fem_al/generic_fem.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ static int generic_fem_power_down(void)
return err;
}

static uint32_t tx_default_gain_get(void)
static int8_t default_tx_output_power_get(void)
{
return DT_PROP(DT_NODELABEL(nrf_radio_fem), tx_gain_db);
}
Expand Down Expand Up @@ -188,7 +188,7 @@ static const struct fem_interface_api generic_fem_api = {
.power_up = generic_fem_power_up,
.power_down = generic_fem_power_down,
.antenna_select = generic_fem_antenna_select,
.tx_default_gain_get = tx_default_gain_get,
.default_tx_output_power_get = default_tx_output_power_get,
};

static int generic_fem_setup(void)
Expand Down
12 changes: 6 additions & 6 deletions lib/fem_al/nrf21540.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,16 @@ static int nrf21540_init(void)
return 0;
}

static int tx_gain_validate(uint32_t gain)
static int tx_power_control_validate(fem_tx_power_control tx_power_control)
{
if (IS_ENABLED(CONFIG_MPSL_FEM_NRF21540_GPIO_SPI)) {
return (gain > NRF21540_TX_GAIN_MAX) ? -EINVAL : 0;
return (tx_power_control > NRF21540_TX_GAIN_MAX) ? -EINVAL : 0;
} else {
return ((gain == 0) || (gain == 1)) ? 0 : -EINVAL;
return ((tx_power_control == 0) || (tx_power_control == 1)) ? 0 : -EINVAL;
}
}

static uint32_t tx_default_gain_get(void)
static int8_t default_tx_output_power_get(void)
{
return CONFIG_MPSL_FEM_NRF21540_TX_GAIN_DB;
}
Expand Down Expand Up @@ -108,8 +108,8 @@ static int nrf21540_antenna_select(enum fem_antenna ant)
#endif /* DT_NODE_HAS_PROP(NRF21540_NODE, ant_sel_gpios) */

static const struct fem_interface_api nrf21540_api = {
.tx_gain_validate = tx_gain_validate,
.tx_default_gain_get = tx_default_gain_get,
.tx_power_control_validate = tx_power_control_validate,
.default_tx_output_power_get = default_tx_output_power_get,
.antenna_select = nrf21540_antenna_select
};

Expand Down
9 changes: 5 additions & 4 deletions samples/bluetooth/direct_test_mode/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ The behavior of the commands vary depending on the hardware configuration and Kc
Additionally, you can use following vendor-specific commands:

* The ``SET_TX_POWER`` command sets the SoC TX output power.
* The ``FEM_GAIN_SET`` command sets the front-end module gain.
* The ``FEM_TX_POWER_CONTROL_SET`` command sets the front-end module gain.

Bluetooth Direction Finding support
===================================
Expand Down Expand Up @@ -289,9 +289,10 @@ Vendor-specific commands can be divided into different categories as follows:
* ``0`` - ANT1 enabled, ANT2 disabled
* ``1`` - ANT1 disabled, ANT2 enabled

* If the **Length** field is set to ``4`` (symbol ``FEM_GAIN_SET``), the **Frequency** field sets the front-end module (FEM) TX gain value in arbitrary units.
* If the **Length** field is set to ``4`` (symbol ``FEM_TX_POWER_CONTROL_SET``), the **Frequency** field sets the front-end module (FEM) TX power control value and is specific to the FEM type in use.
The valid gain values are specified in your product-specific front-end module (FEM).
For example, in the nRF21540 front-end module, the gain range is 0 - 31.
For example, in the nRF21540 front-end module with GPIO interface, the tx power control range is 0 (POUTA) to 1 (POUTB).
For example, in the nRF21540 front-end module with GPIO?SPI, the tx power control range is 0 - 31 and is the value of TX_GAIN field of CONFREG0 register.
* If the **Length** field is set to ``5`` (symbol ``FEM_ACTIVE_DELAY_SET``), the **Frequency** field sets the front-end module (FEM) activation delay in microseconds relative to the radio start.
By default, this value is set to ``radio ramp-up time - front-end module (FEM) TX/RX settling time``.
* If the **Length** field is set to ``6`` (symbol ``FEM_DEFAULT_PARAMS_SET``) and the **Frequency** field to any value, the front-end module parameters, such as ``antenna output``, ``gain``, and ``delay``, are set to their default values.
Expand All @@ -309,7 +310,7 @@ Vendor-specific commands can be divided into different categories as follows:
When you build the DTM sample with support for front-end modules and the :ref:`CONFIG_DTM_POWER_CONTROL_AUTOMATIC <CONFIG_DTM_POWER_CONTROL_AUTOMATIC>` Kconfig option is enabled, the following vendor-specific command are not available:

* ``SET_TX_POWER``
* ``FEM_GAIN_SET``
* ``FEM_TX_POWER_CONTROL_SET``

You can disable the :ref:`CONFIG_DTM_POWER_CONTROL_AUTOMATIC <CONFIG_DTM_POWER_CONTROL_AUTOMATIC>` Kconfig option if you want to set the SoC output power and the front-end module gain by separate commands.
The official DTM command ``0x09`` for setting power level takes into account the SoC output power and the front-end module gain to set the total requested output power.
Expand Down
34 changes: 20 additions & 14 deletions samples/bluetooth/direct_test_mode/src/dtm.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ BUILD_ASSERT(NRFX_TIMER_CONFIG_LABEL(ANOMALY_172_TIMER_INSTANCE) == 1,
/* Maximum number of valid channels in BLE. */
#define PHYS_CH_MAX 39

#define FEM_USE_DEFAULT_GAIN 0xFF
#define FEM_USE_DEFAULT_TX_POWER_CONTROL 0xFF

/* Minimum supported CTE length in 8 us units. */
#define CTE_LENGTH_MIN 0x02
Expand Down Expand Up @@ -273,8 +273,8 @@ enum dtm_vs_subcmd {
/* Switch front-end module (FEM) antenna. */
FEM_ANTENNA_SELECT = 3,

/* Set front-end module (FEM) gain value. */
FEM_GAIN_SET = 4,
/* Set front-end module (FEM) tx power control value. */
FEM_TX_POWER_CONTROL_SET = 4,

/* Set FEM ramp-up time. */
FEM_RAMP_UP_SET = 5,
Expand Down Expand Up @@ -318,19 +318,21 @@ struct dtm_cte_info {
dtm_iq_report_callback_t iq_rep_cb;
};

#if CONFIG_FEM
struct fem_parameters {
/* Front-end module ramp-up time in microseconds. */
uint32_t ramp_up_time;

/* Front-end module vendor ramp-up time in microseconds. */
uint32_t vendor_ramp_up_time;

/* Front-end module Tx gain in unit specific for used FEM.
/* Front-end module Tx power control specific for used FEM.
* For nRF21540 GPIO/SPI, this is a register value.
* For nRF21540 GPIO, this is MODE pin value.
*/
uint32_t gain;
fem_tx_power_control tx_power_control;
};
#endif /* CONFIG_FEM */

/* DTM instance definition */
static struct dtm_instance {
Expand Down Expand Up @@ -384,8 +386,10 @@ static struct dtm_instance {
/* Constant Tone Extension configuration. */
struct dtm_cte_info cte_info;

#if CONFIG_FEM
/* Front-end module (FEM) parameters. */
struct fem_parameters fem;
#endif

/* Radio Enable PPI channel. */
uint8_t ppi_radio_start;
Expand All @@ -399,7 +403,9 @@ static struct dtm_instance {
#endif /* NRF52_ERRATA_172_PRESENT */
.radio_mode = NRF_RADIO_MODE_BLE_1MBIT,
.txpower = NRF_RADIO_TXPOWER_0DBM,
.fem.gain = FEM_USE_DEFAULT_GAIN,
#if CONFIG_FEM
.fem.tx_power_control = FEM_USE_DEFAULT_TX_POWER_CONTROL,
#endif
};

/* The PRBS9 sequence used as packet payload.
Expand Down Expand Up @@ -927,7 +933,7 @@ int dtm_init(dtm_iq_report_callback_t callback)
/* When front-end module is used, set output power to the front-end module
* default gain.
*/
dtm_inst.txpower = fem_default_tx_gain_get();
dtm_inst.txpower = fem_default_tx_output_power_get();
#endif /* CONFIG_DTM_POWER_CONTROL_AUTOMATIC */

/** Connect radio interrupts. */
Expand Down Expand Up @@ -1455,9 +1461,9 @@ static int dtm_vendor_specific_pkt(uint32_t vendor_cmd, uint32_t vendor_option)
NRF_RADIO_SHORT_READY_START_MASK);

#if CONFIG_FEM
if ((dtm_inst.fem.gain != FEM_USE_DEFAULT_GAIN) &&
if ((dtm_inst.fem.tx_power_control != FEM_USE_DEFAULT_TX_POWER_CONTROL) &&
(!IS_ENABLED(CONFIG_DTM_POWER_CONTROL_AUTOMATIC))) {
if (fem_tx_gain_set(dtm_inst.fem.gain) != 0) {
if (fem_tx_power_control_set(dtm_inst.fem.tx_power_control) != 0) {
return -EINVAL;
}
}
Expand Down Expand Up @@ -1489,8 +1495,8 @@ static int dtm_vendor_specific_pkt(uint32_t vendor_cmd, uint32_t vendor_option)
break;

#if !CONFIG_DTM_POWER_CONTROL_AUTOMATIC
case FEM_GAIN_SET:
dtm_inst.fem.gain = vendor_option;
case FEM_TX_POWER_CONTROL_SET:
dtm_inst.fem.tx_power_control = vendor_option;

break;
#endif /* !CONFIG_DTM_POWER_CONTROL_AUTOMATIC */
Expand All @@ -1501,7 +1507,7 @@ static int dtm_vendor_specific_pkt(uint32_t vendor_cmd, uint32_t vendor_option)
break;

case FEM_DEFAULT_PARAMS_SET:
dtm_inst.fem.gain = FEM_USE_DEFAULT_GAIN;
dtm_inst.fem.tx_power_control = FEM_USE_DEFAULT_TX_POWER_CONTROL;
dtm_inst.fem.vendor_ramp_up_time = 0;

if (fem_antenna_select(FEM_ANTENNA_1) != 0) {
Expand Down Expand Up @@ -2082,9 +2088,9 @@ int dtm_test_transmit(uint8_t channel, uint8_t length, enum dtm_packet pkt)
NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);

#if CONFIG_FEM
if ((dtm_inst.fem.gain != FEM_USE_DEFAULT_GAIN) &&
if ((dtm_inst.fem.tx_power_control != FEM_USE_DEFAULT_TX_POWER_CONTROL) &&
(!IS_ENABLED(CONFIG_DTM_POWER_CONTROL_AUTOMATIC))) {
if (fem_tx_gain_set(dtm_inst.fem.gain) != 0) {
if (fem_tx_power_control_set(dtm_inst.fem.tx_power_control) != 0) {
return -EINVAL;
}
}
Expand Down
6 changes: 3 additions & 3 deletions samples/peripheral/radio_test/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ nRF21540 front-end module

.. include:: /includes/sample_dtm_radio_test_fem.txt

You can configure the nRF21540 front-end module (FEM) transmitted power gain, antenna output and activation delay using the main shell commands of the :ref:`radio_test_ui`.
You can configure the nRF21540 front-end module (FEM) transmitted power control, antenna output and activation delay using the main shell commands of the :ref:`radio_test_ui`.

Skyworks front-end module
=========================
Expand Down Expand Up @@ -152,13 +152,13 @@ The behavior of the commands vary depending on the hardware configuration and Kc

* The ``output_power`` command sets the total output power, including front-end module gain.
* The ``total_output_power`` command sets the total output power, including front-end module gain with a value in dBm unit provided by user.
* For these commands, the radio peripheral and FEM gain is calculated and set automatically to meet your requirements.
* For these commands, the radio peripheral and FEM transmit power control is calculated and set automatically to meet your requirements.
* If an exact output power value cannot be set, a lower value is used.

* Radio Test with front-end module support and manual Tx output power control (the :kconfig:option:`CONFIG_RADIO_TEST_POWER_CONTROL_AUTOMATIC` Kconfig option is disabled):

* The ``output_power`` command sets the SoC output command with a subcommands set.
* The ``fem`` command with the ``tx_gain`` subcommand sets the front-end module gain to an arbitrary value for given front-end module.
* The ``fem`` command with the ``tx_power_control`` subcommand sets the front-end module transmit power control to a value for given specific front-end module.
* You can use this configuration to perform tests on your hardware design.

Building and running
Expand Down
Loading
Loading