Home (/s/)
Forums (/s/topiccatalog)
Projects (/s/projects)
Technical Blog (/s/all-blogs)
Community Guidelines (/s/about
Knowledge Article
PROPRIETARY
(/S/TOPIC/0TO1M000000QHAKW…
Simple wireless temperature sensor application on EFR32 with RAIL
FOLLOW
Share This Topic
This tutorial builds on basic RAIL knowledge and does not detail all its APIs in depth. For a better understanding,
please go through the RAIL tutorials if you haven't already. Introduction
Jul 9, 2021 Knowledge
DETAILS
This tutorial builds on basic RAIL knowledge and does not detail all its APIs in depth. For a better
understanding, please go through the RAIL tutorials if you haven't already.
Introduction
This project combines the MCU-based examples with the RAIL examples using one, or preferably two wireless starter
kits. The purpose of this tutorial is to show how to include various peripheral drivers into a RAIL example project. It
utilizes the basic capabilities of the RAIL while taking advantage of the built-in peripherals on the WSTKs as well, such
as the LCD screen (through SPI), the digital temperature and relative humidity sensor (via I2C) and basic GPIO
features, such as flashing LEDs and using interrupts for the buttons.
Specification
The specification of our application is relatively simple:
Make the application reusable, run the same code on all WSTKs.
The user should be able to switch between transmit and receive mode with a push of a button.
Receive mode should be default. In this mode, receive the packet and update the screen based on the packet’s
contents.
If transmit mode is selected, read data from the thermometer and send it out in a packet.
First steps and hardware configuration
Setting up the radio configuration and the RAIL from scratch is not recommended, as it is time consuming and by using
an example project we can make sure to get everything right for the first try. Let’s start our project with a RAIL
example project instead. For our case the “RAIL: Simple TRX” example seems ideal: transmit and receive already work
in this project all we should do is to add the graphics and sensor functionality and include the sensor data in the
packet.
AppBuilder setup
After creating the project, the App Builder opens. First thing we should do is to choose a radio profile. Custom profiles
can also be configured; however, a base profile is a sure bet. In this example we’re using a Mighty Gecko 868 MHz
board, therefore one of the 868 MHz profiles are chosen. Choose any of the base profiles supported by your board.
F
il (1) (/s/relatedlist/ka01M000000gG8NQA
e
s
rail_temp.c
Jul 9, 2021 • 9KB • c
View All
(/s/relatedlist/ka01M000000gG8NQAU/AttachedContentDocum
RELATED ARTICLES
How to Create Simple Applications for TX
Performance Testing using RAIL (/s/article/how-
1.93K
How to Set Up a RAIL Test Example Project to Cope
with Custom Hardware (/s/article/how-to-set-up-
2.61K
to-create-simple-applications-for-tx-perfor‐
mance-testing-using-rail)
a-rail-test-example-project-to-cope-with-cus‐
tom-hardware)
Setting up OOK modulation in RAIL using EFR32
(/s/article/setting-up-ook-modulation-in-rail-us‐ 1.68K
ing-efr32)
WGM160P Certification Testing (using an example
application provided in Gecko OS
(/s/article/wgm160p-certification-testing-using- 1.24K
an-example-application-provided-in-gecko-os)
Setting up Serial Output Using Hardware
Configurator (/s/article/setting-up-serial-output-
using-hardware-configurator)
Configuring the radio in the App Builder
The last step before generating the code is to disable some of the macros turned on by default in this example. Make
sure the only macro enabled on the “Other” tab is the “HAL_MICRO” as we won’t need the VCOM retarget or any other
debug functions in this project.
7.9K
TRENDING ARTICLES
Downloading CP210x drivers from Windows Update
(/s/article/downloading-cp210x-drivers-fromwindows-update)
Legacy OS Software and Driver Packages
(/s/article/legacy-os-software-and-driverpackages)
What is the serial enumeration driver and why would I need
it?
Home (/s/)
Forums (/s/topiccatalog)
Projects (/s/projects)
(/s/article/what-is-the-serial-enumerationCommunity Guidelines (/s/about
driver-and-why-would-i-need-it-x)
Technical Blog (/s/all-blogs)
Latest CP210x Drivers
(/s/article/latest-cp210x-drivers)
What's the role of CC pin in Type-C solution
(/s/article/what-s-the-role-of-cc-pin-in-typec-solution)
Configuring the macros
Press “Generate” to create the basic TRX application using RAIL.
Configuring DefaultMode Peripherals
This project is now set up to be used for RAIL, however the LCD and sensor drivers are not included yet. First, we will
have to enable these peripherals ­– and disable anything unnecessary for the project – in the Hardware Configurator.
Make sure to enable the following:
I2C Sensor (also enables I2C0)
SPI Display (also enables USART1)
We won’t need:
Serial
Virtual COM port
USART0 (can only be disabled after the first two)
Also delete the retargetserial.c file from the hal-efr32 folder as we won’t need this source anymore since we don't
want to retarget the serial port in this example.
Including necessary drivers
DefaultMode peripherals
To use the two extra drivers, we will need to also include them and a few other dependencies to our project's include
paths.
Home (/s/)
Forums (/s/topiccatalog)
Add the extra includes here
Add the following lines to the include paths:
"${StudioSdkPath}/platform/middleware/glib/dmd"
"${StudioSdkPath}/platform/middleware/glib/glib"
And copy the following folders/files to your project.
From ${StudioSdkPath}\hardware\kit\common\drivers
To [project folder]\spidisplay\
display.c
displayls013b7dh03.c
displaypalemlib.c
retargettextdisplay.c
textdisplay.c
To [project folder]\sensor\
si7013.c
From ${StudioSdkPath}\hardware\kit\[your kit's folder]\config
To [project folder]\hal-config\
retargettextdisplayconfig.h
textdisplayconfig.h
If you did everything right, the project source tree should look something like this:
Projects (/s/projects)
Technical Blog (/s/all-blogs)
Community Guidelines (/s/about
List of sources included in the project
At this point the code won’t compile however,
some macros
still(/s/topiccatalog)
need to be enabled. AddProjects
TEXTDISPLAY_FONT_8x8=1
Homeas(/s/)
Forums
(/s/projects)
Technical Blog (/s/all-blogs)
and INCLUDE_TEXTDISPLAY_SUPPORT=1 to your Symbols under the Project properties. These two defines will let our
project know that we have a screen in our design which supports text display, and we need the font size to be 8x8
pixel big.
Configuring the macros in the project properties
Also, there’re two macros still undefined (as they are not defined for this board in the retargettextdisplayconfig.h).
Modify your copy of this header file, so it’s base content will look like below. If your retargeted text display
configuration file has these lines, you're good to go.
/* Display number to retarget stdout to. */
#define RETARGETTEXTDISPLAY_DISPLAY_NO
(0)
// ADDED MANUALLY
#define RETARGETTEXTDISPLAY_SCROLL_MODE (0)
#define RETARGETTEXTDISPLAY_LINE_FEED_MODE (0)
With this modification the project should compile and you should have all the necessary drivers included in it. There’s
only one setting left to change and we can start writing the main functionality. We will use printf to write lines of data
to the LCD which data will also contain floating point numbers (temperature, humidity). To be able to do that, make
sure “Printf float” is enabled under the General Linker settings.
Enable printf float so the floating-point numbers will be supported by printf
Driver initialization
RAIL and radio setup
As our initial design is already set up for transmit and receive, all the necessary RAIL configuration is done. However,
as it is recommended in the RAIL tutorial: Calibrations (/s/article/rail-tutorial-calibrations), in this example the
calibrations are also enabled. The other modification to the RAIL setup is handling the RAIL_EVENT_TX_COMPLETION
event. This event combines all transmit related events – even the errors –, therefore this way we have a better
opportunity to handle them. In the example code provided, all RAIL and radio related calls are grouped together into
the radioInit() function provided by the original RAIL TRX example.
Initializing the LCD
With the drivers set up, we can retarget the printf function to the screen on the starter kit. This way we have an easy
and convenient way to write lines of text on the screen, without having an in-depth knowledge of the graphics drivers.
To initialize and retarget the screen, we need the following few lines:
Community Guidelines (/s/about
// Initialize the display module
Home (/s/)
DISPLAY_Init();
// Retarget stdio to a text display
Forums (/s/topiccatalog)
Projects (/s/projects)
if (RETARGET_TextDisplayInit() != TEXTDISPLAY_EMSTATUS_OK) {
while (1)
;
}
You can find out more of the graphical driver and using the LCD screen in the emlcd and textdisplay MCU examples for
the EFM32PG kit.
Setting up the sensor
The sensor uses I²C to send the measured data. To use the sensor, we will need to initialize the I²C peripheral and
enable the sensor itself through its enable pin. The I²C driver has a predefined structure for use with the sensor and
the configuration files of our board should contain all the necessary locations for the data and enable pins. Do the
following to setup the sensor:
// i2c init
I2CSPM_Init_TypeDef i2cInit = I2CSPM_INIT_SENSOR;
I2CSPM_Init(&i2cInit);
// Enable Si7021 sensor isolation switch
GPIO_PinModeSet(BSP_I2CSENSOR_ENABLE_PORT, BSP_I2CSENSOR_ENABLE_PIN, gpioModePushPull, 1);
Please refer to the humitemp and inttemp MCU examples for the EFM32PG kit to learn more about using the sensor.
GPIO Callback for the buttons
The callback is already written in the Simple TRX example, the only thing we will have to do is to modify it a little. The
functionality we should have is to toggle the RX and TX whenever a button is pressed.
RAIL Callback
As it was discussed in the RAIL tutorials, the way of using the RAIL is through the event handler. We can configure all
kind of events and catch them in the main callback function of the RAIL. The calibration event was enabled earlier, the
callback function should be modified accordingly as well. It’s not the only thing we need to modify here however. Since
the simple TRX example doesn’t need the packet it receives, as default it just drops it. We would like to keep the
packet and hold it for future use by calling RAIL_HoldRxPacket() after RX completion. We also would like to write a
confirmation message on the screen if the packet was sent successfully and set a packet pending flag false after –
any kind of – transmit completion. This flag will be necessary to monitor the scheduled (delayed) transmit and its
completion.
void RAILCb_Generic(RAIL_Handle_t railHandle, RAIL_Events_t events) {
(void) railHandle;
if (events & RAIL_EVENT_CAL_NEEDED) {
// Calibrate if necessary
RAIL_Calibrate(railHandle, NULL, RAIL_CAL_ALL_PENDING);
}
if (events & RAIL_EVENTS_RX_COMPLETION) {
// Toggle RX LED and hold the packet if something was received
BSP_LedToggle(LED_RX);
packetRx = true;
if ((events & RAIL_EVENT_RX_PACKET_RECEIVED)
&& packetHandle == RAIL_RX_PACKET_HANDLE_INVALID) {
packetHandle = RAIL_HoldRxPacket(railHandle);
}
}
if (events & RAIL_EVENT_TX_PACKET_SENT) {
// Toggle TX LED and print sent message on successful packet sent event
BSP_LedToggle(LED_TX);
}
if (events & RAIL_EVENTS_TX_COMPLETION) {
// Clear the pending flag if TX is complete (even if it was a failure)
txPacketPending = false;
}
}
Handling transmit and receive in the main loop
Inits are done, Callbacks were written, it’s time to create the main functionality of the example!
Processing the received packet
In the main endless loop, the first thing we should do is to check if any packet was received. The easiest way to do
that is to check the RAIL_RX_PACKET_HANDLE_INVALID flag. If it’s valid, there’s a packet in the FIFO. All we should do
is to copy this packet, process its contents and write them on the screen. After this, we should release the packet
making space for the next one.
Technical Blog (/s/all-blogs)
Community Guidelines (/s/about
// If anything was received, process the data and push it to the screen
Home (/s/)
Forums (/s/topiccatalog)
if (packetHandle != RAIL_RX_PACKET_HANDLE_INVALID) {
RAIL_RxPacketInfo_t packetInfo;
Projects (/s/projects)
RAIL_GetRxPacketInfo(railHandle, packetHandle, &packetInfo);
RAIL_CopyRxPacket(receiveUnion.raw, &packetInfo);
// Copy the held packet using its packet info
RAIL_ReleaseRxPacket(railHandle, packetHandle);
// Release the packet once it was copied
packetHandle = RAIL_RX_PACKET_HANDLE_INVALID;
printf("\f\n\n\n Msg. received!\n\n\n");
printf(" Msg. nr.: %lu", receiveUnion.data.messageNr);
printf("\n\n\n Temp: %.3f C", receiveUnion.data.temperature);
printf("\n\n Hum: %.3f P", receiveUnion.data.humidity);
}
Transmit mode
In transmit mode a new packet is being scheduled and sent. The temperature and humidity data can be read through
the Si7013_MeasureRHAndTemp function. A division by thousand is necessary to get the actual values. After
combining the packet to send, we should set the FIFO up and start the scheduled transmit. The delay in general is
recommended to give the LCD time to refresh. A 0.5 - 1 second delay also helps the readability of the display. This is
the point where we should also set the txPacketPending flag – if scheduling the transmit didn't result in an error –, as
we wouldn’t want to send another packet while the previous one is pending, nor do we want to start receiving until the
last transfer is not complete. At this point the application waits until the packet is pending, and only after the transmit
is complete it writes "Message sent" on the screen along with the appropriate message number.
if (packetTx) {
uint32_t tempHum;
int32_t tempTemp;
Si7013_MeasureRHAndTemp(i2cInit.port, SI7021_ADDR, &tempHum, &tempTemp);
sendUnion.data.humidity = (float) tempHum / 1000;
// We get the humidity in millipercent
sendUnion.data.temperature = (float) tempTemp / 1000;
// We get the temperature in millicelsius
sendUnion.data.messageNr++;
RAIL_Idle(railHandle, RAIL_IDLE, true);
uint16_t dataLength = sizeof(sendUnion.raw);
RAIL_SetTxFifo(railHandle, &sendUnion.raw[0], dataLength, dataLength);
if (RAIL_StartScheduledTx(railHandle, channel, RAIL_TX_OPTIONS_DEFAULT,
&scheduleTxConfig, NULL) == RAIL_STATUS_NO_ERROR) {
// Start a scheduled (delayed) transmit with the custom parameters set before
txPacketPending = true;
// Mark the packet to be pending with this flag if there were no errors
} else {
printf("\f\n\n\n Send ERROR!\n\n\n");
}
// Wait until the packet is sent
while (txPacketPending) {
;
}
printf("\f\n\n\n Msg. sent!\n\n\n");
printf(" Msg. nr.: %lu", sendUnion.data.messageNr);
}
Receive mode
The receive part of the main while loop will be perfect for our project as it was written for the simple TRX, no
modification is needed here.
Conclusion
This tutorial showed how to integrate drivers usually not included in RAIL example applications. However there are
plenty examples available for the EFM32 controllers, it's not always straightforward which steps are required to use
the available peripherals when you are working with an EFR SoC . We saw how simply we can modify a working RAIL
example to send and also display something variable and useful, by showing the appropriate hardware configuration,
the necessary files and initializations, and the functions to utilize the peripherals.
API introduced in this tutorial
Functions
RETARGET_TextDisplayInit()
RAILCb_Generic()
RAIL_HoldRxPacket()
RAIL_GetRxPacketInfo()
RAIL_CopyRxPacket()
RAIL_ReleaseRxPacket()
Si7013_Detect()
Si7013_MeasureRHAndTemp()
RAIL_Idle()
RAIL_SetTxFifo()
RAIL_StartScheduledTx()
TITLE
Technical Blog (/s/all-blogs)
Community Guidelines (/s/about
Simple wireless temperature sensor application on EFR32
with RAIL
Home (/s/)
Forums (/s/topiccatalog)
URL NAME
Projects (/s/projects)
Technical Blog (/s/all-blogs)
Community Guidelines (/s/about
simple-wireless-temperature-sensor-application-on-efr32with-rail
Proprietary
(/s/topic/0TO1M000000qHaKWA…
Sort by:
Latest Posts
Search this feed...
0xde4dbeef (/s/profile/0051M000007SHELQA4) (Community Member)
September 15, 2021 at 1:02 PM (/s/feed/0D51M000085c4osSAA)
Hey Silabs, the fact that every single article you post is dated Jul 9, 2021 makes it extremely hard to find out if
an article is still relevant in the first place. Your documentation is all over the place and very frustrating to use!
Like
Comment
1.03K views
Log In to Comment
(https://www.silabs.com/)
Stay Connected With Us
Plug into the latest on Silicon Labs products, including product releases and
resources, documentation updates, PCN notifications, upcoming events, and
more.
Enter Your Email
About Us (https://www.silabs.com/about-us)
Careers (https://www.silabs.com/about-us/careers)
Community (https://community.silabs.com/s/)
Contact Us (https://www.silabs.com/about-us/contact-us)
Cookies (https://www.silabs.com/about-us/legal/cookie-policy)
()
Corporate Responsibility (https://www.silabs.com/about-us/corporateresponsibility)
Investor Relations (http://investor.silabs.com/)
Press Room (http://news.silabs.com/)
Privacy and Terms (https://www.silabs.com/about-us/legal)
Site Feedback (mailto:feedback@silabs.com)
()
(https://www.silabs.com/facebook)
(https://www.silabs.com/linkedin)
(https://www.instagram.com/siliconlabs/)
(https://twitter.com/siliconlabs)
Copyright © 2025 Silicon Laboratories. All rights reserved.
(https://www.youtube.com/user/ViralSilabs)
(https://www.silabs.com/about(http://i.youku.com/u/UMzQ2MzEwMzU2)
(http://weibo.com/siliconlabs)
us/wechat)