Driving FEMs usually require some logic signals, which can be driven from software, but generally that's not fast enough (e.g. for CSMA/CA): It needs some hardware based signals.

Since EFR32 is an integrated radio MCU, this is not handled in the radio module, but a more general purpose module: Peripheral Reflex System, or PRS for short.

EFR32s has 12 PRS channels, each of these channels can be driven by numerous signals from various sources, and even some logic operations can be done between them. These channels can be connected to PRS consumers, so it can trigger a timer start for example.

You can also wire PRS channels to some GPIOs, and this is the feature we'll use. For more information of PRS, see the reference manual.

Hardware configurator does provide an "External LNA" module, but it's not supported in RAIL (as of Flex SDK 2.0). Also, it only supports one TX/RX and one sleep pin, which is probably not enough for more complicated FEMs.

This article is stack independent, although some stacks might provide an integrated way, like the External LNA module.

The prs signals

Generally a FEM requires the following:

  • rx/tx switch
  • sleep
  • rx/tx bypass

The bypass signals are usually either compile time or application time settings, so they can be driven like any other GPIO from software, or exactly the same as sleep and rx/tx, therefore it's not part of this article.

The following PRS signals are useful for driving a FEM:

  • RAC_ACTIVE active high when radio is on (either RX or TX)
  • RAC_LNAEN active high when LNA is needed
  • RAC_PAEN active high when PA is needed

Note that all signals can be inverted

RAC_ACTIVE can be used to drive the sleep pin, but using (RAC_LNAEN or RAC_PAEN) is more energy efficient.

GPIOs usable for PRS

See the Alternate Functionality Pinout chapter or device pinout table in the datasheet. PRS channel pins has PRS_CHx functionality on it.

The hardware configurator can be also used as a dynamic pinout diagram in Simplicity Studio (in all Flex SDK examples)

Keep in mind that you need independent PRS channels for each signal, you can't configure a PRS channel to two locations.
Also, logical operations limited to channels next to each other:

  • OR operation is only supported between a channel and a previous one  (i.e. channel1 = channel0 OR channel1).
  • AND operation is only supported between a channel and the next one  (i.e. channel0 = channel0 AND channel1).

This limits the usable pins, e.g. it's recommended to drive a sleep pin as (RAC_LNAEN or RAC_PAEN), which means whatever channel you plan to use for sleep, the previous one MUST be set up to either RAC_LNAEN or RAC_PAEN. However, you can set up the same signal to multiple channels, and you don't have to drive a gpio with a channel.

Configuring GPIOs in RAILTest

Generally, RAILTest is recommended to test the radio's setup and performance, so energy efficiency is not a goal here. Therefor, it would be enough to just drive pins low and high, although it's a bit simpler to use the tx/rx switch from PRS.

RAILTest only supports a few GPIOs:
PC10, PC11, PF2, PF3, PF4, PF5, PC9, PD9, PD10, PD11, PD12

A number of PRS signals are supported, unfortunately drive low/high and RAC_ACTIVE is not amongst them.

The following commands can be used

  • to drive pin high (when radio is on; 32/0 81/0 is the PRS source/signal of RAC_ACTIVE):
    • On EFR32xG1: setupDebugSignal CUSTOM_PRS 32 0
    • On everything else: setupDebugSignal CUSTOM_PRS 81 0
  • to drive pin low (CUSTOM_LIB is used internally for RAIL debugging, but on the public versions of the SDK it just drives the pin low):
    • setDebugSignal CUSTOM_LIB 0
  • to drive rx/tx pin, high on rx:
    • setDebugSignal LNAEN
  • to drive rx/tx pin, high on tx:
    • setDebugSignal PAEN
  • to turn off a pin
    • setDebugSignal OFF

E.g. to drive the LNA on the MGM12P module (sleep pin on PD10, tx/rx on PD11)

setDebugSignal PD10 LNAEN
setDebugSignal PD11 CUSTOM_PRS 81 0

Configuring GPIOs in application source

To use PRS channels, you first need to enable GPIO and PRS clock:

CMU_ClockEnable(cmuClock_PRS, true);
CMU_ClockEnable(cmuClock_GPIO, true);

Set the GPIO we use to pushpull mode:

GPIO_PinModeSet(port, pin, gpioModePushPullAlternate, 0);

Enable PRS signal:

PRS->CH[x].CTRL = PRS_signal | PRS_CH_CTRL_ASYNC;

It's recommended to use async mode, since this is needed to have a working signal even in sleep states.

Set location of the PRS signal pin:

PRS_ROUTELOCy |= PRS_ROUTELOCy_CHxLOC_LOCz

(the 12 PRS channels are divided into 3 ROUTELOC registers, so channel 0-3 is in ROUTELOC0, etc)

Enable the pin:

BUS_RegBitWrite(&PRS->ROUTEPEN, _PRS_ROUTEPEN_CHxPEN_SHIFT, 1);

E.g. to drive the LNA on the MGM12P module (sleep pin on PD10, tx/rx on PD11):

CMU_ClockEnable(cmuClock_GPIO, true);
CMU_ClockEnable(cmuClock_PRS, true);
GPIO_PinModeSet(gpioPortD, 10, gpioModePushPullAlternate, 0);
GPIO_PinModeSet(gpioPortD, 11, gpioModePushPullAlternate, 0);
PRS->CH[6].CTRL = PRS_RAC_ACTIVE | PRS_CH_CTRL_ASYNC;
PRS->CH[5].CTRL = PRS_RAC_LNAEN | PRS_CH_CTRL_ASYNC;
PRS->ROUTELOC1 |= PRS_ROUTELOC1_CH5LOC_LOC0 | PRS_ROUTELOC1_CH6LOC_LOC13;
BUS_RegBitWrite(&PRS->ROUTEPEN, _PRS_ROUTEPEN_CH6PEN_SHIFT, 1);
BUS_RegBitWrite(&PRS->ROUTEPEN, _PRS_ROUTEPEN_CH5PEN_SHIFT, 1);

Invert a signal

Inverting a signal is very simple. To create an inverted sleep signal for example (high in sleep):

PRS->CH[x].CTRL = PRS_RAC_ACTIVE | PRS_CH_CTRL_ASYNC | PRS_CH_CTRL_INV;

Logical operation between signals

As above mentioned:

  • PRS channels can be OR'ed with the previous channel (i.e. channel1 = channel0 OR channel1).
  • PRS channels can be AND'ed with the next channel (i.e. channel0 = channel0 AND channel1).

If you meet this limitation, the setup is pretty simple, just use PRS_CH_CTRL_ORPREV and PRS_CH_CTRL_ANDNEXT.

For example the energy efficient (RAC_LNAEN | RAC_PAEN) way to drive the LNA on MGM12P:
 

PRS->CH[5].CTRL = PRS_RAC_LNAEN | PRS_CH_CTRL_ASYNC;
PRS->CH[6].CTRL = PRS_RAC_PAEN | PRS_CH_CTRL_ASYNC | PRS_CH_CTRL_ORPREV;

 

  • Proprietary
  • RAIL
  • Knowledge Base Articles