If your Wi-Fi connected product is headless, then technically speaking, the obvious solution for exchanging the Wi-Fi credentials required to commission the product onto the customer’s Wi-Fi network is SoftAP.
SoftAP stands for Software Enabled Access Point. Some product manufacturers use SoftAP to create a temporary access point for the unique purpose of getting the customer’s Wi-Fi network name (SSID), security mode and password as illustrated in the following diagram:
Figure 1 Wi-Fi commissioning using SoftAP
The customer connects his smartphone to the connected product’s SoftAP, and then uses either a mobile app or web page that displays the list of Access Points available to select and enter the password.
The connected product, once it has the customer’s Wi-Fi network information (SSID, Password and Security Mode) it connects to the Access Point.
The Access Point lets the connected product join the network and gain access to the Internet.
SoftAP used to be the Wi-Fi commissioning solution of choice for early IoT devices, but the two fundamental problems listed below have made it an unreliable solution:
Once the customer’s smartphone connects to a SoftAP, it will lose Internet connection.
If the customer’s smartphone loses Internet connection, then the phone’s logic may switch to a different Access Point and thus disconnect from the product.
In order to improve the out-of-box experience, product manufacturers have turned to Bluetooth as a solution for commissioning. For the Wi-Fi connected products that already support Bluetooth for a different purpose (e.g. streaming audio or video) then Bluetooth is the go-to mechanism for Wi-Fi commissioning as illustrated in the following diagram:
Figure 2 Wi-Fi commissioning using Bluetooth
The customer installs the product manufacturer’s BLE Mobile Application and pairs with the connected product.
The mobile application displays a list of Access Points, the customer selects one of them and enters its password.
The connected product, once it has the customer’s Wi-Fi network information (SSID, Password and Security Mode) it connects to the Access Point.
The Access Point lets the connected product join the network and gain access to the Internet.
Because of how important the out-of-box experience is to a product’s success, many product manufacturers should consider going to the extremes of adding a Bluetooth chip exclusively to support the Wi-Fi commissioning of the product. Silicon Labs has BLE chips such as the EFR32MG12 that not only supports BLE but also other wireless protocols in the same chip.
Whatever your case may be, this blog shows you one simple way to use Bluetooth for Wi-Fi commissioning by covering the following topics:
BLE GATT Server Design
BLE Mobile Application
Theory of Operation
Prerequisites
It is assumed that you are familiar with Web Technologies such as HTML and JavaScript, and more important, that you are familiar with your own Wi-Fi and Bluetooth stacks regarding the following topics:
BLE Stack
Tool to create a BLE Generic Attribute Profile (GATT) database.
Callbacks to handle the BLE Characteristics Read and Write requests.
API to send Notifications to BLE clients.
Wi-Fi Stack
API to start a Wi-Fi scan
Callback to handle the Wi-Fi scan results
API to join an Access Point
API to store the Access Point’s credentials in non-volatile memory
Hardware Requirements
Any Wi-Fi chip/module (e.g. Silicon Labs WF200 module)
Any BLE chip/module (e.g. Silicon Labs EFR32MG12 chip)
Web Server to host a static web page (e.g. AWS account)
Software Requirements
BLE GATT Configurator
Google Chrome Web Browser
BLE GATT Server Design
Using your GATT Configuration tool, you need to create two BLE GATT Services:
Wi-Fi Scanner Service
This service allows a Bluetooth Client to initiate the scanning of visible Wi-Fi networks and its corresponding information such as SSID, Security Mode and Signal Strength.
Wi-Fi Configurator Service
Allows a Bluetooth Client to configure the connected product with the information necessary to connect to a Wi-FI Access Point (i.e. SSID, Security Mode and Password).
The table below shows an example of such GATT database. Notice that the UUIDs have been truncated for sake of simplicity. In reality, they should be 128-bit and it’s important you keep them documented in a table similar to this.
BLE GATT Configuration
Service
Characteristic
Name
UUID
Name
BLE Variable
UUID
Value Settings
Properties
Type
Length
Read
Write
Indicate
Wi-Fi Configurator
2b42…5ab3
State
gattdb_wifi_ cfg_state
c519…07da
user
1
Yes
Yes
Yes
SSID
gattdb_wifi_ cfg_ssid
a4a3…5da7
user
32
No
Yes
No
Password
gattdb_wifi_ cfg_password
1d4b…c315
user
16
No
Yes
No
Security
gattdb_wifi_ cfg_security
0420…278c
user
1
No
Yes
No
Wi-Fi Scanner
9b51…af7d
State
gattdb_wifi_ scan_state
cc89…81c8
user
1
Yes
Yes
Yes
AP List Part 1
gattdb_wifi_ scan_ap_list_1
d07c…d141
user
255
Yes
No
No
AP List Part 2
gattdb_wifi_ scan_ap_list_2
7e44…99d6
user
255
Yes
No
No
AP List Part 3
gattdb_wifi_ scan_ap_list_3
d3c1…b004
user
255
Yes
No
No
AP List Part 4
gattdb_wifi_ scan_ap_list_4
a2a0…7ee0
user
255
Yes
No
No
AP List Part 5
gattdb_wifi_ scan_ap_list_5
8907…2823
user
255
Yes
No
No
Table 1 BLE GATT Configuration
Characteristics
Both services have a characteristic called State that is used to communicate the state of the corresponding operation. Therefore, both characteristics support Read, Write and Notification.
Code Listing 1 Wi-Fi Scanner and Wi-Fi Configurator Service States
The rest of characteristics are meant to exchange the actual data. Notice that the results from the Wi-Fi Scanner need to be communicated in multiple characteristics because of limitations on the maximum length of a BLE Characteristic’s value (i.e. 255 bytes).
Here is an example of the value exchanged by one of such characteristics. It is in JSON format and it is sorted by signal strength such that the closest access point is displayed on top:
Code Listing 2 List of Access Points in JSON format
BLE Mobile Application
For the BLE mobile application you have the choice of creating a native BLE application to support iOS and Android as a minimum or use Web Bluetooth.
Web Bluetooth allows a web browser (e.g. Google Chrome) to see and interact directly with Bluetooth devices as illustrated in the following image:
Figure 3 Web Bluetooth
The BLE mobile application is actually a web page (i.e. HTML and JavaScript) and it's hosted in the product manufacturer's web server.
The customer opens a web browser (e.g. Google Chrome) and goes to the web server’s URL to download the web page.
The web page displays a list of nearby BLE devices and pairs with the BLE device you want to connect.
The advantages of Web Bluetooth over traditional native BLE mobile applications are:
One single web page hosted in a web server allows much easier updates.
One single web page can be used to support all mobile devices
One single web page can also be used not only to connect via Web Bluetooth but also to host in the connected device in SoftAP mode for a line of products that does not support BLE.
Developers with HTML and JavaScript skills are a lot easier to find than those with BLE Mobile App development skills for iOS and Android.
If Web Bluetooth is used instead of a traditional native BLE mobile app, then the revised block diagram for the Wi-Fi commissioning system using Web BLE would look like the following:
Figure 4 Wi-Fi commissioning using Web BLE
The BLE mobile application is actually a web page (i.e. HTML and JavaScript) and it's hosted in the product manufacturer's web server. The web page allows the user to select from a list of Wi-Fi Access Points and enter the Access Point’s password.
The customer opens a web browser (i.e. Google Chrome) and goes to the web server’s URL to download the web page. The web page displays a list of nearby BLE Devices and pairs with the device you want to connect.
The web page sends a scan request to the BLE device which in turn calls the Wi-Fi stack APIs to scan and get the results. Finally, the web page displays a list of Access Points, the customer selects one of them and enters its password.
The connected product, once it has the customer’s Wi-Fi network information (SSID, Password and Security Mode) it connects to the Access Point.
The Access Point lets the connected product join the network and gain access to the Internet.
Theory of Operation
The diagram below summarizes the way the entire system works:
Connected Product
(BLE GATT Server)
Smartphone
(BLE Client)
To initiate a Wi-Fi Scan procedure, the BLE Client sends a request to write:
BLE GATT characteristic: gattdb_wifi_scan_state
Value: WIFI_SCANNER_STATE_SCAN
The BLE GATT Server receives the request to write:
BLE GATT characteristic: gattdb_wifi_scan_state
Value: WIFI_SCANNER_STATE_SCAN
If the Wi-Fi Scanner State Machine's state is WIFI_SCANNER_STATE_IDLE then it will call the Wi-Fi API to start a scan
The Wi-Fi stack returns the scan results by calling a callback function. There, the list of access points is stored in a data structure with a global scope for general purposes
The Wi-Fi stack signals the completion of the scan procedure by calling another callback function
The embedded application prepares a multi-part JSON payload to be stored in a data structure with a global scope for BLE purposes
The embedded application sets the characteristic gattdb_wifi_scan_state to WIFI_SCANNER_STATE_SCANNED and notifies BLE clients that this characteristic has changed
The BLE client receives the notification and sends requests to read the following BLE GATT characteristics: gattdb_wifi_scan_ap_list_1
gattdb_wifi_scan_ap_list_2
gattdb_wifi_scan_ap_list_3
gattdb_wifi_scan_ap_list_4
gattdb_wifi_scan_ap_list_5
The BLE GATT server receives the requests to read the following characteristics and responds with the values: gattdb_wifi_scan_ap_list_1
gattdb_wifi_scan_ap_list_2
gattdb_wifi_scan_ap_list_3
gattdb_wifi_scan_ap_list_4
gattdb_wifi_scan_ap_list_5
The BLE client receives indication that the values of the characteristics have changed and calls the corresponding event handlers
The handler for the event characteristic value changed parses the JSON payload into a JavaScript object, merges each part into a single array of access points, sorts the array by signal strength and populates the drop-down box
The customer selects the Wi-Fi Access Point he wants to join from the web page's drop-down box and enters the password in an input box
The BLE client sends a request to write the following BLE characteristics: gattdb_wifi_cfg_ssid
gattdb_wifi_cfg_password
gattdb_wifi_cfg_security
The BLE GATT server receives the requests to write to the following characteristics: gattdb_wifi_cfg_ssid
gattdb_wifi_cfg_password
gattdb_wifi_cfg_security
The BLE GATT server updates the variables only if there is not any Wi-Fi configuration in progress
The BLE GATT server changes the state of the Wi-Fi Configuration state machine to WIFI_CFG_STATE_ONGOING and sends notification to the BLE client that this state has changed
The BLE client receives the notification and to save the Access Point credentials in non-volatile memory, it sends a request to write:
BLE GATT characteristic: gattdb_wifi_cfg_state
Value: WIFI_CFG_STATE_SAVE
The BLE GATT server receives the request to write:
BLE GATT characteristic: gattdb_wifi_cfg_state
Value: WIFI_CFG_STATE_SAVE and if not saving process in progress, it calls the API to store variables in non-volatile memory
The BLE GATT server changes the state of the Wi-Fi Configuration state machine to WIFI_CFG_STATE_SAVED and sends notification to the BLE client that this state has changed
The BLE client receives the notification and to restart the Wi-Fi interface and connect to the new Access Point, it sends a request to write:
BLE GATT characteristic: gattdb_wifi_cfg_state
Value: WIFI_CFG_STATE_JOIN
The BLE GATT server receives the request to write:
BLE GATT Characteristic: gattdb_wifi_cfg_state
Value: WIFI_CFG_STATE_JOIN and calls the Wi-Fi API to join a network
Figure 5 Flow Diagram
Source Code
To keep the blog relevant to any Wi-FI and BLE stack, the source-code-level details on how to perform the different functions outlined in the previous flow diagram have been omitted.
The following Wi-Fi and BLE APIs are better described in their corresponding documentation and are beyond the scope of this blog:
Callbacks to handle the BLE Characteristics Read and Write requests.
API to send Notifications to BLE clients.
API to start a Wi-Fi scan
Callback to handle the Wi-Fi scan results
API to join an Access Point
API to store the Access Point’s credentials in non-volatile memory
The web page that makes the actual BLE mobile application however, is provided as an attachment (web_ble.zip) and if you like this approach, feel free to modify it and use it under the terms of the Apache License.
Figure 6 Web Bluetooth Mobile Application
Security Considerations
Because of the sensitive nature of the information exchanged, you should consider using the security features of your Bluetooth stack:
Pairing
Bonding
Device Authentication
Encryption
Data Signing
Check your Bluetooth stack documentation for more information on these security features.
Hello and welcome to the inaugural article for a new blog series, Timing 201. My previous blog series, Timing 101, ran for 12 articles over a period of roughly a year and a half.
As the name suggests, I intend to discuss timing topics with a little bit more breadth and depth than might be considered “Timing 101” material. However, that does not mean I won’t cover introductory material, if and when it’s called for, especially if readers ask for it.
When More is Less
You may recall that clock buffers are typically specified in terms of additive jitter. That is because they do not have an intrinsic phase noise source such as an XO (crystal oscillator) or a PLL’s VCXO. They consist of only amplifiers and perhaps dividers. So we would generally expect an XO followed by a clock buffer to have at least somewhat increased phase noise or jitter compared to the XO alone.
All things being equal, this will be the case, except when the amplifier has sufficiently high gain to act as a limiting amplifier or LA. In these situations, the apparent measured source + LA phase noise may actually decrease. I ran in to this phenomena years ago evaluating various clock + buffer combinations. The results weren’t always making sense and it turned out at the time that some of the noise I was measuring was in fact, not really phase noise, hence the title of this case.
To see how this might happen, let’s touch on what is meant here by apparent measured phase noise.
Phasors ON
You may recall I discussed modulation spurs previously in Timing 101 #7: The Case of the Spurious Phase Noise Part II. In that article, I considered carriers with relatively small amounts of AM (Amplitude Modulation) and narrowband FM (Frequency Modulation) or equivalent PM (Phase Modulation). The general ideas comparing AM and FM/PM spurs also apply to AM and FM/PM noise.
One topic I did not touch on at that time was the phasor or phase vector representations of AM and NB FM as shown below. The carrier vector is shown as a thick red arrow and the modulation LSB (lower sideband) and USB (upper sideband) vector components are shown as thinner blue arrows. The vector sum or resultant of the modulation is the thick blue arrow. The modulating frequency is f<subscript>M and the rotating arrows indicate the change in the modulation vectors over time versus the carrier. For the figures below the overall vector sum is the geometric addition of the carrier + modulation resultant.
What’s useful about the phasor representation is that it indicates that random noise modulating the carrier can be regarded as consisting of both AM and PM components. That is, components of the noise contributing to carrier magnitude changes are the AM components. Likewise, components of the noise contributing to carrier angle changes are FM or equivalent PM components.
You may see authors emphasizing this distinction by using script L(f) or ℒ(f) to refer toPM noise or “real” phase noise and script M(f) or ℳ(f) to refer to AM noise. The first paper I know of using this notation is:
Spectral Density Analysis: Frequency Domain Specification and Measurement of Signal Stability, by Donald Halford, John H. Shoaf, and A. S. Risley, National Bureau of Standards, Boulder, CO, published in 27th Annual Symposium on Frequency Control, 12-14 June 1973, https://tf.nist.gov/general/pdf/1558.pdf
The magnitude of noise that is AM + PM will be the RSS or Root Sum Square of the individual modulation contributions. Instruments that treat these noise components the same will then “see” this RSS noise directly as phase noise. This is what is meant by apparent phase noise and it is a particular issue for Spectrum Analyzers as discussed below.
The Spectrum Analyzer in Brief
As I noted in Timing 101 #7, Spectrum Analyzers do not preserve phase information and so a low modulation AM spur appears similar to a narrow band low modulation FM spur.
Below is a block diagram for a classic swept spectrum analyzer which suggests why. It is essentially a calibrated frequency selective peak responding voltmeter. The difference in phase between the DUT (Device Under Test) and the LO (Local Oscillator) inputs at the mixer is arbitrary. The Spectrum Analyzer doesn’t “know” anything about their relative phases and AM and PM cannot be distinguished.
The Phase Noise Analyzer in Brief
By contrast, the Phase Noise Analyzer is much less susceptible to AM. The simplified block diagram below gives the basic idea behind the method typically used by Phase Noise Analyzers and Signal Source Analyzers. The mixer is usually a double-balanced mixer to suppress even-order mixing products.
Note that, unlike the Spectrum Analyzer, there is a PLL (Phase Lock Loop) that enforces a specific phase relationship between the DUT and the Reference. Further, it can be shown that AM and PM can be distinguished as follows.
If phase offset = 90˚ then the mixer detects PM and suppresses AM
If phase offset = 0˚ then the mixer detects AM and suppresses PM
As designed, the Phase Noise Analyzer will be superior to the spectrum analyzer for rejecting AM.
Take It to the Limit
So how exactly does the limiting amplifier or LA help us here? The clue lies in the behavior of the LA: It removes, or at least minimizes, amplitude variation from the clock signal. Therefore, if a source has both AM and PM noise components, then an ideal limiter will remove the AM component noise leaving only the PM noise (the genuine phase noise) behind. The exaggerated sketch below gives the basic idea.
Now getting back to the original work which prompted this post:
If a clock source had apparent phase noise that included both AM and PM noise contributions, then following it with a high gain clock buffer or LA would strip away the AM resulting in less than expected measured phase noise. Rather than yielding additive jitter the new component apparently yielded “subtractive” jitter. Thus the case of the phase noise that wasn’t.
When should AM be considered when making phase noise measurements?
The short answer is that AM is always a potential consideration when one is making careful jitter and phase noise measurements. Having a limiter on one’s lab bench is as important as a balun.
However, there are specific instances where AM can be more of an issue than others.
1. Measuring phase noise using a spectrum analyzer or any other instrument that does not sufficiently reject AM.
A limiter can be valuable even when working with a Phase Noise Analyzer by suppressing AM beyond the rejection capability of the mixer. This may be necessary when measuring very low phase noise sources.
2. Measuring low frequency low phase noise sources.
You may recall the 20log(N) rule, i.e. if the carrier frequency of a clock is divided down by a factor of N then we expect the phase noise to decrease by 20log(N); however, this rule only applies to phase noise. If there is significant AM noise also then this component will loom larger, as we decrease the carrier frequency, and potentially impact measurements.
3. Measuring a source known or suspected to have AM noise.
Clock sources with high common mode noise fall in to this category. For example, we specifically inject power supply ripple when testing oscillator power supply rejection. This is why you see a limiting amplifier shown in Figure 5. PSRR Setup in AN491: Power Supply Rejection For Low-Jitter Clocks. See the highlighted block in the diagram below which comes from that app note.
4. Troubleshooting
Finally, the ability to distinguish between phase noise and spurs, and AM noise and spurs, can be very helpful when troubleshooting a system and determining the root cause of performance issues. Additional testing may also be needed to determine how sensitive the ultimate receiver is to clock impairments that include AM noise.
Conclusion
I hope you have enjoyed this Timing 201 article. In the next article, I will give some measurement examples and offer a few rules of thumb.
As always, if you have topic suggestions for this blog or timing-related questions, please send them to kevin.smith@silabs.com with “Timing 201” in the subject line. I will give them consideration and see if I can fit them in. Thanks for reading. Keep calm and clock on.
This blog is part of the Kernel 201: Designing a Dynamic Multiprotocol Application with Micrium OS. The table of contents for this blog series can be found here.
Note:It is recommended to download the Kernel 201 WebBluetooth Application and have the code in front of you as you go through this blog post. The code can be downloaded on the Kernel 201: Project Resources page.
Introduction
WebBluetooth API is a Javascript API that provides Bluetooth support for web pages. The API, which was first published in 2015, is still considered Experimental but it has been supported in Google Chrome since version 56 and Opera since version 43 for desktop and Android devices. At the time of writing this, WebBluetooth API is still not supported on Edge, Firefox, or Safari and it does not work on iPhones at all.
The advantage of using the WebBluetooth API is it allows for a quick way to develop an application that can run on desktop or mobile from the same code. In the past if a developer wished to interact with Bluetooth on both desktop and mobile, typically separate applications were needed. The code provided on the Project Resources page runs on any web server that has HTTPS enabled, and will work on desktop and Android.
The WebBluetooth App that interacts with the Kernel 201 Application is based off of StartBootstrap’s SB Admin 2 template. The template provides the necessary css code to support small screens such as mobile devices and large screens like desktop monitors.
The code included in the WebBluetooth App has been paired back considerably from the full SB Admin template to only include the files needed. If you wish to view the entire SB Admin template, it can be found here.
There are only 3 files and one folder in the WebBluetooth App specific to the Kernel 201 Application. The rest of the files are part of Bootstrap, jQuery and SB Admin files that do not need modification.
index.html & images directory
css/bt.css
js/bt.js
index.html & images directory
The entire WebBluetooth App’s HTML code is located in this one file. The app’s display is very simplistic, just display fields and buttons for control. All of the different views for the application are already in the index.html page, the Javascript code controls the showing and hiding of different elements based on the different states of the application.
The images folder holds the different images shown in the WebBluetooth App. In the current version of the application it is used only to hold the logos as seen above.
bt.css
The bt.css file is the main css file from the SB Admin template. There have been minor changes such as color scheme, screen size and card behavior made to the file.
bt.js
This file is what controls the behavior of the WebBluetooth App. It contains the WebBluetooth API code as well as control of what elements are shown on the index.html page.
After clicking the Lab 1 button, a user is brought to the screen above. Clicking connect will trigger the function btConnect() in bt.js. This function begins making WebBluetooth API calls that will start the connection process to the Kernel 201 Application.
The Javascript Engine runs in a single thread, so when it hits a function that requires a delay or user input, instead of blocking the entire application it puts that function off until the delay or input is received and continues executing the rest of the code. In order to ensure the WebBluetooth API functions are called in order, the connect code relies on Javascript Promises. The Promises allow the connection events to happen sequentially using the then() keyword. In the example above you can see that the connect() will not occur until the requestDevice() function has finished. If the then() keyword was not used, Javascript would attempt to run connect() before the requestDevice() function completed causing an error.
When the requestDevice() function is first executed, a filter is applied. The filter is using the UUID of the Lab Control service. You may recall from the Kernel 201: Bluetooth Task blog that the Lab Control service contains all of the tasks in the lab application. By filtering on the Lab Control service, it allows the Bluetooth Connection Dialog to only show Bluetooth devices running the Kernel 201 Application as shown above.
After the connection is made, the WebBluetooth App connects to the Lab Control service and subscribes to notifications from all of the characteristics specified. The notifications allow for the Kernel 201 Application to send a status update to the WebBlueooth App as soon as it occurs, rather than having the WebBluetooth App constantly poll for changes. After its completed the notification subscriptions, the WebBluetooth App makes read requests from the Kernel 201 Application and displays the device state as shown above.
Once the display has been changed to the current state of the Kernel 201 Application, the WebBluetooth App maintains a Bluetooth connection but sit idle until one of two actions occur:
The user clicks a button
A notification is received from the Kernel 201 Application
When the user clicks an LED button, the LED write function will call the Bluetooth write function to send a write command to the Kernel 201 Application with the LED data. After the command is sent, the WebBluetooth App does not change the user interface to reflect the command just sent. The change in the user interface will come from the Kernel 201 Application sending a notification that a change has been made to the LED. This prevents the user interface from getting out of sync with the Kernel 201 Application.
When a notification is received from the Kernel 201 Application, the callback bt_cb_onnotify() fires and determines what portion of the UI needs to be updated. It then passes along the received data to the necessary functions to update the UI.
Final Thoughts
The WebBluetooth API provides a simple, quick way to create apps that run on both mobile and desktop natively. Unfortunately, since it is still experimental, there is a lack of support for it. Hopefully in the future, it will become a widely accepted way of interacting with Bluetooth devices. If you have any questions or thoughts on this feel free to leave them below.
This blog is part of the Kernel 201: Designing a Dynamic Multiprotocol Application with Micrium OS. The table of contents for this blog series can be found here.
Note:It is recommended to download the Kernel 201 application and have the code in front of you as you go through this blog post. The code can be downloaded on the Kernel 201: Project Resources page.
Note: This project has a slightly different RTOS interface with the Bluetooth stack than other example projects. The differences will be highlighted in this article.
Introduction
The goal of the Bluetooth task in the Kernel 201 Application is to communicate with a web browser running a WebBluetooth App. The WebBluetooth App is highlighted in detail in another post that can be found here.
The Bluetooth task will perform the following actions:
Start Bluetooth Advertising after the stack boots and after a disconnect
Handle read and write requests from the WebBluetooth App
Send notifications to the WebBluetooth App
Kernel 201 Bluetooth Initialization
Before starting the Bluetooth Task, configurations and initializations must be performed for the Bluetooth stack to operate correctly. Part of the configuration for the Bluetooth stack comes from the GATT editor in Simplicity Studio; the other portion of the Bluetooth configuration comes from the gecko_configuration_t structure.
To modify the Bluetooth GATT configuration, there is an application in Simplicity Studio to help configure the GATT database. In the Kernel 201 Application there is a file called kernel201.isc. Opening that file in Simplicity Studio will open the GATT Configurator where you can make changes to the GATT database.
In the GATT Configurator, a new Bluetooth Service called Lab Control has been added for the Kernel 201 Application. Any task in the application that wishes to have Bluetooth control will have a characteristic under the Lab Control service. For the Kernel 201 Application, each characteristic will support Read, Write and Notify. The characteristics are given unique UUID numbers that are hardcoded into the WebBluetooth App. If someone wishes to add a new task, modifications would also have to be made to the WebBluetooth App to support the new UUID. The code for the WebBluetooth App is available for download under the Kernel 201: Project Resources page.
By default, the Kernel 201 Application shows up as “Kernel201” for the Bluetooth Device Name. If you wish to change the Device Name to something else, this can be accomplished under the Device Name Characteristic in the GATT Configurator. The value field is where the new Device Name would be specified and the length must be adjusted. Note: For the DMP portion of this application to work correctly the Device Name must be 16 characters or less. This is a Kernel 201 Application requirement, not a Bluetooth requirement.
After all changes have been made in the GATT Configurator, the kernel201.isc file needs to be saved and then click Generate to update the GATT information. For further information on the GATT Configurator, refer to UG365: GATT Configurator Users Guide
In the lab_bluetooth.c file, there is also the gecko_configuration_t Bluetooth configuration structure that must be passed in during initialization. As shown above the structure sets internal flags, heap location and size (separate heap from Micrium OS), GATT Database, callback functions and other power and security parameters. For more information on the structure, refer to UG136: Silicon Labs Bluetooth C Application Developer’s Guide.
The Kernel 201 Application also introduces a second configuration structure that is not found in other Dynamic Multiprotocol Applications or officially supported by the Bluetooth stack.
static BLUETOOTH_RTOS_CFG_s bluetooth_rtos_cfg = // Bluetooth RTOS config
{
.ll_prio = SLAB_LINKLAYER_PRIO,
.bt_prio = SLAB_BLUETOOTH_PRIO,
.bt_callback = labBluetoothEvtCallback, // Callback to signal a Bluetooth
.gecko_config = &bluetooth_config // event to process.
};
Typically, the function bluetooth_start_task() only takes in the task priorities for the Link Layer and Bluetooth tasks. This structure adds a callback function that will be used when there is a Bluetooth event for the labBluetoothTask to process.
This change is necessary because the existing implementation of the Bluetooth Stack’s RTOS port relied on the user application to pend on an Event Flag. Since the tasks in the Kernel 201 Application pend on Task Message Queues, it was not possible to use the Bluetooth Event Flags in conjunction with the Task Message Queue. The addition of the callback function adds the flexibility for applications to use any kernel service desired for signaling rather than being forced to use an Event Flag.
Kernel 201 Bluetooth Task
The main Bluetooth task loop is structured just like all other tasks in the Kernel 201 Application (except for the watchdog task). When the task is created, the Bluetooth stack is configured and initialized and then begins waiting for messages in the Task Message Queue.
while (DEF_TRUE)
{
p_msg = OSTaskQPend( LAB_WDOG_TASK_TIMEOUT_MS, // Wait for lab message
OS_OPT_PEND_BLOCKING, // or timeout.
&lab_q_id,
0,
&err);
do {
if(err.Code == RTOS_ERR_TIMEOUT) { // If timeout, feed watchdog
break;
} else if(err.Code != RTOS_ERR_NONE) { // Assert on other errors
APP_RTOS_ASSERT_CRITICAL(err.Code == RTOS_ERR_NONE, ;);
}
switch(lab_q_id) {
case LAB_Q_ID_BLUETOOTH_EVT:
labBluetoothHandleEvt(); // Handle Bluetooth Event
break;
case LAB_Q_ID_MSG: // Handle Lab Message
labBluetoothHandleMsg((LAB_MSG_s*) p_msg);
labUtilMsgFree(p_msg); // Then free Lab Message
break;
default:
break;
}
} while(0);
labWDOGFeed(LAB_TASK_BLUETOOTH); // Feed the watchdog
}
There are two types of messages and one error code that the Bluetooth task handles:
RTOS_ERR_TIMEOUT – No events have been received in the timeout period, feed the software watchdog and pend again.
LAB_Q_ID_BLUETOOTH_EVT – Called when there is an event from the Bluetooth stack to handle.
LAB_Q_ID_MSG – Called when there is a message in the void* argument of the Task Message Queue to process.
RTOS_ERR_TIMEOUT
As part of the software watchdog, the Bluetooth task must feed the software watchdog at a specified rate. There is a define in lab.h that all tasks use called LAB_WDOG_TASK_TIMEOUT_MS. This define specifies how often every task should check-in with the software watchdog. If the Task Message Queue does not receive a message before the timeout value is hit, the pend call returns with RTOS_ERR_TIMEOUT. Since it’s a timeout the Bluetooth task knows that no message was received, it only feeds the software watchdog and then starts pending on the Task Message Queue again.
LAB_Q_ID_BLUETOOTH_EVT
When the Bluetooth stack has an event for the Kernel 201 Application to process, it makes a call to the callback function specified in the BLUETOOTH_RTOS_CFG_s structure. That function is defined as follows:
In the callback function, a message is sent to the labBluetoothTask to tell it there is a message waiting to be processed. The callback function must send a message because the callback function is executed from the internal Bluetooth Task. If the callback function was to process the Bluetooth event it would lock up the internal Bluetooth task and potentially cause the Bluetooth Stack to miss other Bluetooth events.
When the signal to process an event is received by the labBluetoothTask, the function labBluetoothHandleEvt() is called. This function first retrieves the event that must be processed, and then determines how to handle it. The chart below shows the flow of the event handler:
gecko_evt_system_boot_id and gecko_evt_le_connection_closed_id
These events are called when the Bluetooth stack has been booted, and when a Bluetooth connection has been dropped. In both cases, the Bluetooth stack must be told to start advertising again as we don’t have a connection.
gecko_evt_gatt-server_user_write_request_id
The write event is called when the WebBluetooth App is wishing to send a command to a task in the system. A common example would be using the WebBluetooth App to change the LEDs.
The Bluetooth write event that is received from the Bluetooth stack also contains data such as the task the data is to be sent to, as well as the data itself. To send the data to the specified task, a lab message buffer is allocated using the utility functions. Once a buffer has been allocated, it is configured for the task destination and then the data specific to that task is copied into the buffer. The buffer is then sent to the desired task/s.
gecko_evt_gatt-server_user_read_request_id
The read event is called only when a WebBluetooth App first connects to the Kernel 201 Application. The read is used to determine the state of all of the tasks in the system for the WebBluetooth App. After the WebBluetooth App has connected and received the task status the first time, all subsequent updates are received via a Bluetooth notification.
LAB_Q_ID_MSG
When another task in the system wishes to send data via Bluetooth, a lab message must be sent to the Bluetooth task via the Task Message Queue. In most cases, this is used when a task has completed a request and is updating the remote application. In the LED example, after the LED has been changed a message is sent to the Bluetooth task so the WebBluetooth App connected, if any, is updated.
Kernel 201 Bluetooth Example
The following diagram shows the typical flow of data when a user wishes to change the LED:
The user makes a request on the WebBluetooth App to change the LED color to red.
The WebBluetooth App sends a Bluetooth write command to the Kernel 201 Application.
The Silicon Labs internal Bluetooth stack receives the message via the radio, assemble the data and executes the labBluetoothEvtCallback() that was passed in during the Bluetooth configuration. The callback puts a LAB_Q_ID_BLUETOOTH_EVT message in the labBluetoothTask’s Task Message Queue.
The labBluetoothTask receives the LAB_Q_ID_BLUETOOTH_EVT in its Task Message Queue and handles it as follows:
Get the Bluetooth Event from the Bluetooth stack.
Determine it is a write event.
Determine it is an LED write event.
Allocate a lab message buffer, configure it for a LED message and send it to the LED task via the LED Task’s Task Message Queue.
The labLEDTask receives the LAB_Q_ID_MSG along with the lab message buffer pointer.
It proceeds to change the LED as requested.
After the change has been made, the LED task sends the same lab message content it received back to the Bluetooth task, but signals that it is an update message, not a command message.
The labBluetoothTask receives a LAB_Q_ID_MSG in its Task Message Queue.
The message is sent to the Silicon Labs internal Bluetooth stack via the Gecko characteristic notification command
The Silicon Labs internal Bluetooth stack processes the characteristic notification command and sends the data to the WebBluetooth App.
The WebBluetooth App receives the Bluetooth characteristic notification update and changes the WebBluetooth App to show the LED color has been changed to red.
Final Thoughts
The Bluetooth Task is one of two wireless tasks in the system that will send commands to the other tasks in the system and report back the status of the system. The other task is the Proprietary Wireless that is covered in Kernel 201: Proprietary Wireless Task. The Bluetooth Task has the advantage that the developer does not need to make multiple RAIL calls to configure the radio or listen for hardware interrupts because it is abstracted away by the Bluetooth Stack. The Proprietary Wireless Task does not have this luxury and will require some more in-depth knowledge of the RAIL API. If you have any questions or comments on the Bluetooth Task feel free to leave them below.
If you are running in a multi-threaded environment in which you have more than one task making use of a peripheral driver such as USART, SPI, I2C, etc., you should consider making it thread-safe.
The Micrium OS kernel offers a variety of services designed to protect shared resources. In our case, let’s make use of the Mutual Exclusion Semaphore also known as mutex. Why a mutex? Because we want our resource (peripheral driver) to be accessed only by one task at a time. Regular semaphores present a vulnerability with priority-inversion. Mutexes, on the other hand, are implemented in a way that priority inversions are prevented by using priority inheritance.
For this exercise, you will be editing files from the Gecko SDK, which is not recommended therefore do this with caution.
In the peripheral driver file that you want to protect, include the following file:
#include <kernel/include/os.h>
Now we have to declare a global variable for our mutex, for example, if you want to protect the SPI you could declare it as follows:
OS_MUTEX SPI_Mutex;
With the mutex now declared, you need to invoke the kernel call to create it. My recommendation is to make this in the initialization function of the peripheral driver that you are using. You create the mutex by calling:
OSMutexCreate(&SPI_Mutex, “SPI Mutex”, &err);
Notice how the function requires an error argument, just declare RTOS_ERR err locally and pass it on.
Always make sure to check the error returned, if it’s not RTOS_ERR_NONE then something went wrong.
The mutex is now created and registered with the kernel. Now you will need to wrap around the driver calls that your application is using with:
void foo () {
RTOS_ERR err;
OSMutexPend(&SPI_Mutex, /* Pointer to the mutex */
0, /* No timeout */
OS_OPT_PEND_BLOCKING, /* Block if not available */
DEF_NULL, /*Timestamp not used */
&err);
if (err.Code != RTOS_ERR_NONE) {
/* handle error */
}
/* peripheral driver function code */
...
...
...
OSMutexPost(&SPI_Mutex,
OS_OPT_POST_NONE,
&err);
if (err.Code != RTOS_ERR_NONE) {
/* handle error */
}
}
Please make sure to check the returned errors. A common one is RTOS_ERR_NOT_READY, this happens when the pend or post calls are made before the kernel is in its running state (after the call to OSStart()).
If the driver initialization function can potentially be called multiple times from more than one task, my recommendation is to also protect it.
With this setup, you can be sure that your peripheral is only being accessed by one task at a time.
Last month, we spoke with the co-founders of IOTAS, Sce Pike, CEO and Jeremy Steinhauer, VP of Data Services and learned how multi-family residential buildings, otherwise known as apartments, have recently stepped up their smart home game. IOTAS, which stands for IoT as a Service, has been a key player in making this happen after creating a smart home platform for apartment renters several years ago. The platform, built for residents, property owners and installers, provides residents with a seamless IoT solution that monitors apartment unit systems, including thermostats, motion detectors, security and lighting. The solution is so easy to use renters have been asking to take it with them when moving out of their apartment.
IOTAS has grown rapidly since its inception four years ago and was recently recognized by the Bay Area’s Start-up Grind as the 2019 Start-up of the Year. The company’s install base has grown to 100,000 smart devices in more than 70 communities.
Read more below about our conversation with IOTAS and how the company tapped into a major new market opportunity for smart home technologies.
How did IOTAS get started?
Sce: In 2014, a real estate developer in Portland approached me and explained he was looking for technology differentiation for his apartment property. My background is in mobile design development, and I had recently sold my first mobile consumer company, so the idea of focusing on the technology experience in the real estate market was intriguing. I quickly realized the $5 billion real estate market had the potential to scale a new technology extremely fast.
I went ahead and recruited Jeremy as my co-founder and we immediately built out a technology solution focused exclusively on apartments. We installed 40 smart home devices in a 1,000 square foot apartment unit to create a true smart home experience, not something that was cumbersome to put together. We wanted to create a move-in ready solution that just worked. We then took the idea out on a real estate conference roadshow, and it became obvious fast that we had created the next amenity commercial property owners were seeking. Property owners knew they had to provide technological advancements in their buildings to meet the demands of millennials and GenZ.
Once we received this feedback, we scaled the solution exponentially over the next few years, with our installs growing by 500 percent last year alone. We see the potential of disruption for all multi-family properties within five years, with all of them having some level of smart technology.
How did the real estate market know they needed this?
Sce: The real estate industry is 13 percent of the U.S. GDP and does a great deal of collective research. Property companies understand their own demographic very well, and at the time they were seeing technology become pervasive across their tenants’ lives, but the shift wasn’t reflected in apartment buildings. The industry saw this void as an opportunity to create an edge for their properties. Five years ago, when we first entered the market, the conferences were only starting to talk about smart home technology, but now smart apartments are mainstream, and the vast majority of properties are allocating budgets to incorporate smart home technologies.
Tell me about your product.
Jeremy: We’re focused on making the smart home experience extremely easy for residents and property managers. We work with property developers and managers to install smart devices in apartments with a suite of applications, including door locks, thermostats, light switches, power outlets and sensors to monitor leaks, motion, temperature, etc. Residents simply download the app to their phone and get a smart home out of the box. We also created automated defaults, like “out for the day” or “welcome home,” which set up preferred systems for that specific time period.
The second application is geared towards property managers to improve efficiencies – it’s the tool managers use to link the residential units and create their own automations for vacant units, such as temperature, appliances and lighting. Property managers can use it to immediately set-up for tours of certain units by turning on lights, setting the thermostat to a comfortable temperature, etc. on and off before or after. The application also has alerts for property managers if something is amiss, such as extremely high or low temperatures or humidity levels for vacant units.
The third application is the installer and/or auto-provisioning application. During our initial foray into smart apartment, we were installing 40 devices and quickly learned that commissioning that many devices to a gateway was a painful process and not scalable. We then spent the next few years perfecting the provisioning process. Now we have several auto-provisioning patents, where we have reduced the time to install devices for an installer from one hour to 15 minutes.
The final application is our internal application – how we administrate the system and create the data around the buildings and users.
Have you ever thought about going beyond multi-family homes?
Sce: From the onset, we have been focused on the multi-family market, for a variety of reasons. The economy of scale is a big reason – we didn’t want to sell one device at a time, we wanted to sell to buildings and make installations quickly. It’s much easier to design a solution for multiple homogenous units versus custom homes.
Though we have had many residents leave their apartments and ask how they can take IOTAS with them – so much so, that we’re now working on a way for residents to be able to upgrade their systems and go on a subscription basis to take IOTAS into their new home. This new solution is on our roadmap and we’re hoping to offer it by the end of this year.
How does Silicon Labs fit into your product?
Right now, we’re using the Z-Wave 500 Series Module solution and we are using the Z-Wave 700 Series for our next generation product to be rolled out later this year. We’re also considering using Zigbee in the future for wireless, so we’re using a Silicon Labs Zigbee module as we figure out a potential software stack for a Zigbee-based application. All of the end nodes are controlled by Z-Wave; we don’t have any internal connections over Wi-Fi. The Wi-Fi is purely used to connect the hub to our cloud.
Why did you decide to use the Z-Wave hub?
Jeremy: We started with Zigbee, but the standards were not there yet, as the devices weren’t all interoperable. The decision to use Z-Wave was also driven by the cost of each product. Having the ability to work with something like Z-Wave right out of the box with standardized protocols was a big selling point, as well.
Where do you IoT going in the next 5-8 years?
Jeremy: We’re extremely focused on the user experience, and we knew early on that we didn’t just want to be remote control for the home. In that same vein, I think that’s where IoT is headed – the more interconnectivity among devices, the richer the home experience can be. We see this going beyond the home, where people can take the experience with them. The smart home experience isn’t just about building profiles around people within the four walls that they live in, but taking the experience everywhere they go in the living world, such as their car, workplace, hotels, and even vacations.
This blog is part of the Kernel 201: Designing a Dynamic Multiprotocol Application with Micrium OS. The table of contents for this blog series can be found here.
Note:It is recommended to download the Kernel 201 application and have the code in front of you as you go through this blog post. The code can be downloaded on the Kernel 201: Project Resources page.
Introduction
There are different levels of safety to consider when developing a real-time system.
Safety Critical
Systems whose failure may result in death/serious injury, loss or damage to property or environmental harm.
Typically, has well defined specifications for product certification and release (e.g. DO-178, IEC 61508, IEC 62304)
Usually an expensive and time-consuming process to release a product.
Non-Safety Critical
System failures are not directly related to catastrophic events.
Minimal or no certification required for product release.
Even though a majority of products may fall under the non-safety critical system category, it doesn’t mean a safety critical design pattern shouldn’t be considered when developing a real-time system. Designing an application using safety critical components can make a product more robust and reliable.
There are two properties of a system that are commonly considered in safety critical designs:
Safety – System does not create accidents, injuries, loss of life or destruction of property.
Reliability – System runs for long periods of time without error.
These two properties are not mutually exclusive. A system that is considered safe may fail as long as it is able to recover and operate in a manner that does not cause accidents; it is just considered unreliable. On the other hand, a system that can continue to run without error but operates unsafely is a reliable, but unsafe system.
There are many software architectural patterns that a developer can use to help improve a system’s safety and reliability. While the main focus of this article is on one specific pattern (Watchdog Pattern), these are a few other patterns you may come across when researching safety critical design:
Dual Channel – Multiple channels perform the same operations and compare results
Monitor-Actuator – Separate channels for actuators performing actions and monitors keeping track of the actuator
Watchdog Pattern – Software or hardware component that requires signals from other parts of the system on a periodic basis.
Safety Executive – Centralized coordinator to monitor system safety. Typically incorporates a watchdog, build-in tests, and monitor actuator or dual channel patterns.
This article will focus on implementing a watchdog pattern using a mix of software and hardware.
Hardware Watchdog
A standard feature on EFM32 and EFR32 microcontrollers is a hardware watchdog. The hardware watchdog is a timer that when enabled, constantly counts up. The watchdog timer has a user configured timeout value that the application is responsible for “feeding” (clearing) the watchdog counter before the counter reaches that value. If the watchdog reaches the configured time value, a system reset will occur. The assumption is because the application did not feed the watchdog in time, an error has occurred in the system and it must be reset.
The hardware watchdog pattern works well for super-loop applications or in RTOS applications where only one task needs to be monitored and a system-wide reset would not negatively affect other tasks in the system. Complications arise when you wish to ensure multiple tasks are running as expected. One way to solve this problem is to implement a software watchdog that is responsible for handling the hardware watchdog.
This is a simplified overview of the hardware watchdog timer available on EFM32 and EFR32. For more detailed on the EFM32 & EFR32 watchdog timers, Series 0 can be found here and Series 1 can be found here.
Software Watchdog
A software watchdog pattern is a safety design pattern that allows for the monitoring of multiple tasks in an RTOS application. It is typically used in conjunction with a hardware watchdog, but in cases where a hardware watchdog is not available, the software watchdog can be responsible for performing the system reset.
Micrium OS Kernel provides two different kernel services that can be used to implement a software watchdog: Event Flags and Message Queues. For applications that have 32 tasks or less, an Event Flag is an ideal kernel service to use due to the Event Flag being able to monitor 32 unique bits. For applications with more than 32 tasks to be monitored, either multiple flag groups are needed or tasks can send unique values via a Message Queue to periodically check in.
In the image above, each task is represented with a unique bit in the Event Flag Group. The Event Flag is configured to pend on almost all bits of the Event Flag Group and has a timeout configured. If every task posts to the Event Flag before the timeout value is reached, the Event Flag pend returns with RTOS_ERR_NONE, the software watchdog will feed the hardware watchdog and then call pend on the Event Flag again.
If one or more tasks do not post to the Event Flag before the timeout value is reached, the Event Flag pend will return with RTOS_ERR_TIMEOUT. Also, the return value of the pend call will tell you what tasks have and have not checked in. Then with that information the software watchdog can make the decision on whether or not it should feed the hardware watchdog or let it reset the system.
Implementing a Software Watchdog in the Kernel 201 Application
The rest of this article will refer to the Kernel 201 Dynamic Multiprotocol Application. It is recommended to download the project to follow along. There are three files related to the software watchdog implementation: lab.h, lab_main.c and lab_wdog.c.
lab.h
The lab.h file is the centralized location for the application’s configuration parameters such as task priorities, stack sizes, message structures and enums. More detail on lab.h can be found in the blog Kernel 201: Task Architecture & Communication.
The defines above can be found in lab.h and are used as unique identifiers for each task in the system that will be monitored by the software watchdog. Each value will represent a bit in the Event Flag Group bitfield.
lab_main.c
When Micrium OS Kernel is initialized and started in main(), its common to only create one task before calling OSStart(). This is typically done to allow for the statistics task to get a baseline reading of the system at idle before other tasks are created.
In many sample applications the first task created is called the startup task because it is responsible for creating the rest of the tasks in the system and “starting up” the application. This is a poor naming choice for a task as after the startup task creates the other tasks in the system, some examples delete the startup task. What many do not realize is calling OSTaskDel() does not free up any resources related to the task. If the application does not know to access the startup task's stack and TCB, that memory sits unused.
It is not recommended to call OSTaskDel() on startup tasks. A better solution is to use the task for monitoring the system or repurpose the task for another task in the system.
Instead of calling it a startup task, the Kernel 201 Application calls it a system task. It could also be called the watchdog task since the software watchdog will run out of the system task. After the application has been initialized and all of the other tasks have been created, the last call in the labSystemTask function is:
labWDOGTask(); // Run the WDOG task. This call does NOT return
Rather than creating a new task for the watchdog, the application uses the system task to run the watchdog.
lab_wdog.c
The software watchdog file is very straightforward with only three functions: labWDOGInit(), labWDOGTask() and labWDOGFeed().
labWDOGInit()
The init function initializes the hardware watchdog (but does not enable it yet) and creates the Event Flag for the software watchdog.
labWDOGTask()
The software watchdog task operates as follows:
while(1) {
OSFlagPend(&labWDOGFlag, // Wait for all tasks to check in
flags,
LAB_WDOG_SYSTEM_TIMEOUT_MS,
OS_OPT_PEND_FLAG_SET_ALL +
OS_OPT_PEND_FLAG_CONSUME,
0,
&err);
if(err.Code == RTOS_ERR_NONE) { // All tasks checked on-time.
WDOG_Feed(); // Feed the hardware watchdog.
} else if(err.Code == RTOS_ERR_TIMEOUT) {
while(1); // Trigger a reset. Logic can be set
} // here to ignore tasks that did not
} // check in on time.
The watchdog pends on the specified task flags as seen in lab.h, and the pend includes a timeout. If all tasks call a flag post at least once before the timeout value is reached, the OSFlagPend() call returns with RTOS_ERR_NONE, the hardware watchdog is fed via WDOG_Feed() and it loops around and starts the pend over again.
If one or more tasks fail to check in, the return value will be RTOS_ERR_TIMEOUT. In this example the code will then sit in a while(1) until the hardware watchdog resets the system. This would be the ideal location to either add logic to see what flags did or did not check in, and also to add a flag to persistent memory so when the system does reset, it can see on boot that it reset due to an error.
labWDOGFeed()
void labWDOGFeed(CPU_INT32U task)
{
RTOS_ERR err;
OSFlagPost(&labWDOGFlag, // Set the task's flag in the WDOG flag group
task,
OS_OPT_POST_FLAG_SET,
&err);
APP_RTOS_ASSERT_CRITICAL((RTOS_ERR_CODE_GET(err) == RTOS_ERR_NONE), ;);
}
The feed function is provided so all tasks do not need to have a reference to the Watchdog Event Flag. When tasks check in they just need to provide their identifier defined in lab.h. Since a flag group bit can only be 0 or 1, it does not matter if a task checks in once or multiple times each pend cycle.
Since every task is centered around a Message Queue, the timeout parameter on the message queue is set to a value less than the watchdog flag group to ensure that each task feeds the watchdog before the watchdog timeout.
Final Thoughts
One downside to this pattern is it does not work well with a low-power, battery operated system where you may want to sleep for longer periods of time than the hardware watchdog can handle. However, if power is not a concern the software watchdog pattern provides a simple way to ensure all tasks in an RTOS application are operating as expected. If you have any questions or comments, feel free to leave them below.
This blog is part of the Kernel 201: Designing a Dynamic Multiprotocol Application with Micrium OS. The table of contents for this blog series can be found here.
This blog is part of the Kernel 201: Designing a Dynamic Multiprotocol Application with Micrium OS. The table of contents for this blog series can be found here.
Note: It is recommended to download the Kernel 201 application and have the code in front of you as you go through this blog post. The code can be downloaded on the Kernel 201: Project Resources page.
Task Architecture
The first step of designing any real-time system, before writing any code, is to identify all events the system will be responsible for. Listing out these actions will help identify what events may be grouped together in tasks and what actions will require their own task/s. There are a number of resources available that discuss different task modeling strategies. Some common strategies you may come across are:
Signal event groups – Every event is put in its own task. Not efficient in large systems.
Sequential events – Events that must be processed in order can be grouped together.
Timing events – Events that occur on a periodic time base can be grouped together
Interface events – All events associated with a particular interface
Safety monitoring – Any safety monitoring events should be separated from any actuation tasks
For this application, these are the following events that must be handled and how they’ll be grouped into tasks:
Bluetooth TX – labBluetoothTask
Bluetooth RX – labBluetoothTask
Proprietary Wireless TX – labPropTask
Proprietary Wireless RX – labPropTask
GPIO LED Control – labLEDTask
RBG LED Control – labLEDTask
Button 0 Read – labBtnTask
Button 1 Read – labBtnTask
Hardware Watchdog – labWDOGTask
labBluetoothTask
Silicon Labs’ Bluetooth stack already creates two tasks, Bluetooth and LinkLayer to handle the transmission and reception. The Bluetooth task provides callbacks for the user to implement to know when there is an event to process. The labBluetoothTask will handle those events from the Bluetooth task and pass that data along to the other tasks in the system. The labBluetoothTask will also receive data from other tasks in the system to transmit via Bluetooth.
labPropTask
Silicon Labs does not provide internal tasks for Proprietary Wireless (RAIL) as it does for Bluetooth, but it is important to group the RAIL functions together as they are not thread-safe functions. The labPropTask will handle all data received by RAIL and send it to other tasks in the system as needed. It will also receive data from other tasks in the system and send it out via RAIL.
labLEDTask
Since only the GPIO or RGB LEDs can be active at one time, it makes sense to group them together.
labBtnTask
The button task operates on a low priority polling interval. It could be switched to an interrupt based task but by leaving it as a polling task, it leaves open the option to add other polling events to the task in the future.
labWDOGTask
The watchdog task will implement a software based watchdog to control how the system feeds the hardware watchdog. It is important that this task have no other operations than handling the watchdog.
Task Communication
Now that the events have been divided up into their respective tasks, it is important to implement a consistent method for communication between tasks. There are again many different ways to implement task communication. Micrium OS Kernel provides Semaphores, Task Semaphores, Event Flags, Message Queues and Task Message Queues. While each of these kernel objects have various pros and cons, no one of these services is better than another; it just depends on the application and how it is using these kernel services.
For this application, each task (with the exception of the watchdog task) will be centered around a Task Message Queue and the entire application will use a sort-of layered messaging scheme, similar to the OSI model but much more simplified. The main loop of each task will pend on a Task Message Queue and wait for a message or timeout to determine its next action.
The image above shows the basic layout for all tasks in the system. The code snippet below shows some pseudocode for the task
void* p_msg;
LAB_Q_ID_e lab_q_id;
while (DEF_TRUE)
{
p_msg = OSTaskQPend( LAB_WDOG_TASK_TIMEOUT_MS, // Block the task until we
OS_OPT_PEND_BLOCKING, // receive a message
&lab_q_id,
0,
&err);
do {
if(err.Code == RTOS_ERR_TIMEOUT) { // If we timeout, just feed
break; // the watchdog task
} else if(err.Code != RTOS_ERR_NONE) { // Shouldn't occur, assert
APP_RTOS_ASSERT_CRITICAL(err.Code == RTOS_ERR_NONE, ;);
}
switch(lab_q_id) {
case LAB_Q_ID_XXX_EVT:
labXXXHandleEvt(); // Handle a task event
break;
case LAB_Q_ID_MSG:
labXXXHandleMsg((LAB_MSG_s*) p_msg); // Handle a lab message
labUtilMsgFree(p_msg); // Then free the message
break; // back to the pool
default:
break;
}
} while(0);
labWDOGFeed(LAB_TASK_ID_XXX); // Feed the watchdog after
} // every task action
By using the Task Message Queue, it allows a task to wait on three different types of events:
Timeouts
Events
Lab Messages
Timeouts
The software watchdog wants every task to check in on a specified rate to show it has not gone out to lunch. By specifying a timeout value in the Task Message Queue pend, the pend call will return with RTOS_ERR_TIMEOUT if a message is not received in the specified time. If a task expects a message in a set time interval, logic can also be added to the error check for RTOS_ERR_TIMEOUT to keep track of how many timeouts we receive in a row.
Events
Some tasks may have a hardware interrupt or software timer callback they need to handle in addition to processing messages from other tasks in the system. The msg_size data field in OSTaskQPend() provides a 32-bit value that is used as an identifier field for this task design. When a task receives a message, it will have a switch statement to handle the value of msg_size. In this application, all message identifiers can be found in an enum called LAB_Q_ID_e.
When an interrupt or software timer callback wants to send a message to the task it is associated with, it will make a call similar to the one below:
It is important to note that the LAB_Q_ID_e value is specified in the msg_size field and not the void* field. All messages sent must have a valid identifier in the msg_size field where the void* argument is optional. In this case, the void* argument is set to 0 as there is no extra data to send.
Lab Messages
These messages are how tasks communicate with each other in this application. Rather than having the Bluetooth or Proprietary Wireless tasks spend time configuring PWM timers to drive the RGB LEDs, it makes more sense to send the LED task a LED command to be processed. This also allows us to handle wireless communication at a higher priority than changing the LEDs or polling the button states. The wireless tasks may be affected if responses are not sent out at specific intervals where if the system has to wait an extra 10ms to toggle the LED, the user most likely won’t notice.
The lab messages follow a layered model where every message has the same header, the header defines what else is to follow in the packet. This application provides utility functions for getting, sending and freeing messages (refer to lab_util.c). There are advantages to these utility functions that will be discussed a little later. When you get/free a message you are actually pulling from a memory pool of fixed block sizes. All messages, regardless of how much of the block they use, are the same size. In the case of this application, all messages are 32 bytes in size. This means that if a task needs to send or receive a message larger than 32 bytes, either the size of every block in the system must be increased, multiple messages must be sent or modifications must be made to the utility functions to allow for allocation and freeing of different size blocks.
The struct above shows the lab message structure that all messages will start with. The ID field identifies what message will follow it and the type corresponds to if it’s a command, response, update or error message. The void* argument is used so you can cast the next layer to the end of the lab message struct.
LAB_MSG_s *p_msg;
p_msg = (LAB_MSG_s*) labUtilMsgGet(); // Get a data buffer to send a message
if(p_msg == DEF_NULL) {
break;
}
p_msg->id = LAB_MSG_ID_LED; // Set the message id
p_msg->type = LAB_MSG_TYPE_CMD; // Set that its a command message
When you wish to allocate a message to send, the code snippet above shows how you would use the labUtil function to allocate a message. The image below shows how the lab message fits into the allocated block.
After you configure the message ID and message type fields, you need to configure the next part of the block for the message ID you specified. For this example, let’s assume we’re changing the LEDs. LEDs are controlled by the LAB_LED_MSG_s struct. To accomplish this, you will cast the LAB_LED_MSG_s to p_data so when you enter information for the LED message, it goes into the correct location in lab message.
LAB_MSG_s *p_msg;
LAB_LED_MSG_s *p_led_msg;
p_msg = (LAB_MSG_s*) labUtilMsgGet(); // Get a data buffer to send a message
if(p_msg == DEF_NULL) {
break;
}
p_msg->id = LAB_MSG_ID_LED; // Set the message id
p_msg->type = LAB_MSG_TYPE_CMD; // Set that its a command message
p_led_msg = (LAB_MSG_LED_s*) &(p_msg->p_data);
p_led_msg->mode = LAB_LED_MODE_RGB;
p_led_msg->color = LAB_LED_COLOR_GREEN;
p_led_msg->state = LAB_LED_STATE_BLINK;
The code snippet above shows how to cast the p_data argument to the LED message structure. Now when you modify the fields of the LED message structure it will be aligned in the message block as shown below.
Once the full message is assembled, the message needs to be sent to the desired task/s. Some messages may only go to one task where others may need to be sent to multiple tasks. The lab utility function for sending offers flexibility for sending messages. Using the labUtilSend() function as shown below, you pass the pointer to the message block just configured and the task/s the message should be sent to.
labUtilMsgSend(p_msg, dest_task); // Send the message to the specified destination
In the case where one message is being sent to multiple tasks, the send function will keep track of the number of tasks it was sent to. This allows each task to call the free function after its processed the message, but the memory block is not actually freed until all tasks that received the message free it. To free a message all a task needs to do is make the following call:
labUtilMsgFree(p_msg); // Free the message back to the pool
It is the labUtilMsgFree function's job to determine when the message is actually returned to the message pool. If one task never calls free on the message it received, that block will never be freed and that memory will be lost so it is imperative that all tasks free all messages they receive, even if they receive the message in error.
Final Thoughts
This wraps up the Task Communication and Architecture section of the Kernel 201 application. Moving forward the Bluetooth, Proprietary Wireless, LED and Button tasks will all be using this communication structure. If you have any questions about this post feel free to leave comments below.
This blog is part of the Kernel 201: Designing a Dynamic Multiprotocol Application with Micrium OS. The table of contents for this blog series can be found here.
Note: It is recommended to download the Kernel 201 application and have the code in front of you as you go through this blog post. The code can be downloaded on the Kernel 201: Project Resources page.
Introduction
Micrium OS offers default configurations to allow a user to get started quickly. These configurations are useful for quick starts, test applications and instances where memory is not a constraint. It is important that all developers using Micrium OS do give some attention to the RTOS configuration as the defaults are not ideal for a released application.
To ensure the dynamic multiprotocol application starts off on a good foot, one of the first steps that will be taken is to configure Micrium OS. Most of the sample applications available in Simplicity Studio provide a good starting point, but this post will look a little more in-depth at the configuration that’s available.
Micrium OS Configuration Files
os_cfg.h
Note: Some example projects have already made modifications to os_cfg.h. The comments here are based on differences between the default os_cfg.h found in the Gecko SDK Micrium OS directory and this project.
This file provides all compile-time options for Micrium OS Kernel. It provides the ability to turn on and off almost all parts of the kernel. Typically, the default values are fine to start a project out with. In this project there are a few differences from the default config worth highlighting:
App hooks enable will turn on the callback functions (if one is defined) anytime the following events occur:
Redzone Hit (if Redzone is enabled) – Occurs when a stack overflow is detected
Task Create – Occurs after the task has been created but before OSTaskCreate() returns
Task Delete (if task delete is enabled) – Occurs after the TCB is cleared and removed from the kernel but before OSTaskDel() returns.
Task Return – Occurs if a task attempts to return
Idle Task – Occurs at the end of the idle task while(1) loop
Stat Task – Occurs after CPU usage calculation in the stat task
Task Switch – Occurs right before a task is switched out
Time Tick – Occurs right before a semaphore post to the tick task
The hook that is set up in most projects is the idle task hook. Since this hook is called from the idle task loop, it is an ideal time to enter a lower power mode. Right now the kernel can run from EM0, EM1 or EM2 (EM2 requires use of the LFRCO).
Dynamic Tick
Dynamic tick allows the kernel to adjust the tick rate as needed to minimize the amount of time the kernel has to wake from sleep. The images below show the advantage of using dynamic tick over a periodic tick.
Periodic Tick
Dynamic Tick
Priority Maximum
The PRIO_MAX setting controls the maximum number of task priorities allowed in the system. Micrium OS supports an unlimited* number of task priorities but there are advantages of having the value set to a smaller number.
If a system only has 10 tasks, there is an advantage to setting PRIO_MAX to 32 vs 64, 128, 256, 512 or some other very large number. The way the kernel’s scheduler looks for the next available task is it has an array called OSPrioTbl[] which is defined as follows:
Each bit in the PrioTbl corresponds to a task priority so since each row holds 32 bits, that’s 32 priority levels that can be checked in one go. If PRIO_MAX is set to 512, the kernel will potentially have to go through 16 rows before deciding to drop to the idle task. That’s a lot of extra overhead for task priorities that are not being used.
*Hardware provides the limitation, there is no limitation in software.
OSTaskDel
The OSTaskDel() should be disabled by default in almost all Micrium OS applications. Deleting a task only removes it from the kernel so it is no longer scheduled. It does not take into account any kernel objects associated with the task nor does it free up any memory associated with the task being deleted. There are very few situations where OSTaskDel() is needed.
common_cfg.h
The common_cfg.h file is used to configure the memory, string and clock modules. The defaults for string and clock are fine for this project, but since the goal of this project is to reduce the kernel’s footprint the memory will be adjusted.
By default the kernel uses an internal heap to allocate space for internal tasks and message queues. By making the following change to the heap size, it will turn off the internal heap.
#define LIB_MEM_CFG_HEAP_SIZE 0uL
If this was the only change is made to the project, the project would compile but fail immediately during runtime when OSInit() is called due to no memory being available. A change also has to be made in rtos_cfg.h to disable the use of the internal heap for internal tasks and message queues.
rtos_cfg.h
The rtos_cfg.h file controls three things:
Assert configuration
Memory usage configuration for internal tasks and message queues
Logging
The assert configuration defaults to locking the system in a while(1) loop for debug and critical asserts. The debug asserts should be modified when going into production but for development it can be useful to leave the while(1) loop to find issues quicker.
The logging is an optional module that is not used in this project.
The Default Config configuration is what determines if the heap is used for internal tasks or not. By making the following change, it will require that a number of internal structures are externally configured. This will allow for the kernel to operate with the heap being set to 0.
A full list of available RTOS_MODULE options can be found in the Gecko SDK version of rtos_description.h.
Main Configuration
Once the changes have been made to the necessary config files, the desired kernel configuration must be made in the application. In this example, the file lab_main.c has the following kernel configuration.
Tick Task
The tick task is used to control the kernel’s system tick which is used for time delay calls and pend timeouts. In this application it is based off of the RTCC interrupt. The following configuration will define a stack for the tick task and set the config only if OS_CFG_TASK_TICK_EN is set in the os_cfg.h file. The stack size, priority and frequency of the tick task are all configured in the lab.h file.
The idle task is the lowest priority task in the system. When the kernel has no other tasks to schedule, it will run the Idle Task. When entering the Idle Task, there is a hook function that can be implemented to allow the user application to enter a lower power mode. The following configuration will define a stack for the idle task and set the config only if OS_CFG_TASK_IDLE_EN is set in the os_cfg.h file. If the idle task is not enabled, when the current task finishes the scheduler sits in a while(1) loop until another action happens in the system rather than jump to a different task. When the idle task is enabled the stack size of the idle task can be found in lab.h. You can not set the priority of the idle task because it must always be the lowest priority task in the system.
The timer task is used to control Micrium OS Kernel’s software timers. The reason the timers operate in a different task than the tick task is the timer callback functions are made from the timer task, so it allows the timer callbacks to run at a different priority than the tick task if desired. The following configuration will define a stack and set the config only if OS_CFG_TMR_ EN is enabled in the os_cfg.h file. The stack size, priority and frequency of the timer task are all configured in the lab.h file.
The stat task is an internal task that provides such run-time statistics as overall CPU utilization (0.00 to 100.00%), per-task CPU utilization (0.00 to 100.00%), and per-task stack usage. The following configuration will define a stack and set the config only if OS_CFG_STAT_TASK_EN is enabled in the os_cfg.h file. The stack size, priority and frequency of the stat task are all configured in the lab.h file.
The ARM Cortex-M series has a separate stack for interrupts to execute out of. Micrium OS Kernel will configure the stack location during the OSInit() call, but a stack must be provided. The following configuration creates the interrupt stack and sets the necessary configuration. This is not an optional configuration, it is required of all Micrium OS Kernel applications.
If message queues will be used in an application (this application makes heavy use of them) then a message pool must be defined. When messages are sent in either a message queue or task message queue, a message pool object is allocated to hold the data being sent (void* argument and message size argument). The message pool should have enough entries for every message queue entry in the application. For example, if you have 3 message queues each with 10 entries in them, you should have a message pool size of 30. The following configuration is used to specify the message pool size in this application.
And finally, in the main() before OSInit() is called, the memory segment must be created so the kernel knows how to access the memory buffer specified above.
Mem_SegCreate( "Msg Pool Mem", // Create the Message Pool segment
&MsgPoolMemSeg,
(CPU_ADDR)&MsgPoolMem,
MSG_POOL_SIZE,
LIB_MEM_PADDING_ALIGN_NONE,
&err);
APP_RTOS_ASSERT_DBG((RTOS_ERR_CODE_GET(err) == RTOS_ERR_NONE), 1);
Putting it all together
You may have noticed that all of the configs are just #defines. These #defines are used to create one giant #define as shown below.
Once the OS_INIT_CFG_APP define is put assembled with all of the task and memory pool configs, the define should be assigned to the global variable as follows:
const OS_INIT_CFG OS_InitCfg = OS_INIT_CFG_APP;
This variable is externed by the kernel so it must be named OSInitCfg as this is what the kernel uses internally.
Final Thoughts
While it may appear a little complicated, the configuration of Micrium OS Kernel is very important to the success of an application and worth the extra effort. A misconfigured kernel can cause issues farther down the road so it is important to configure it correctly to start with. By removing the general purpose heap it allows the developer to have a full understanding of what's going on under the hood so there is no confusion about how the kernel is configured. If you have any questions or comments feel free to leave them below.
Official Blog of Silicon Labs
How to use Bluetooth Low-Energy for Wi-Fi commissioning
Introduction
If your Wi-Fi connected product is headless, then technically speaking, the obvious solution for exchanging the Wi-Fi credentials required to commission the product onto the customer’s Wi-Fi network is SoftAP.
SoftAP stands for Software Enabled Access Point. Some product manufacturers use SoftAP to create a temporary access point for the unique purpose of getting the customer’s Wi-Fi network name (SSID), security mode and password as illustrated in the following diagram:
SoftAP used to be the Wi-Fi commissioning solution of choice for early IoT devices, but the two fundamental problems listed below have made it an unreliable solution:
In order to improve the out-of-box experience, product manufacturers have turned to Bluetooth as a solution for commissioning. For the Wi-Fi connected products that already support Bluetooth for a different purpose (e.g. streaming audio or video) then Bluetooth is the go-to mechanism for Wi-Fi commissioning as illustrated in the following diagram:
Because of how important the out-of-box experience is to a product’s success, many product manufacturers should consider going to the extremes of adding a Bluetooth chip exclusively to support the Wi-Fi commissioning of the product. Silicon Labs has BLE chips such as the EFR32MG12 that not only supports BLE but also other wireless protocols in the same chip.
Whatever your case may be, this blog shows you one simple way to use Bluetooth for Wi-Fi commissioning by covering the following topics:
Prerequisites
It is assumed that you are familiar with Web Technologies such as HTML and JavaScript, and more important, that you are familiar with your own Wi-Fi and Bluetooth stacks regarding the following topics:
BLE Stack
Wi-Fi Stack
Hardware Requirements
Software Requirements
BLE GATT Server Design
Using your GATT Configuration tool, you need to create two BLE GATT Services:
Wi-Fi Scanner Service
This service allows a Bluetooth Client to initiate the scanning of visible Wi-Fi networks and its corresponding information such as SSID, Security Mode and Signal Strength.
Wi-Fi Configurator Service
Allows a Bluetooth Client to configure the connected product with the information necessary to connect to a Wi-FI Access Point (i.e. SSID, Security Mode and Password).
The table below shows an example of such GATT database. Notice that the UUIDs have been truncated for sake of simplicity. In reality, they should be 128-bit and it’s important you keep them documented in a table similar to this.
BLE GATT Configuration
Table 1 BLE GATT Configuration
Characteristics
Both services have a characteristic called State that is used to communicate the state of the corresponding operation. Therefore, both characteristics support Read, Write and Notification.
Here are the possible states:
Code Listing 1 Wi-Fi Scanner and Wi-Fi Configurator Service States
The rest of characteristics are meant to exchange the actual data. Notice that the results from the Wi-Fi Scanner need to be communicated in multiple characteristics because of limitations on the maximum length of a BLE Characteristic’s value (i.e. 255 bytes).
Here is an example of the value exchanged by one of such characteristics. It is in JSON format and it is sorted by signal strength such that the closest access point is displayed on top:
Code Listing 2 List of Access Points in JSON format
BLE Mobile Application
For the BLE mobile application you have the choice of creating a native BLE application to support iOS and Android as a minimum or use Web Bluetooth.
Web Bluetooth allows a web browser (e.g. Google Chrome) to see and interact directly with Bluetooth devices as illustrated in the following image:
The advantages of Web Bluetooth over traditional native BLE mobile applications are:
If Web Bluetooth is used instead of a traditional native BLE mobile app, then the revised block diagram for the Wi-Fi commissioning system using Web BLE would look like the following:
Theory of Operation
The diagram below summarizes the way the entire system works:
Connected Product
(BLE GATT Server)
Smartphone
(BLE Client)
To initiate a Wi-Fi Scan procedure, the BLE Client sends a request to write:
BLE GATT characteristic: gattdb_wifi_scan_state
Value: WIFI_SCANNER_STATE_SCAN
The BLE GATT Server receives the request to write:
BLE GATT characteristic: gattdb_wifi_scan_state
Value: WIFI_SCANNER_STATE_SCAN
gattdb_wifi_scan_ap_list_1
gattdb_wifi_scan_ap_list_2
gattdb_wifi_scan_ap_list_3
gattdb_wifi_scan_ap_list_4
gattdb_wifi_scan_ap_list_5
gattdb_wifi_scan_ap_list_1
gattdb_wifi_scan_ap_list_2
gattdb_wifi_scan_ap_list_3
gattdb_wifi_scan_ap_list_4
gattdb_wifi_scan_ap_list_5
gattdb_wifi_cfg_ssid
gattdb_wifi_cfg_password
gattdb_wifi_cfg_security
gattdb_wifi_cfg_ssid
gattdb_wifi_cfg_password
gattdb_wifi_cfg_security
BLE GATT characteristic: gattdb_wifi_cfg_state
Value: WIFI_CFG_STATE_SAVE
BLE GATT characteristic: gattdb_wifi_cfg_state
Value: WIFI_CFG_STATE_SAVE and if not saving process in progress, it calls the API to store variables in non-volatile memory
BLE GATT characteristic: gattdb_wifi_cfg_state
Value: WIFI_CFG_STATE_JOIN
BLE GATT Characteristic: gattdb_wifi_cfg_state
Value: WIFI_CFG_STATE_JOIN and calls the Wi-Fi API to join a network
Figure 5 Flow Diagram
Source Code
To keep the blog relevant to any Wi-FI and BLE stack, the source-code-level details on how to perform the different functions outlined in the previous flow diagram have been omitted.
The following Wi-Fi and BLE APIs are better described in their corresponding documentation and are beyond the scope of this blog:
The web page that makes the actual BLE mobile application however, is provided as an attachment (web_ble.zip) and if you like this approach, feel free to modify it and use it under the terms of the Apache License.
Security Considerations
Because of the sensitive nature of the information exchanged, you should consider using the security features of your Bluetooth stack:
Check your Bluetooth stack documentation for more information on these security features.
Further Reading
Timing 201 #1: The Case of the Phase Noise That Wasn't - Part 1
Introduction
Hello and welcome to the inaugural article for a new blog series, Timing 201. My previous blog series, Timing 101, ran for 12 articles over a period of roughly a year and a half.
As the name suggests, I intend to discuss timing topics with a little bit more breadth and depth than might be considered “Timing 101” material. However, that does not mean I won’t cover introductory material, if and when it’s called for, especially if readers ask for it.
When More is Less
You may recall that clock buffers are typically specified in terms of additive jitter. That is because they do not have an intrinsic phase noise source such as an XO (crystal oscillator) or a PLL’s VCXO. They consist of only amplifiers and perhaps dividers. So we would generally expect an XO followed by a clock buffer to have at least somewhat increased phase noise or jitter compared to the XO alone.
All things being equal, this will be the case, except when the amplifier has sufficiently high gain to act as a limiting amplifier or LA. In these situations, the apparent measured source + LA phase noise may actually decrease. I ran in to this phenomena years ago evaluating various clock + buffer combinations. The results weren’t always making sense and it turned out at the time that some of the noise I was measuring was in fact, not really phase noise, hence the title of this case.
To see how this might happen, let’s touch on what is meant here by apparent measured phase noise.
Phasors ON
You may recall I discussed modulation spurs previously in Timing 101 #7: The Case of the Spurious Phase Noise Part II. In that article, I considered carriers with relatively small amounts of AM (Amplitude Modulation) and narrowband FM (Frequency Modulation) or equivalent PM (Phase Modulation). The general ideas comparing AM and FM/PM spurs also apply to AM and FM/PM noise.
One topic I did not touch on at that time was the phasor or phase vector representations of AM and NB FM as shown below. The carrier vector is shown as a thick red arrow and the modulation LSB (lower sideband) and USB (upper sideband) vector components are shown as thinner blue arrows. The vector sum or resultant of the modulation is the thick blue arrow. The modulating frequency is f<subscript>M and the rotating arrows indicate the change in the modulation vectors over time versus the carrier. For the figures below the overall vector sum is the geometric addition of the carrier + modulation resultant.
What’s useful about the phasor representation is that it indicates that random noise modulating the carrier can be regarded as consisting of both AM and PM components. That is, components of the noise contributing to carrier magnitude changes are the AM components. Likewise, components of the noise contributing to carrier angle changes are FM or equivalent PM components.
You may see authors emphasizing this distinction by using script L(f) or ℒ(f) to refer to PM noise or “real” phase noise and script M(f) or ℳ(f) to refer to AM noise. The first paper I know of using this notation is:
Spectral Density Analysis: Frequency Domain Specification and Measurement of Signal Stability, by Donald Halford, John H. Shoaf, and A. S. Risley, National Bureau of Standards, Boulder, CO, published in 27th Annual Symposium on Frequency Control, 12-14 June 1973, https://tf.nist.gov/general/pdf/1558.pdf
The magnitude of noise that is AM + PM will be the RSS or Root Sum Square of the individual modulation contributions. Instruments that treat these noise components the same will then “see” this RSS noise directly as phase noise. This is what is meant by apparent phase noise and it is a particular issue for Spectrum Analyzers as discussed below.
The Spectrum Analyzer in Brief
As I noted in Timing 101 #7, Spectrum Analyzers do not preserve phase information and so a low modulation AM spur appears similar to a narrow band low modulation FM spur.
Below is a block diagram for a classic swept spectrum analyzer which suggests why. It is essentially a calibrated frequency selective peak responding voltmeter. The difference in phase between the DUT (Device Under Test) and the LO (Local Oscillator) inputs at the mixer is arbitrary. The Spectrum Analyzer doesn’t “know” anything about their relative phases and AM and PM cannot be distinguished.
The Phase Noise Analyzer in Brief
By contrast, the Phase Noise Analyzer is much less susceptible to AM. The simplified block diagram below gives the basic idea behind the method typically used by Phase Noise Analyzers and Signal Source Analyzers. The mixer is usually a double-balanced mixer to suppress even-order mixing products.
Note that, unlike the Spectrum Analyzer, there is a PLL (Phase Lock Loop) that enforces a specific phase relationship between the DUT and the Reference. Further, it can be shown that AM and PM can be distinguished as follows.
As designed, the Phase Noise Analyzer will be superior to the spectrum analyzer for rejecting AM.
Take It to the Limit
So how exactly does the limiting amplifier or LA help us here? The clue lies in the behavior of the LA: It removes, or at least minimizes, amplitude variation from the clock signal. Therefore, if a source has both AM and PM noise components, then an ideal limiter will remove the AM component noise leaving only the PM noise (the genuine phase noise) behind. The exaggerated sketch below gives the basic idea.
Now getting back to the original work which prompted this post:
If a clock source had apparent phase noise that included both AM and PM noise contributions, then following it with a high gain clock buffer or LA would strip away the AM resulting in less than expected measured phase noise. Rather than yielding additive jitter the new component apparently yielded “subtractive” jitter. Thus the case of the phase noise that wasn’t.
When should AM be considered when making phase noise measurements?
The short answer is that AM is always a potential consideration when one is making careful jitter and phase noise measurements. Having a limiter on one’s lab bench is as important as a balun.
However, there are specific instances where AM can be more of an issue than others.
1. Measuring phase noise using a spectrum analyzer or any other instrument that does not sufficiently reject AM.
A limiter can be valuable even when working with a Phase Noise Analyzer by suppressing AM beyond the rejection capability of the mixer. This may be necessary when measuring very low phase noise sources.
2. Measuring low frequency low phase noise sources.
You may recall the 20log(N) rule, i.e. if the carrier frequency of a clock is divided down by a factor of N then we expect the phase noise to decrease by 20log(N); however, this rule only applies to phase noise. If there is significant AM noise also then this component will loom larger, as we decrease the carrier frequency, and potentially impact measurements.
3. Measuring a source known or suspected to have AM noise.
Clock sources with high common mode noise fall in to this category. For example, we specifically inject power supply ripple when testing oscillator power supply rejection. This is why you see a limiting amplifier shown in Figure 5. PSRR Setup in AN491: Power Supply Rejection For Low-Jitter Clocks. See the highlighted block in the diagram below which comes from that app note.
4. Troubleshooting
Finally, the ability to distinguish between phase noise and spurs, and AM noise and spurs, can be very helpful when troubleshooting a system and determining the root cause of performance issues. Additional testing may also be needed to determine how sensitive the ultimate receiver is to clock impairments that include AM noise.
Conclusion
I hope you have enjoyed this Timing 201 article. In the next article, I will give some measurement examples and offer a few rules of thumb.
As always, if you have topic suggestions for this blog or timing-related questions, please send them to kevin.smith@silabs.com with “Timing 201” in the subject line. I will give them consideration and see if I can fit them in. Thanks for reading. Keep calm and clock on.
Cheers,
Kevin
Kernel 201: WebBluetooth App
This blog is part of the Kernel 201: Designing a Dynamic Multiprotocol Application with Micrium OS. The table of contents for this blog series can be found here.
Note: It is recommended to download the Kernel 201 WebBluetooth Application and have the code in front of you as you go through this blog post. The code can be downloaded on the Kernel 201: Project Resources page.
Introduction
WebBluetooth API is a Javascript API that provides Bluetooth support for web pages. The API, which was first published in 2015, is still considered Experimental but it has been supported in Google Chrome since version 56 and Opera since version 43 for desktop and Android devices. At the time of writing this, WebBluetooth API is still not supported on Edge, Firefox, or Safari and it does not work on iPhones at all.
The advantage of using the WebBluetooth API is it allows for a quick way to develop an application that can run on desktop or mobile from the same code. In the past if a developer wished to interact with Bluetooth on both desktop and mobile, typically separate applications were needed. The code provided on the Project Resources page runs on any web server that has HTTPS enabled, and will work on desktop and Android.
The full WebBluetooth API can be found here.
WebBluetooth App
The WebBluetooth App that interacts with the Kernel 201 Application is based off of StartBootstrap’s SB Admin 2 template. The template provides the necessary css code to support small screens such as mobile devices and large screens like desktop monitors.
The code included in the WebBluetooth App has been paired back considerably from the full SB Admin template to only include the files needed. If you wish to view the entire SB Admin template, it can be found here.
There are only 3 files and one folder in the WebBluetooth App specific to the Kernel 201 Application. The rest of the files are part of Bootstrap, jQuery and SB Admin files that do not need modification.
index.html & images directory
The entire WebBluetooth App’s HTML code is located in this one file. The app’s display is very simplistic, just display fields and buttons for control. All of the different views for the application are already in the index.html page, the Javascript code controls the showing and hiding of different elements based on the different states of the application.
The images folder holds the different images shown in the WebBluetooth App. In the current version of the application it is used only to hold the logos as seen above.
bt.css
The bt.css file is the main css file from the SB Admin template. There have been minor changes such as color scheme, screen size and card behavior made to the file.
bt.js
This file is what controls the behavior of the WebBluetooth App. It contains the WebBluetooth API code as well as control of what elements are shown on the index.html page.
After clicking the Lab 1 button, a user is brought to the screen above. Clicking connect will trigger the function btConnect() in bt.js. This function begins making WebBluetooth API calls that will start the connection process to the Kernel 201 Application.
The Javascript Engine runs in a single thread, so when it hits a function that requires a delay or user input, instead of blocking the entire application it puts that function off until the delay or input is received and continues executing the rest of the code. In order to ensure the WebBluetooth API functions are called in order, the connect code relies on Javascript Promises. The Promises allow the connection events to happen sequentially using the then() keyword. In the example above you can see that the connect() will not occur until the requestDevice() function has finished. If the then() keyword was not used, Javascript would attempt to run connect() before the requestDevice() function completed causing an error.
When the requestDevice() function is first executed, a filter is applied. The filter is using the UUID of the Lab Control service. You may recall from the Kernel 201: Bluetooth Task blog that the Lab Control service contains all of the tasks in the lab application. By filtering on the Lab Control service, it allows the Bluetooth Connection Dialog to only show Bluetooth devices running the Kernel 201 Application as shown above.
After the connection is made, the WebBluetooth App connects to the Lab Control service and subscribes to notifications from all of the characteristics specified. The notifications allow for the Kernel 201 Application to send a status update to the WebBlueooth App as soon as it occurs, rather than having the WebBluetooth App constantly poll for changes. After its completed the notification subscriptions, the WebBluetooth App makes read requests from the Kernel 201 Application and displays the device state as shown above.
Once the display has been changed to the current state of the Kernel 201 Application, the WebBluetooth App maintains a Bluetooth connection but sit idle until one of two actions occur:
When the user clicks an LED button, the LED write function will call the Bluetooth write function to send a write command to the Kernel 201 Application with the LED data. After the command is sent, the WebBluetooth App does not change the user interface to reflect the command just sent. The change in the user interface will come from the Kernel 201 Application sending a notification that a change has been made to the LED. This prevents the user interface from getting out of sync with the Kernel 201 Application.
When a notification is received from the Kernel 201 Application, the callback bt_cb_onnotify() fires and determines what portion of the UI needs to be updated. It then passes along the received data to the necessary functions to update the UI.
Final Thoughts
The WebBluetooth API provides a simple, quick way to create apps that run on both mobile and desktop natively. Unfortunately, since it is still experimental, there is a lack of support for it. Hopefully in the future, it will become a widely accepted way of interacting with Bluetooth devices. If you have any questions or thoughts on this feel free to leave them below.
Kernel 201: Bluetooth Task
This blog is part of the Kernel 201: Designing a Dynamic Multiprotocol Application with Micrium OS. The table of contents for this blog series can be found here.
Note: It is recommended to download the Kernel 201 application and have the code in front of you as you go through this blog post. The code can be downloaded on the Kernel 201: Project Resources page.
Note: This project has a slightly different RTOS interface with the Bluetooth stack than other example projects. The differences will be highlighted in this article.
Introduction
The goal of the Bluetooth task in the Kernel 201 Application is to communicate with a web browser running a WebBluetooth App. The WebBluetooth App is highlighted in detail in another post that can be found here.
The Bluetooth task will perform the following actions:
Kernel 201 Bluetooth Initialization
Before starting the Bluetooth Task, configurations and initializations must be performed for the Bluetooth stack to operate correctly. Part of the configuration for the Bluetooth stack comes from the GATT editor in Simplicity Studio; the other portion of the Bluetooth configuration comes from the gecko_configuration_t structure.
To modify the Bluetooth GATT configuration, there is an application in Simplicity Studio to help configure the GATT database. In the Kernel 201 Application there is a file called kernel201.isc. Opening that file in Simplicity Studio will open the GATT Configurator where you can make changes to the GATT database.
In the GATT Configurator, a new Bluetooth Service called Lab Control has been added for the Kernel 201 Application. Any task in the application that wishes to have Bluetooth control will have a characteristic under the Lab Control service. For the Kernel 201 Application, each characteristic will support Read, Write and Notify. The characteristics are given unique UUID numbers that are hardcoded into the WebBluetooth App. If someone wishes to add a new task, modifications would also have to be made to the WebBluetooth App to support the new UUID. The code for the WebBluetooth App is available for download under the Kernel 201: Project Resources page.
By default, the Kernel 201 Application shows up as “Kernel201” for the Bluetooth Device Name. If you wish to change the Device Name to something else, this can be accomplished under the Device Name Characteristic in the GATT Configurator. The value field is where the new Device Name would be specified and the length must be adjusted. Note: For the DMP portion of this application to work correctly the Device Name must be 16 characters or less. This is a Kernel 201 Application requirement, not a Bluetooth requirement.
After all changes have been made in the GATT Configurator, the kernel201.isc file needs to be saved and then click Generate to update the GATT information. For further information on the GATT Configurator, refer to UG365: GATT Configurator Users Guide
In the lab_bluetooth.c file, there is also the gecko_configuration_t Bluetooth configuration structure that must be passed in during initialization. As shown above the structure sets internal flags, heap location and size (separate heap from Micrium OS), GATT Database, callback functions and other power and security parameters. For more information on the structure, refer to UG136: Silicon Labs Bluetooth C Application Developer’s Guide.
The Kernel 201 Application also introduces a second configuration structure that is not found in other Dynamic Multiprotocol Applications or officially supported by the Bluetooth stack.
Typically, the function bluetooth_start_task() only takes in the task priorities for the Link Layer and Bluetooth tasks. This structure adds a callback function that will be used when there is a Bluetooth event for the labBluetoothTask to process.
This change is necessary because the existing implementation of the Bluetooth Stack’s RTOS port relied on the user application to pend on an Event Flag. Since the tasks in the Kernel 201 Application pend on Task Message Queues, it was not possible to use the Bluetooth Event Flags in conjunction with the Task Message Queue. The addition of the callback function adds the flexibility for applications to use any kernel service desired for signaling rather than being forced to use an Event Flag.
Kernel 201 Bluetooth Task
The main Bluetooth task loop is structured just like all other tasks in the Kernel 201 Application (except for the watchdog task). When the task is created, the Bluetooth stack is configured and initialized and then begins waiting for messages in the Task Message Queue.
There are two types of messages and one error code that the Bluetooth task handles:
RTOS_ERR_TIMEOUT
As part of the software watchdog, the Bluetooth task must feed the software watchdog at a specified rate. There is a define in lab.h that all tasks use called LAB_WDOG_TASK_TIMEOUT_MS. This define specifies how often every task should check-in with the software watchdog. If the Task Message Queue does not receive a message before the timeout value is hit, the pend call returns with RTOS_ERR_TIMEOUT. Since it’s a timeout the Bluetooth task knows that no message was received, it only feeds the software watchdog and then starts pending on the Task Message Queue again.
LAB_Q_ID_BLUETOOTH_EVT
When the Bluetooth stack has an event for the Kernel 201 Application to process, it makes a call to the callback function specified in the BLUETOOTH_RTOS_CFG_s structure. That function is defined as follows:
In the callback function, a message is sent to the labBluetoothTask to tell it there is a message waiting to be processed. The callback function must send a message because the callback function is executed from the internal Bluetooth Task. If the callback function was to process the Bluetooth event it would lock up the internal Bluetooth task and potentially cause the Bluetooth Stack to miss other Bluetooth events.
When the signal to process an event is received by the labBluetoothTask, the function labBluetoothHandleEvt() is called. This function first retrieves the event that must be processed, and then determines how to handle it. The chart below shows the flow of the event handler:
gecko_evt_system_boot_id and gecko_evt_le_connection_closed_id
These events are called when the Bluetooth stack has been booted, and when a Bluetooth connection has been dropped. In both cases, the Bluetooth stack must be told to start advertising again as we don’t have a connection.
gecko_evt_gatt-server_user_write_request_id
The write event is called when the WebBluetooth App is wishing to send a command to a task in the system. A common example would be using the WebBluetooth App to change the LEDs.
The Bluetooth write event that is received from the Bluetooth stack also contains data such as the task the data is to be sent to, as well as the data itself. To send the data to the specified task, a lab message buffer is allocated using the utility functions. Once a buffer has been allocated, it is configured for the task destination and then the data specific to that task is copied into the buffer. The buffer is then sent to the desired task/s.
gecko_evt_gatt-server_user_read_request_id
The read event is called only when a WebBluetooth App first connects to the Kernel 201 Application. The read is used to determine the state of all of the tasks in the system for the WebBluetooth App. After the WebBluetooth App has connected and received the task status the first time, all subsequent updates are received via a Bluetooth notification.
LAB_Q_ID_MSG
When another task in the system wishes to send data via Bluetooth, a lab message must be sent to the Bluetooth task via the Task Message Queue. In most cases, this is used when a task has completed a request and is updating the remote application. In the LED example, after the LED has been changed a message is sent to the Bluetooth task so the WebBluetooth App connected, if any, is updated.
Kernel 201 Bluetooth Example
The following diagram shows the typical flow of data when a user wishes to change the LED:
Final Thoughts
The Bluetooth Task is one of two wireless tasks in the system that will send commands to the other tasks in the system and report back the status of the system. The other task is the Proprietary Wireless that is covered in Kernel 201: Proprietary Wireless Task. The Bluetooth Task has the advantage that the developer does not need to make multiple RAIL calls to configure the radio or listen for hardware interrupts because it is abstracted away by the Bluetooth Stack. The Proprietary Wireless Task does not have this luxury and will require some more in-depth knowledge of the RAIL API. If you have any questions or comments on the Bluetooth Task feel free to leave them below.
Making Peripheral Drivers Thread-safe
If you are running in a multi-threaded environment in which you have more than one task making use of a peripheral driver such as USART, SPI, I2C, etc., you should consider making it thread-safe.
The Micrium OS kernel offers a variety of services designed to protect shared resources. In our case, let’s make use of the Mutual Exclusion Semaphore also known as mutex. Why a mutex? Because we want our resource (peripheral driver) to be accessed only by one task at a time. Regular semaphores present a vulnerability with priority-inversion. Mutexes, on the other hand, are implemented in a way that priority inversions are prevented by using priority inheritance.
For this exercise, you will be editing files from the Gecko SDK, which is not recommended therefore do this with caution.
In the peripheral driver file that you want to protect, include the following file:
Now we have to declare a global variable for our mutex, for example, if you want to protect the SPI you could declare it as follows:
With the mutex now declared, you need to invoke the kernel call to create it. My recommendation is to make this in the initialization function of the peripheral driver that you are using. You create the mutex by calling:
Notice how the function requires an error argument, just declare RTOS_ERR err locally and pass it on.
Always make sure to check the error returned, if it’s not RTOS_ERR_NONE then something went wrong.
The mutex is now created and registered with the kernel. Now you will need to wrap around the driver calls that your application is using with:
Please make sure to check the returned errors. A common one is RTOS_ERR_NOT_READY, this happens when the pend or post calls are made before the kernel is in its running state (after the call to OSStart()).
If the driver initialization function can potentially be called multiple times from more than one task, my recommendation is to also protect it.
With this setup, you can be sure that your peripheral is only being accessed by one task at a time.
Beware also that some drivers have abort functions, you have to be careful with this and not lock your system on a mutex pend. For more information on how to protect a resource using Micrium OS please visit https://doc.micrium.com/display/OSUM50600/Resource+Management+Using+the+Kernel
IoT Hero IOTAS Brings Smart Home Experience to Apartments
Last month, we spoke with the co-founders of IOTAS, Sce Pike, CEO and Jeremy Steinhauer, VP of Data Services and learned how multi-family residential buildings, otherwise known as apartments, have recently stepped up their smart home game. IOTAS, which stands for IoT as a Service, has been a key player in making this happen after creating a smart home platform for apartment renters several years ago. The platform, built for residents, property owners and installers, provides residents with a seamless IoT solution that monitors apartment unit systems, including thermostats, motion detectors, security and lighting. The solution is so easy to use renters have been asking to take it with them when moving out of their apartment.
IOTAS has grown rapidly since its inception four years ago and was recently recognized by the Bay Area’s Start-up Grind as the 2019 Start-up of the Year. The company’s install base has grown to 100,000 smart devices in more than 70 communities.
Read more below about our conversation with IOTAS and how the company tapped into a major new market opportunity for smart home technologies.
How did IOTAS get started?
Sce: In 2014, a real estate developer in Portland approached me and explained he was looking for technology differentiation for his apartment property. My background is in mobile design development, and I had recently sold my first mobile consumer company, so the idea of focusing on the technology experience in the real estate market was intriguing. I quickly realized the $5 billion real estate market had the potential to scale a new technology extremely fast.
I went ahead and recruited Jeremy as my co-founder and we immediately built out a technology solution focused exclusively on apartments. We installed 40 smart home devices in a 1,000 square foot apartment unit to create a true smart home experience, not something that was cumbersome to put together. We wanted to create a move-in ready solution that just worked. We then took the idea out on a real estate conference roadshow, and it became obvious fast that we had created the next amenity commercial property owners were seeking. Property owners knew they had to provide technological advancements in their buildings to meet the demands of millennials and GenZ.
Once we received this feedback, we scaled the solution exponentially over the next few years, with our installs growing by 500 percent last year alone. We see the potential of disruption for all multi-family properties within five years, with all of them having some level of smart technology.
How did the real estate market know they needed this?
Sce: The real estate industry is 13 percent of the U.S. GDP and does a great deal of collective research. Property companies understand their own demographic very well, and at the time they were seeing technology become pervasive across their tenants’ lives, but the shift wasn’t reflected in apartment buildings. The industry saw this void as an opportunity to create an edge for their properties. Five years ago, when we first entered the market, the conferences were only starting to talk about smart home technology, but now smart apartments are mainstream, and the vast majority of properties are allocating budgets to incorporate smart home technologies.
Tell me about your product.
Jeremy: We’re focused on making the smart home experience extremely easy for residents and property managers. We work with property developers and managers to install smart devices in apartments with a suite of applications, including door locks, thermostats, light switches, power outlets and sensors to monitor leaks, motion, temperature, etc. Residents simply download the app to their phone and get a smart home out of the box. We also created automated defaults, like “out for the day” or “welcome home,” which set up preferred systems for that specific time period.
The second application is geared towards property managers to improve efficiencies – it’s the tool managers use to link the residential units and create their own automations for vacant units, such as temperature, appliances and lighting. Property managers can use it to immediately set-up for tours of certain units by turning on lights, setting the thermostat to a comfortable temperature, etc. on and off before or after. The application also has alerts for property managers if something is amiss, such as extremely high or low temperatures or humidity levels for vacant units.
The third application is the installer and/or auto-provisioning application. During our initial foray into smart apartment, we were installing 40 devices and quickly learned that commissioning that many devices to a gateway was a painful process and not scalable. We then spent the next few years perfecting the provisioning process. Now we have several auto-provisioning patents, where we have reduced the time to install devices for an installer from one hour to 15 minutes.
The final application is our internal application – how we administrate the system and create the data around the buildings and users.
Have you ever thought about going beyond multi-family homes?
Sce: From the onset, we have been focused on the multi-family market, for a variety of reasons. The economy of scale is a big reason – we didn’t want to sell one device at a time, we wanted to sell to buildings and make installations quickly. It’s much easier to design a solution for multiple homogenous units versus custom homes.
Though we have had many residents leave their apartments and ask how they can take IOTAS with them – so much so, that we’re now working on a way for residents to be able to upgrade their systems and go on a subscription basis to take IOTAS into their new home. This new solution is on our roadmap and we’re hoping to offer it by the end of this year.
How does Silicon Labs fit into your product?
Right now, we’re using the Z-Wave 500 Series Module solution and we are using the Z-Wave 700 Series for our next generation product to be rolled out later this year. We’re also considering using Zigbee in the future for wireless, so we’re using a Silicon Labs Zigbee module as we figure out a potential software stack for a Zigbee-based application. All of the end nodes are controlled by Z-Wave; we don’t have any internal connections over Wi-Fi. The Wi-Fi is purely used to connect the hub to our cloud.
Why did you decide to use the Z-Wave hub?
Jeremy: We started with Zigbee, but the standards were not there yet, as the devices weren’t all interoperable. The decision to use Z-Wave was also driven by the cost of each product. Having the ability to work with something like Z-Wave right out of the box with standardized protocols was a big selling point, as well.
Where do you IoT going in the next 5-8 years?
Jeremy: We’re extremely focused on the user experience, and we knew early on that we didn’t just want to be remote control for the home. In that same vein, I think that’s where IoT is headed – the more interconnectivity among devices, the richer the home experience can be. We see this going beyond the home, where people can take the experience with them. The smart home experience isn’t just about building profiles around people within the four walls that they live in, but taking the experience everywhere they go in the living world, such as their car, workplace, hotels, and even vacations.
Kernel 201: Implementing a Software Watchdog
This blog is part of the Kernel 201: Designing a Dynamic Multiprotocol Application with Micrium OS. The table of contents for this blog series can be found here.
Note: It is recommended to download the Kernel 201 application and have the code in front of you as you go through this blog post. The code can be downloaded on the Kernel 201: Project Resources page.
Introduction
There are different levels of safety to consider when developing a real-time system.
Safety Critical
Non-Safety Critical
Even though a majority of products may fall under the non-safety critical system category, it doesn’t mean a safety critical design pattern shouldn’t be considered when developing a real-time system. Designing an application using safety critical components can make a product more robust and reliable.
There are two properties of a system that are commonly considered in safety critical designs:
These two properties are not mutually exclusive. A system that is considered safe may fail as long as it is able to recover and operate in a manner that does not cause accidents; it is just considered unreliable. On the other hand, a system that can continue to run without error but operates unsafely is a reliable, but unsafe system.
There are many software architectural patterns that a developer can use to help improve a system’s safety and reliability. While the main focus of this article is on one specific pattern (Watchdog Pattern), these are a few other patterns you may come across when researching safety critical design:
This article will focus on implementing a watchdog pattern using a mix of software and hardware.
Hardware Watchdog
A standard feature on EFM32 and EFR32 microcontrollers is a hardware watchdog. The hardware watchdog is a timer that when enabled, constantly counts up. The watchdog timer has a user configured timeout value that the application is responsible for “feeding” (clearing) the watchdog counter before the counter reaches that value. If the watchdog reaches the configured time value, a system reset will occur. The assumption is because the application did not feed the watchdog in time, an error has occurred in the system and it must be reset.
The hardware watchdog pattern works well for super-loop applications or in RTOS applications where only one task needs to be monitored and a system-wide reset would not negatively affect other tasks in the system. Complications arise when you wish to ensure multiple tasks are running as expected. One way to solve this problem is to implement a software watchdog that is responsible for handling the hardware watchdog.
This is a simplified overview of the hardware watchdog timer available on EFM32 and EFR32. For more detailed on the EFM32 & EFR32 watchdog timers, Series 0 can be found here and Series 1 can be found here.
Software Watchdog
A software watchdog pattern is a safety design pattern that allows for the monitoring of multiple tasks in an RTOS application. It is typically used in conjunction with a hardware watchdog, but in cases where a hardware watchdog is not available, the software watchdog can be responsible for performing the system reset.
Micrium OS Kernel provides two different kernel services that can be used to implement a software watchdog: Event Flags and Message Queues. For applications that have 32 tasks or less, an Event Flag is an ideal kernel service to use due to the Event Flag being able to monitor 32 unique bits. For applications with more than 32 tasks to be monitored, either multiple flag groups are needed or tasks can send unique values via a Message Queue to periodically check in.
In the image above, each task is represented with a unique bit in the Event Flag Group. The Event Flag is configured to pend on almost all bits of the Event Flag Group and has a timeout configured. If every task posts to the Event Flag before the timeout value is reached, the Event Flag pend returns with RTOS_ERR_NONE, the software watchdog will feed the hardware watchdog and then call pend on the Event Flag again.
If one or more tasks do not post to the Event Flag before the timeout value is reached, the Event Flag pend will return with RTOS_ERR_TIMEOUT. Also, the return value of the pend call will tell you what tasks have and have not checked in. Then with that information the software watchdog can make the decision on whether or not it should feed the hardware watchdog or let it reset the system.
Implementing a Software Watchdog in the Kernel 201 Application
The rest of this article will refer to the Kernel 201 Dynamic Multiprotocol Application. It is recommended to download the project to follow along. There are three files related to the software watchdog implementation: lab.h, lab_main.c and lab_wdog.c.
lab.h
The lab.h file is the centralized location for the application’s configuration parameters such as task priorities, stack sizes, message structures and enums. More detail on lab.h can be found in the blog Kernel 201: Task Architecture & Communication.
The defines above can be found in lab.h and are used as unique identifiers for each task in the system that will be monitored by the software watchdog. Each value will represent a bit in the Event Flag Group bitfield.
lab_main.c
When Micrium OS Kernel is initialized and started in main(), its common to only create one task before calling OSStart(). This is typically done to allow for the statistics task to get a baseline reading of the system at idle before other tasks are created.
In many sample applications the first task created is called the startup task because it is responsible for creating the rest of the tasks in the system and “starting up” the application. This is a poor naming choice for a task as after the startup task creates the other tasks in the system, some examples delete the startup task. What many do not realize is calling OSTaskDel() does not free up any resources related to the task. If the application does not know to access the startup task's stack and TCB, that memory sits unused.
It is not recommended to call OSTaskDel() on startup tasks. A better solution is to use the task for monitoring the system or repurpose the task for another task in the system.
Instead of calling it a startup task, the Kernel 201 Application calls it a system task. It could also be called the watchdog task since the software watchdog will run out of the system task. After the application has been initialized and all of the other tasks have been created, the last call in the labSystemTask function is:
Rather than creating a new task for the watchdog, the application uses the system task to run the watchdog.
lab_wdog.c
The software watchdog file is very straightforward with only three functions: labWDOGInit(), labWDOGTask() and labWDOGFeed().
labWDOGInit()
The init function initializes the hardware watchdog (but does not enable it yet) and creates the Event Flag for the software watchdog.
labWDOGTask()
The software watchdog task operates as follows:
The watchdog pends on the specified task flags as seen in lab.h, and the pend includes a timeout. If all tasks call a flag post at least once before the timeout value is reached, the OSFlagPend() call returns with RTOS_ERR_NONE, the hardware watchdog is fed via WDOG_Feed() and it loops around and starts the pend over again.
If one or more tasks fail to check in, the return value will be RTOS_ERR_TIMEOUT. In this example the code will then sit in a while(1) until the hardware watchdog resets the system. This would be the ideal location to either add logic to see what flags did or did not check in, and also to add a flag to persistent memory so when the system does reset, it can see on boot that it reset due to an error.
labWDOGFeed()
The feed function is provided so all tasks do not need to have a reference to the Watchdog Event Flag. When tasks check in they just need to provide their identifier defined in lab.h. Since a flag group bit can only be 0 or 1, it does not matter if a task checks in once or multiple times each pend cycle.
Since every task is centered around a Message Queue, the timeout parameter on the message queue is set to a value less than the watchdog flag group to ensure that each task feeds the watchdog before the watchdog timeout.
Final Thoughts
One downside to this pattern is it does not work well with a low-power, battery operated system where you may want to sleep for longer periods of time than the hardware watchdog can handle. However, if power is not a concern the software watchdog pattern provides a simple way to ensure all tasks in an RTOS application are operating as expected. If you have any questions or comments, feel free to leave them below.
Kernel 201: Project Resources
This blog is part of the Kernel 201: Designing a Dynamic Multiprotocol Application with Micrium OS. The table of contents for this blog series can be found here.
Kernel 201 Application
Hardware: https://www.silabs.com/products/development-tools/thunderboard/thunderboard-sense-two-kit
SDK Requirements: Gecko SDK Suite 2.5.5, Bluetooth 2.11.5, Flex 2.5.5, MCU 5.7.3, Micrium OS Kernel 5.6
SLS Project File: https://www.dropbox.com/s/8cupsgovf0f7odq/kernel201.sls?dl=0
Kernel 201 Instructor Application
Hardware: https://www.silabs.com/products/development-tools/wireless/bluetooth/blue-gecko-bluetooth-low-energy-soc-starter-kit
SDK Requirements: Gecko SDK Suite 2.5.5, Flex 2.5.5, MCU 5.7.3, Micrium OS Kernel 5.6
SLS Project File: https://www.dropbox.com/s/u6a25v38mpdm1fl/kernel201_rail.sls?dl=0
WebBluetooth Application
Live webpage: https://kernel201.micrium.com
Zip File: https://www.dropbox.com/s/j4tlgmqvge8p4g3/kernel-201-web.zip?dl=0
Electron Application
Zip File: https://www.dropbox.com/s/s98rsobqqhfr5wk/kernel-201-instructor-app.zip?dl=0
Kernel 201: Task Architecture & Communication
This blog is part of the Kernel 201: Designing a Dynamic Multiprotocol Application with Micrium OS. The table of contents for this blog series can be found here.
Note: It is recommended to download the Kernel 201 application and have the code in front of you as you go through this blog post. The code can be downloaded on the Kernel 201: Project Resources page.
Task Architecture
The first step of designing any real-time system, before writing any code, is to identify all events the system will be responsible for. Listing out these actions will help identify what events may be grouped together in tasks and what actions will require their own task/s. There are a number of resources available that discuss different task modeling strategies. Some common strategies you may come across are:
For this application, these are the following events that must be handled and how they’ll be grouped into tasks:
labBluetoothTask
Silicon Labs’ Bluetooth stack already creates two tasks, Bluetooth and LinkLayer to handle the transmission and reception. The Bluetooth task provides callbacks for the user to implement to know when there is an event to process. The labBluetoothTask will handle those events from the Bluetooth task and pass that data along to the other tasks in the system. The labBluetoothTask will also receive data from other tasks in the system to transmit via Bluetooth.
labPropTask
Silicon Labs does not provide internal tasks for Proprietary Wireless (RAIL) as it does for Bluetooth, but it is important to group the RAIL functions together as they are not thread-safe functions. The labPropTask will handle all data received by RAIL and send it to other tasks in the system as needed. It will also receive data from other tasks in the system and send it out via RAIL.
labLEDTask
Since only the GPIO or RGB LEDs can be active at one time, it makes sense to group them together.
labBtnTask
The button task operates on a low priority polling interval. It could be switched to an interrupt based task but by leaving it as a polling task, it leaves open the option to add other polling events to the task in the future.
labWDOGTask
The watchdog task will implement a software based watchdog to control how the system feeds the hardware watchdog. It is important that this task have no other operations than handling the watchdog.
Task Communication
Now that the events have been divided up into their respective tasks, it is important to implement a consistent method for communication between tasks. There are again many different ways to implement task communication. Micrium OS Kernel provides Semaphores, Task Semaphores, Event Flags, Message Queues and Task Message Queues. While each of these kernel objects have various pros and cons, no one of these services is better than another; it just depends on the application and how it is using these kernel services.
For this application, each task (with the exception of the watchdog task) will be centered around a Task Message Queue and the entire application will use a sort-of layered messaging scheme, similar to the OSI model but much more simplified. The main loop of each task will pend on a Task Message Queue and wait for a message or timeout to determine its next action.
The image above shows the basic layout for all tasks in the system. The code snippet below shows some pseudocode for the task
By using the Task Message Queue, it allows a task to wait on three different types of events:
Timeouts
The software watchdog wants every task to check in on a specified rate to show it has not gone out to lunch. By specifying a timeout value in the Task Message Queue pend, the pend call will return with RTOS_ERR_TIMEOUT if a message is not received in the specified time. If a task expects a message in a set time interval, logic can also be added to the error check for RTOS_ERR_TIMEOUT to keep track of how many timeouts we receive in a row.
Events
Some tasks may have a hardware interrupt or software timer callback they need to handle in addition to processing messages from other tasks in the system. The msg_size data field in OSTaskQPend() provides a 32-bit value that is used as an identifier field for this task design. When a task receives a message, it will have a switch statement to handle the value of msg_size. In this application, all message identifiers can be found in an enum called LAB_Q_ID_e.
When an interrupt or software timer callback wants to send a message to the task it is associated with, it will make a call similar to the one below:
It is important to note that the LAB_Q_ID_e value is specified in the msg_size field and not the void* field. All messages sent must have a valid identifier in the msg_size field where the void* argument is optional. In this case, the void* argument is set to 0 as there is no extra data to send.
Lab Messages
These messages are how tasks communicate with each other in this application. Rather than having the Bluetooth or Proprietary Wireless tasks spend time configuring PWM timers to drive the RGB LEDs, it makes more sense to send the LED task a LED command to be processed. This also allows us to handle wireless communication at a higher priority than changing the LEDs or polling the button states. The wireless tasks may be affected if responses are not sent out at specific intervals where if the system has to wait an extra 10ms to toggle the LED, the user most likely won’t notice.
The lab messages follow a layered model where every message has the same header, the header defines what else is to follow in the packet. This application provides utility functions for getting, sending and freeing messages (refer to lab_util.c). There are advantages to these utility functions that will be discussed a little later. When you get/free a message you are actually pulling from a memory pool of fixed block sizes. All messages, regardless of how much of the block they use, are the same size. In the case of this application, all messages are 32 bytes in size. This means that if a task needs to send or receive a message larger than 32 bytes, either the size of every block in the system must be increased, multiple messages must be sent or modifications must be made to the utility functions to allow for allocation and freeing of different size blocks.
The struct above shows the lab message structure that all messages will start with. The ID field identifies what message will follow it and the type corresponds to if it’s a command, response, update or error message. The void* argument is used so you can cast the next layer to the end of the lab message struct.
When you wish to allocate a message to send, the code snippet above shows how you would use the labUtil function to allocate a message. The image below shows how the lab message fits into the allocated block.
After you configure the message ID and message type fields, you need to configure the next part of the block for the message ID you specified. For this example, let’s assume we’re changing the LEDs. LEDs are controlled by the LAB_LED_MSG_s struct. To accomplish this, you will cast the LAB_LED_MSG_s to p_data so when you enter information for the LED message, it goes into the correct location in lab message.
The code snippet above shows how to cast the p_data argument to the LED message structure. Now when you modify the fields of the LED message structure it will be aligned in the message block as shown below.
Once the full message is assembled, the message needs to be sent to the desired task/s. Some messages may only go to one task where others may need to be sent to multiple tasks. The lab utility function for sending offers flexibility for sending messages. Using the labUtilSend() function as shown below, you pass the pointer to the message block just configured and the task/s the message should be sent to.
In the case where one message is being sent to multiple tasks, the send function will keep track of the number of tasks it was sent to. This allows each task to call the free function after its processed the message, but the memory block is not actually freed until all tasks that received the message free it. To free a message all a task needs to do is make the following call:
It is the labUtilMsgFree function's job to determine when the message is actually returned to the message pool. If one task never calls free on the message it received, that block will never be freed and that memory will be lost so it is imperative that all tasks free all messages they receive, even if they receive the message in error.
Final Thoughts
This wraps up the Task Communication and Architecture section of the Kernel 201 application. Moving forward the Bluetooth, Proprietary Wireless, LED and Button tasks will all be using this communication structure. If you have any questions about this post feel free to leave comments below.
Kernel 201: Configuring Micrium OS
This blog is part of the Kernel 201: Designing a Dynamic Multiprotocol Application with Micrium OS. The table of contents for this blog series can be found here.
Note: It is recommended to download the Kernel 201 application and have the code in front of you as you go through this blog post. The code can be downloaded on the Kernel 201: Project Resources page.
Introduction
Micrium OS offers default configurations to allow a user to get started quickly. These configurations are useful for quick starts, test applications and instances where memory is not a constraint. It is important that all developers using Micrium OS do give some attention to the RTOS configuration as the defaults are not ideal for a released application.
To ensure the dynamic multiprotocol application starts off on a good foot, one of the first steps that will be taken is to configure Micrium OS. Most of the sample applications available in Simplicity Studio provide a good starting point, but this post will look a little more in-depth at the configuration that’s available.
Micrium OS Configuration Files
os_cfg.h
Note: Some example projects have already made modifications to os_cfg.h. The comments here are based on differences between the default os_cfg.h found in the Gecko SDK Micrium OS directory and this project.
This file provides all compile-time options for Micrium OS Kernel. It provides the ability to turn on and off almost all parts of the kernel. Typically, the default values are fine to start a project out with. In this project there are a few differences from the default config worth highlighting:
App Hooks
App hooks enable will turn on the callback functions (if one is defined) anytime the following events occur:
The hook that is set up in most projects is the idle task hook. Since this hook is called from the idle task loop, it is an ideal time to enter a lower power mode. Right now the kernel can run from EM0, EM1 or EM2 (EM2 requires use of the LFRCO).
Dynamic Tick
Dynamic tick allows the kernel to adjust the tick rate as needed to minimize the amount of time the kernel has to wake from sleep. The images below show the advantage of using dynamic tick over a periodic tick.
Periodic Tick
Dynamic Tick
Priority Maximum
The PRIO_MAX setting controls the maximum number of task priorities allowed in the system. Micrium OS supports an unlimited* number of task priorities but there are advantages of having the value set to a smaller number.
If a system only has 10 tasks, there is an advantage to setting PRIO_MAX to 32 vs 64, 128, 256, 512 or some other very large number. The way the kernel’s scheduler looks for the next available task is it has an array called OSPrioTbl[] which is defined as follows:
Each bit in the PrioTbl corresponds to a task priority so since each row holds 32 bits, that’s 32 priority levels that can be checked in one go. If PRIO_MAX is set to 512, the kernel will potentially have to go through 16 rows before deciding to drop to the idle task. That’s a lot of extra overhead for task priorities that are not being used.
*Hardware provides the limitation, there is no limitation in software.
OSTaskDel
The OSTaskDel() should be disabled by default in almost all Micrium OS applications. Deleting a task only removes it from the kernel so it is no longer scheduled. It does not take into account any kernel objects associated with the task nor does it free up any memory associated with the task being deleted. There are very few situations where OSTaskDel() is needed.
common_cfg.h
The common_cfg.h file is used to configure the memory, string and clock modules. The defaults for string and clock are fine for this project, but since the goal of this project is to reduce the kernel’s footprint the memory will be adjusted.
By default the kernel uses an internal heap to allocate space for internal tasks and message queues. By making the following change to the heap size, it will turn off the internal heap.
If this was the only change is made to the project, the project would compile but fail immediately during runtime when OSInit() is called due to no memory being available. A change also has to be made in rtos_cfg.h to disable the use of the internal heap for internal tasks and message queues.
rtos_cfg.h
The rtos_cfg.h file controls three things:
Assert configuration
Memory usage configuration for internal tasks and message queues
The assert configuration defaults to locking the system in a while(1) loop for debug and critical asserts. The debug asserts should be modified when going into production but for development it can be useful to leave the while(1) loop to find issues quicker.
The logging is an optional module that is not used in this project.
The Default Config configuration is what determines if the heap is used for internal tasks or not. By making the following change, it will require that a number of internal structures are externally configured. This will allow for the kernel to operate with the heap being set to 0.
rtos_description.h
This file defines what Micrium OS modules are enabled. For this project only two defines are needed:
A full list of available RTOS_MODULE options can be found in the Gecko SDK version of rtos_description.h.
Main Configuration
Once the changes have been made to the necessary config files, the desired kernel configuration must be made in the application. In this example, the file lab_main.c has the following kernel configuration.
Tick Task
The tick task is used to control the kernel’s system tick which is used for time delay calls and pend timeouts. In this application it is based off of the RTCC interrupt. The following configuration will define a stack for the tick task and set the config only if OS_CFG_TASK_TICK_EN is set in the os_cfg.h file. The stack size, priority and frequency of the tick task are all configured in the lab.h file.
Idle Task
The idle task is the lowest priority task in the system. When the kernel has no other tasks to schedule, it will run the Idle Task. When entering the Idle Task, there is a hook function that can be implemented to allow the user application to enter a lower power mode. The following configuration will define a stack for the idle task and set the config only if OS_CFG_TASK_IDLE_EN is set in the os_cfg.h file. If the idle task is not enabled, when the current task finishes the scheduler sits in a while(1) loop until another action happens in the system rather than jump to a different task. When the idle task is enabled the stack size of the idle task can be found in lab.h. You can not set the priority of the idle task because it must always be the lowest priority task in the system.
Timer Task
The timer task is used to control Micrium OS Kernel’s software timers. The reason the timers operate in a different task than the tick task is the timer callback functions are made from the timer task, so it allows the timer callbacks to run at a different priority than the tick task if desired. The following configuration will define a stack and set the config only if OS_CFG_TMR_ EN is enabled in the os_cfg.h file. The stack size, priority and frequency of the timer task are all configured in the lab.h file.
Stat Task
The stat task is an internal task that provides such run-time statistics as overall CPU utilization (0.00 to 100.00%), per-task CPU utilization (0.00 to 100.00%), and per-task stack usage. The following configuration will define a stack and set the config only if OS_CFG_STAT_TASK_EN is enabled in the os_cfg.h file. The stack size, priority and frequency of the stat task are all configured in the lab.h file.
Interrupt Stack
The ARM Cortex-M series has a separate stack for interrupts to execute out of. Micrium OS Kernel will configure the stack location during the OSInit() call, but a stack must be provided. The following configuration creates the interrupt stack and sets the necessary configuration. This is not an optional configuration, it is required of all Micrium OS Kernel applications.
Message Pool
If message queues will be used in an application (this application makes heavy use of them) then a message pool must be defined. When messages are sent in either a message queue or task message queue, a message pool object is allocated to hold the data being sent (void* argument and message size argument). The message pool should have enough entries for every message queue entry in the application. For example, if you have 3 message queues each with 10 entries in them, you should have a message pool size of 30. The following configuration is used to specify the message pool size in this application.
In addition to specifying the configuration, a memory segment and memory buffer must be allocated as follows:
And finally, in the main() before OSInit() is called, the memory segment must be created so the kernel knows how to access the memory buffer specified above.
Putting it all together
You may have noticed that all of the configs are just #defines. These #defines are used to create one giant #define as shown below.
Once the OS_INIT_CFG_APP define is put assembled with all of the task and memory pool configs, the define should be assigned to the global variable as follows:
This variable is externed by the kernel so it must be named OSInitCfg as this is what the kernel uses internally.
Final Thoughts
While it may appear a little complicated, the configuration of Micrium OS Kernel is very important to the success of an application and worth the extra effort. A misconfigured kernel can cause issues farther down the road so it is important to configure it correctly to start with. By removing the general purpose heap it allows the developer to have a full understanding of what's going on under the hood so there is no confusion about how the kernel is configured. If you have any questions or comments feel free to leave them below.