This KB shows an implementation of an interrupt based asynchronous mode configuration of the U(S)ART peripheral for RS-232.
The development kit doesn’t include RS-232 line drivers, so ensure that signal levels are compatible before establishing a communication link between two parties. Connecting the EFR32 UART directly to a PC serial port will damage the EFR32.
In order to implement UART into the Z-Wave framework, we will be using USART API from EMLIB.
We open the UART connection with Baud Rate 115200 bps, and in this example we only enable RX.
Step 6: UART Interrupt handler
In the PRIVATE FUNCTIONS section add a circular buffer and a function USART1_RX_IRQHandler().
/*
* USART1 RX example
* - inspired by AN0045 main.c (https://www.silabs.com/documents/public/example-code/an0045-efm32-uart-rs-232.zip)
*
* WSTK EXP Connector Pin configuration:
* GND : 1
* USART1 RX : 10
* USART1 TX : 13
*
* Baud rate: 115200
*/
/* Declare a circular buffer structure to use for Rx queue */
#define BUFFERSIZE 256
static USART_TypeDef *uart = USART1;
volatile struct circularBuffer
{
uint8_t data[BUFFERSIZE]; /* data buffer */
uint32_t rdI; /* read index */
uint32_t wrI; /* write index */
uint32_t pendingBytes; /* count of how many bytes are not yet handled */
bool overflow; /* buffer overflow indicator */
} rxBuf = { {0}, 0, 0, 0, false };
/*
* USART1 RX interrupt handler
*
* Must follow the naming defined startup_efr32fg13p.c
* (See also: https://www.silabs.com/community/mcu/32-bit/knowledge-base.entry.html/2014/11/19/efm32_isr_naming-Azu3)
*/
void USART1_RX_IRQHandler(void)
{
/* Check for RX data valid interrupt */
if (uart->STATUS & USART_STATUS_RXDATAV)
{
/* Copy data into RX Buffer */
uint8_t rxData = USART_Rx(uart);
rxBuf.data[rxBuf.wrI] = rxData;
rxBuf.wrI = (rxBuf.wrI + 1) % BUFFERSIZE;
rxBuf.pendingBytes++;
/* Flag Rx overflow */
if (rxBuf.pendingBytes > BUFFERSIZE)
{
rxBuf.overflow = true;
}
DPRINTF("%c", rxData); // Print the received character to debug output
//
// Put code here to send event/data to application task
//
/* Clear RXDATAV interrupt */
USART_IntClear(USART1, USART_IF_RXDATAV);
}
}
When an RXDATAV interrupt is received, the Rx interrupt handler copies the incoming data to a receive queue.
UART1_RX_IRQHandler() reacts on the RXDATAV interrupt, meaning that the UART RX buffer contains valid data. When this happens, the incoming byte is copied from the UART RX buffer into the RX queue. The queue write index (wrI) is updated, and the pending byte counter is incremented. The IRQ handler will also disable the TXBL interrupt if the transmit queue becomes empty
Step 7: Build solution and test
Build the solution and flash the new firmware image to the device.
If you enable serial debug output, you are now ready to receive input on the UART RX line.
Step 8: Port and Pin used for RX / TX.
The UART1 pins are defined in extension_board_8029a.h, and the pins are configured as:
In document “DSH14476 - UG381: ZGM130S Zen Gecko Wireless Starter Kit User's Guide” we can map the port and pin to a connection on the development hardware. From section 3.4.1 EXP Header Pinout we learn that:
TX Pin: Connection F3 is connected to EXP Header Pin 13.
RX Pin: Connection C9 is connected to EXP Header Pin 10.
Step 9: Connect a USB to TTL cable
We will be using a USB – TTL cable.
Connect the RX wire from the cable to the TX pin on header 13.
Connect the TX wire from the cable to the RX pin on header 10.
Step 10: Use a terminal program to connect
Use your preferred terminal program, e.g. PuTTY or Tera Term and connect to the virtual COM port for your USB – TTL adapter. Connect with Baud Rate 115200 bps.
Step 11: Run and test the solution.
Everything is now setup and we are ready to start sending data from our terminal program. When our device receive data on UART1, it will print it to the debug log on UART0.
Closing comments
This KB is a quick demonstration in how to add support for U(S)ART in the Z-Wave Framework using the EMLIB library.
This example is not really using the received data, but simply prints it on the debug UART port.
When starting to use the received data, the RX interrupt should invoke ZAF_EventHelperEventEnqueueFromISR() with an event defined in the application, e.g.
EVENT_APP_UART_RX, because it allows the chip to sleep between interrupts.
INS14280 - Getting Started for End Device This document also describes how to setup the Z-Wave region and serial debug, which is not covered by this KB.
INS14259 - Z-Wave Plus V2 Application Framework SDK7
UG381: ZGM130S Zen Gecko Wireless Starter Kit User's Guide
This KB will be using the AppTimer module from the Z-Wave Framework. This module is further documented in document INS14259 - Z-Wave Plus V2 Application Framework SDK7 (available in Simplicity Studio).
All software timers are essentially FreeRTOS timers. Using the AppTimer module, you ensure that timer callback functions are executed in the context of the application task.
Step 1: Continuing on an example
This KB continues on the I2C example. It is suggested to complete that exercise in order to see the full effect of implementing the timer – it is however not required and this guide will instruct how to continue if not using I2C in the relevant steps.
Step 2: SSwTimer instance
To start using application timers, you need a SSwTimer instance. In the PRIVATE DATA section, add a SSwTimer instance.
When the timer fires, we want our callback function to enqueue an event to our state machine. Thus we need to add a new event in the _EVENT_APP_ typdedef. We call this event EVENT_APP_TEMPERATURE.
Step 6: Update the state machine to listen for the event
In the AppStateManager(), find the state called STATE_APP_IDLE. In this state, create a new if-case and perform the temperature measurement if EVENT_APP_TEMPERATURE event is received.
// ACTION: Perform temperature measurement on timer event
if (EVENT_APP_TEMPERATURE)
{
uint32_t rhData;
int32_t tempData;
// Get temperature and humidity reading from on-board sensor
performMeasurements(i2cInit.port, &rhData, &tempData);
DPRINTF("\r\nHumidity: %d", rhData);
DPRINTF("\r\nTemperature: %i\r\n", tempData);
}
Note: In this step, we are calling performMeasurements(). This function is part of the I2C example. You can leave out this function call, and just verify in the debug log that the event is called once every second.
Step 7: Build solution and test
Build the solution and flash the new firmware image to the device.
If you enable serial debug output, you should now see that we get the TemperatureTimerCallback() and that results in a temperature and humidity reading.
INS14280 - Getting Started for End Device This document also describes how to setup the Z-Wave region and serial debug, which is not covered by this KB.
INS14259 - Z-Wave Plus V2 Application Framework SDK7 Refer to section 7.7 for more information on the Timer module.
UG381: ZGM130S Zen Gecko Wireless Starter Kit User's Guide
This KB shows an implementation of a SPI Master application, because most use cases involve connecting a SPI Slave device, e.g. a sensor, to the Z-Wave device.
In order to implement SPI into the Z-Wave framework, we will be using the SPIDRV API from EMDRV. In this KB, we will be implementing the SPI example from the SPIDRV documentation page.
Step 1: Include header files
You need to include the following header files to the search path of the project.
A) Go to project properties => C/C++ General => Paths and Symbols
B) In the 'Includes' tab, add the two include paths listed below to both 'Assembly' and 'GNU C'
C) Apply the settings and click 'Yes' in the dialog to rebuild.
D) Click OK to close the properties window.
The needed include paths are:
spidrv.h
Include path: ${StudioSdkPath}/platform/emdrv/spidrv/inc
Add the following include to the main file of the Z-Wave Sample App you are using.
#include <spidrv.h>
Step 4: Setup for Master
A) In spidrv_config.h (referenced in spidrv.h), locate the define EMDRV_SPIDRV_INCLUDE_SLAVE and place your cursor.
B) Uncomment this line by start typing “/”.
C) This opens a dialog. In this dialog select “Make a Copy”. This will make a copy of the header file and move it to the local project location, because we are now editing a file in the SDK.
D) Finish uncommenting EMDRV_SPIDRV_INCLUDE_SLAVE
// SPIDRV configuration option. Use this define to include the slave part of the SPIDRV API.
//#define EMDRV_SPIDRV_INCLUDE_SLAVE
Step 5: Build solution
Now build the solution. If everything went well when adding include paths and linking to source files, you should not get any build errors.
Step 6: Setup SPI
A) In the PRIVATE DATA section, add the SPI handle
In ApplicationInit(), initialize the SPI driver just before the call to ZW_ApplicationRegisterTask.
Since we will be using the Z-Wave serial debugging interface as well, we will setup SPI to use USART1.
In addition, we will also try to transmit data using a blocking transmit function and using a callback to catch the transfer completion.
// ACTION: Init SPI and send buffer.
uint8_t buffer[10];
SPIDRV_Init_t initData = SPIDRV_MASTER_USART1;
// Initialize a SPI driver instance
SPIDRV_Init( handle, &initData );
// Example: Transmit data using a blocking transmit function
if(SPIDRV_MTransmitB( handle, buffer, 10 ) == 0)
DPRINT("SPI Transfer Blocking Success\r\n");
// Example: Transmit data using a callback to catch transfer completion.
SPIDRV_MTransmit( handle, buffer, 10, TransferComplete );
Step 8: Build solution and test
Build the solution and flash the new firmware image to the device.
If you enable serial debug output, you should now see that we are successfully sending data.
Closing comments
This KB is a quick demonstration in how to add support for SPI in the Z-Wave Framework.
This implementation just sends out data in the ApplicationInit() function, but this should be done in an appropriate place depending on what functionality is needed.
A word on SPI Slave
The SPIDRV from EMDRV can also be setup as a slave. However, this implementation relies on the Real-time Clock Driver (RTCDRV). Because Z-Wave is using FreeRTOS as the underlying OS, it is not possible to use SPIDRV in Slave mode as it conflicts with how FreeRTOS uses the RTC.
As such, if you need to implement SPI Slave functionality in the Z-Wave framework, you need to use the lower-level USART driver from EMLIB.
INS14280 - Getting Started for End Device This document also describes how to setup the Z-Wave region and serial debug, which is not covered by this KB.
INS14259 - Z-Wave Plus V2 Application Framework SDK7
UG381: ZGM130S Zen Gecko Wireless Starter Kit User's Guide
In this KB, we will be using a Si7021 Relative Humidity and Temperature Sensor. This sensor is already mounted on the WSTK mainboard that is part of the Z-Wave 700 development kit. The sensor is briefly described in section 5.4 in document ZGM130S Zen Gecko Wireless Starter Kit User's Guide.
In order to implement I2C into the Z-Wave framework, we will be using the I2C API from EMLIB.
Since the same main development board is widely used amount the various Silabs boards, it is possible to find an example in the Gecko_SDK github reporsitory, called "humitemp":
The goal of this KB is to interface to the Si7021 sensor using the I2C API from EMLIB by following the "humitemp" example and demonstrates how to get I2C implemented in the Z-Wave framework.
Step 1: Include header files
You need to include the following header files to the search path of the project.
A) Go to project properties => C/C++ General => Paths and Symbols
B) In the 'Includes' tab, add the two include paths listed below with bold to both 'Assembly' and 'GNU C'
C) Apply the settings and click 'Yes' in the dialog to rebuild.
D) Click OK to close the properties window.
The needed include paths are:
i2cspm.h
Include path: ${StudioSdkPath}/hardware/kit/common/drivers
It is worth noting that em_i2c is also referenced to from i2cspm.h. This means, this example is based on the I2C API from EMLIB. The em_i2c.h is already in the include path, so we do not need to add it. For sake of completeness, the include path is:
${StudioSdkPath}/platform/emlib/inc (NB; no need to add, already in the added)
Step 2: Link the needed source files
With the header files added to the project, we need to link the source files.
A) Create a new folder in the Project Explore window of Simplicity Studio. Call this folder “Drivers”.
B) Right-Click on the Drivers folder and select New => File.
C) In the dialog that opens, click on Advanced.
D) Place a check mark in “Link to file in the file system”
E) Browse to the needed source file (see below).
F) Click Finish
You need to do the steps above (A-F) for the following source files:
Add the following include to the main file of the Z-Wave Sample App you are using.
#include "i2cspm.h"
#include "si7013.h"
Step 4: Build solution
Now build the solution. If everything went well when adding include paths and linking to source files, you should not get any build errors.
Step 5: Initialize I2C and Sensor
A: In the PRIVATE DATA section, add the I2C struct that contains a number of I2C configuration options.
// ACTION: I2C structure used for communication with I2C sensor
static I2CSPM_Init_TypeDef i2cInit = I2CSPM_INIT_DEFAULT;
B: In ApplicationInit() add the code from the main-file from "humitemp" example that initialize the hardware. Add this code just before the call to ZW_ApplicationRegisterTask.
You will get a warning because the function is currently unused. So, let’s try to use it.
Step 8: Tie it all together
We need to call the performMeasurements() function. You would normally make a temperature reading whenever a Multilevel Sensor Get Command has been received if you were to develop a Temperature Sensor.
In this KB, we use the Switch On Off sample application from the Z-Wave SDK. We want to make a measurement, whenever we turn on and off the LED and print it to the debug log.
Locate appBinarySwitchSet(). This function is called whenever a Binary Switch Set command is received on the Z-Wave radio.
After the call to RefreshMMI(), insert the code to call performMeasurements().
appBinarySwitchSet(
CMD_CLASS_BIN_SW_VAL val,
uint8_t duration,
uint8_t endpoint
)
{
UNUSED(endpoint);
UNUSED(duration); /* Ignore duration - for a binary switch only instant transitions make sense */
// ACTION: Variables used for temperature data
uint32_t rhData;
int32_t tempData;
DPRINTF("\r\nappBinarySwitchSet %u\r\n", val);
onOffState = val;
ApplicationData.onOffState = val;
writeAppData(&ApplicationData);
RefreshMMI();
// ACTION: Get temperature reading from on-board sensor
performMeasurements(i2cInit.port, &rhData, &tempData);
DPRINTF("\r\nHumidity: %d", rhData);
DPRINTF("\r\nTemperature: %i\r\n", tempData);
return E_CMD_HANDLER_RETURN_CODE_HANDLED;
}
Step 9: Build solution and see the result.
Build the solution and flash the new firmware image to the device.
Include the device into a Z-Wave network, e.g by using the PC Controller.
Closing comments
This KB is a quick demonstration in how to add support for I2C in the Z-Wave Framework. In the specific event of interacting with a Temperature & Humidity sensor, one should look into the Multilevel Sensor command class for reporting the value on the Z-Wave radio.
In addition, with this implementation, we only read out the temperature on requests. It is possible to use a timer to do a periodical readout, but this is not covered in this KB.
INS14280 - Getting Started for End Device This document also describes how to setup the Z-Wave region and serial debug, which is not covered by this KB.
INS14259 - Z-Wave Plus V2 Application Framework SDK7
UG381: ZGM130S Zen Gecko Wireless Starter Kit User's Guide
How do I generate the needed S2 Public/Private keypair and where are they stored?
Answer
The S2 Public/Private keypair and the responding QR code are all stored in the Lock Bits page with the following manufacturing tokes:
S2 Public Key: TOKEN_MFG_ZW_PUK
S2 Private Key: TOKEN_MFG_ZW_PRK
QR Code: TOKEN_MFG_ZW_QR_CODE
The Z-Wave application is responsible for calculating the S2 Public/Private keypair based on Curve25519, constructing the QR code based on the public key and writing these to the Lock Bits page.
When finish an additional manufacturing token is written to the Lock Bits page to symbolize the completion of this process.
Write completion of Lock Bits page: TOKEN_MFG_ZW_INITIALIZED
As such, this process is only started if the Lock Bits page is erased and the TOKEN_MFG_ZW_INITIALIZED is therefore not in place.
When this process has finished, it is possible to read out the QR code in order to generate the QR image to print on the product.
OTA capabilities are a mandatory feature for all Z-Wave 700 end-devices. The Z-Wave 700 Embedded Framework already implements the feature, but you need to make sure to flash the OTA bootloader and a set of encryption keys.
Example: Firmware update of Switch On Off Sample Application
It is worth knowing the following default locations:
Sample app location
C:\Users\almunkha\SimplicityStudio\v4_workspace\SwitchOnOff\GNU ARM v7.2.1 - Debug
The serial number / Device ID of the device must also be known (e.g. can be seen in Simplicity Studio). The board we are using in this example have ID 440147067.
--- Pre-work: KEYS Step A: Generate the needed keys
This generates 1 file in the same location as the commander
* vendor_encrypt.key
--- Pre-work: Create firmware for initial setup Step C: Using Simplicity Studio, open Switch On Off sample app and compile.
This generates a Hex file that we are flashing the device with for initial setup (will be covered in Step 6).
--- Setup device with bootloader and initial firmware
The Z-Wave chips ships without bootloader, so the first step is to prepare the chip with an OTA bootloader and the initial image we will firmware update.
Info: This step is not required. If you erase the Lock Bits page, a new set of S2 Private/Public key will be generated automatically by the application image. For more info on Lock Bits page, refer to Z-Wave 700: Where are the S2 keypair stored?.
In addition: If you do erase the Lock Bits page, then it is important to flash the bootloader (step 5) and the application image (step 6) before flashing the generated keys (step 7) just like instructed in this KB.
This generates 1 new file that we will be using for OTA update
* appname_mySwitch.gbl
--- And finally; the OTA update Step 12: OTA update
Use PC Controller to start OTA update using location for file appname_mySwitch.gbl.
When file is selected, click on 'Update' which starts the OTA update.
NB: If using the PC Controller for the OTA update, make sure to use version 5.38 or later.
--- RESULT
Firmware Update Md Status Report can be seen in both PC Controller GUI or in Zniffer trace.
Status 0xFF = success
Z-Wave Knowledge Base
Z-Wave 700: How to implement UART with interrupt into the Z-Wave Embedded Framework
How to implement interrupt based UART RS-232 into the Z-Wave Embedded Framework
Several peripheral drivers are available (EMDRV and EMLIB) and can be linked to the Z-Wave application. EMDRV exist on top of the lower level EMLIB.
The following resources are great places to look for more information:
Software Documentation (e.g., EMDRV and EMLIB)
32-bit Peripheral Examples (EMLIB)
This KB shows an implementation of an interrupt based asynchronous mode configuration of the U(S)ART peripheral for RS-232.
The development kit doesn’t include RS-232 line drivers, so ensure that signal levels are compatible before establishing a communication link between two parties. Connecting the EFR32 UART directly to a PC serial port will damage the EFR32.
In order to implement UART into the Z-Wave framework, we will be using USART API from EMLIB.
This guide builds on the Application Note AN0045 USART/UART - Asynchronous mode, but implemented into the Z-Wave Framework.
Step 1: Include header files
The include path for EMLIB is already defined in the project, so no actions are required for this step, this just serves a purpose of information.
The needed header file is:
Include path: ${StudioSdkPath}/platform/emlib/inc
Location:
C:\SiliconLabs\SimplicityStudio\v4_ga\developer\sdks\zwave\v7.11.0\platform\emlib\inc
Step 2: Link the needed source files
We need to link the source file to the project.
You need to do the steps above (A-F) for the following source files:
File location:
C:\SiliconLabs\SimplicityStudio\v4_ga\developer\sdks\zwave\v7.11.0\platform\emlib\src
Step 3: Include in Z-Wave framework
Add the following include to the main file of the Z-Wave Sample App you are using.
Step 4: Build solution
Now build the solution. If everything went well when adding include paths and linking to source files, you should not get any build errors.
Step 5: Initialize the UART and setup for interrupt based RX
In ApplicationInit(), initialize the UART driver just before the call to ZW_ApplicationRegisterTask.
We open the UART connection with Baud Rate 115200 bps, and in this example we only enable RX.
Step 6: UART Interrupt handler
In the PRIVATE FUNCTIONS section add a circular buffer and a function USART1_RX_IRQHandler().
When an RXDATAV interrupt is received, the Rx interrupt handler copies the incoming data to a receive queue.
UART1_RX_IRQHandler() reacts on the RXDATAV interrupt, meaning that the UART RX buffer contains valid data. When this happens, the incoming byte is copied from the UART RX buffer into the RX queue. The queue write index (wrI) is updated, and the pending byte counter is incremented. The IRQ handler will also disable the TXBL interrupt if the transmit queue becomes empty
Step 7: Build solution and test
Build the solution and flash the new firmware image to the device.
If you enable serial debug output, you are now ready to receive input on the UART RX line.
Step 8: Port and Pin used for RX / TX.
The UART1 pins are defined in extension_board_8029a.h, and the pins are configured as:
In document “DSH14476 - UG381: ZGM130S Zen Gecko Wireless Starter Kit User's Guide” we can map the port and pin to a connection on the development hardware. From section 3.4.1 EXP Header Pinout we learn that:
TX Pin: Connection F3 is connected to EXP Header Pin 13.
RX Pin: Connection C9 is connected to EXP Header Pin 10.
Step 9: Connect a USB to TTL cable
We will be using a USB – TTL cable.
Connect the RX wire from the cable to the TX pin on header 13.
Connect the TX wire from the cable to the RX pin on header 10.
Step 10: Use a terminal program to connect
Use your preferred terminal program, e.g. PuTTY or Tera Term and connect to the virtual COM port for your USB – TTL adapter. Connect with Baud Rate 115200 bps.
Step 11: Run and test the solution.
Everything is now setup and we are ready to start sending data from our terminal program. When our device receive data on UART1, it will print it to the debug log on UART0.
Closing comments
This KB is a quick demonstration in how to add support for U(S)ART in the Z-Wave Framework using the EMLIB library.
This example is not really using the received data, but simply prints it on the debug UART port.
When starting to use the received data, the RX interrupt should invoke ZAF_EventHelperEventEnqueueFromISR() with an event defined in the application, e.g.
EVENT_APP_UART_RX, because it allows the chip to sleep between interrupts.
The following KB demonstrates how to add a new event and use it in the Z-Wave State Machine.
Z-Wave 700: How to use Software Timers
Z-Wave 700 End-device framework KBs
Z-Wave 700: How to implement I2C into the Z-Wave Embedded Framework
Z-Wave 700: How to use Software Timers
Z-Wave 700: How to implement SPI into the Z-Wave Embedded Framework
Z-Wave 700: How to implement UART with interrupt into the Z-Wave Embedded Framework (this guide)
Linked documentation (found in Simplicity Studio)
This document also describes how to setup the Z-Wave region and serial debug, which is not covered by this KB.
Z-Wave 700: How to use Software Timers
How to use Software Timers
In this KB we will demonstrate an example of using a Software Timer to perform a temperature and humidity sensor reading once every second.
It is documented in KB Z-Wave 700: How to implement I2C into the Z-Wave Embedded Framework how to readout the temperature and humidity sensor reading using I2C.
This KB will be using the AppTimer module from the Z-Wave Framework. This module is further documented in document INS14259 - Z-Wave Plus V2 Application Framework SDK7 (available in Simplicity Studio).
All software timers are essentially FreeRTOS timers. Using the AppTimer module, you ensure that timer callback functions are executed in the context of the application task.
Step 1: Continuing on an example
This KB continues on the I2C example. It is suggested to complete that exercise in order to see the full effect of implementing the timer – it is however not required and this guide will instruct how to continue if not using I2C in the relevant steps.
Step 2: SSwTimer instance
To start using application timers, you need a SSwTimer instance. In the PRIVATE DATA section, add a SSwTimer instance.
Step 3: Initialize timer
In ApplicationTask() register a timer and add a callback. In this example we start the timer and configure it to 1000 ms.
Step 4: Add a new event
When the timer fires, we want our callback function to enqueue an event to our state machine. Thus we need to add a new event in the _EVENT_APP_ typdedef. We call this event EVENT_APP_TEMPERATURE.
Step 5: Create the callback function
In the PRIVATE FUNCTIONS section create the callback function TemperatureTimerCallback() and enqueue the event EVENT_APP_TEMPERATURE when called.
Step 6: Update the state machine to listen for the event
In the AppStateManager(), find the state called STATE_APP_IDLE. In this state, create a new if-case and perform the temperature measurement if EVENT_APP_TEMPERATURE event is received.
Note: In this step, we are calling performMeasurements(). This function is part of the I2C example. You can leave out this function call, and just verify in the debug log that the event is called once every second.
Step 7: Build solution and test
Build the solution and flash the new firmware image to the device.
If you enable serial debug output, you should now see that we get the TemperatureTimerCallback() and that results in a temperature and humidity reading.
Z-Wave 700 End-device framework KBs
Z-Wave 700: How to implement I2C into the Z-Wave Embedded Framework
Z-Wave 700: How to use Software Timers (this guide)
Z-Wave 700: How to implement SPI into the Z-Wave Embedded Framework
Z-Wave 700: How to implement UART with interrupt into the Z-Wave Embedded Framework
Linked documentation (found in Simplicity Studio)
This document also describes how to setup the Z-Wave region and serial debug, which is not covered by this KB.
Refer to section 7.7 for more information on the Timer module.
Z-Wave 700: How to implement SPI into the Z-Wave Embedded Framework
How to implement SPI into the Z-Wave Embedded Framework
Several peripheral drivers are available (EMDRV and EMLIB) and can be linked to the Z-Wave application. EMDRV exist on top of the lower level EMLIB.
The following resources are great places to look for more information:
Software Documentation (e.g., EMDRV and EMLIB)
32-bit Peripheral Examples (EMLIB)
This KB shows an implementation of a SPI Master application, because most use cases involve connecting a SPI Slave device, e.g. a sensor, to the Z-Wave device.
In order to implement SPI into the Z-Wave framework, we will be using the SPIDRV API from EMDRV. In this KB, we will be implementing the SPI example from the SPIDRV documentation page.
Step 1: Include header files
You need to include the following header files to the search path of the project.
The needed include paths are:
Include path: ${StudioSdkPath}/platform/emdrv/spidrv/inc
File location: C:\SiliconLabs\SimplicityStudio\v4_ga\developer\sdks\zwave\v7.11.0\platform\emdrv\spidrv\inc
Include path: ${StudioSdkPath}/platform/emdrv/spidrv/config
File location:
C:\SiliconLabs\SimplicityStudio\v4_ga\developer\sdks\zwave\v7.11.0\platform\emdrv\spidrv\config
Include path: ${StudioSdkPath}/platform/emdrv/dmadrv/inc
File location: C:\SiliconLabs\SimplicityStudio\v4_ga\developer\sdks\zwave\v7.11.0\platform\emdrv\dmadrv\inc
Include path: ${StudioSdkPath}/platform/emdrv/dmadrv/inc
File location: C:\SiliconLabs\SimplicityStudio\v4_ga\developer\sdks\zwave\v7.11.0\platform\emdrv\dmadrv\config
Step 2: Link the needed source files
With the header files added to the project, we need to link the source files.
You need to do the steps above (A-F) for the following source files:
C:\SiliconLabs\SimplicityStudio\v4_ga\developer\sdks\zwave\v7.11.0\platform\emdrv\spidrv\src
C:\SiliconLabs\SimplicityStudio\v4_ga\developer\sdks\zwave\v7.11.0\platform\emdrv\dmadrv\src
C:\SiliconLabs\SimplicityStudio\v4_ga\developer\sdks\zwave\v7.11.0\platform\emlib\src
Step 3: Include in Z-Wave framework
Add the following include to the main file of the Z-Wave Sample App you are using.
Step 4: Setup for Master
Step 5: Build solution
Now build the solution. If everything went well when adding include paths and linking to source files, you should not get any build errors.
Step 6: Setup SPI
Step 7: Initialize SPI and transfer data
In ApplicationInit(), initialize the SPI driver just before the call to ZW_ApplicationRegisterTask.
Since we will be using the Z-Wave serial debugging interface as well, we will setup SPI to use USART1.
In addition, we will also try to transmit data using a blocking transmit function and using a callback to catch the transfer completion.
Step 8: Build solution and test
Build the solution and flash the new firmware image to the device.
If you enable serial debug output, you should now see that we are successfully sending data.
Closing comments
This KB is a quick demonstration in how to add support for SPI in the Z-Wave Framework.
This implementation just sends out data in the ApplicationInit() function, but this should be done in an appropriate place depending on what functionality is needed.
A word on SPI Slave
The SPIDRV from EMDRV can also be setup as a slave. However, this implementation relies on the Real-time Clock Driver (RTCDRV). Because Z-Wave is using FreeRTOS as the underlying OS, it is not possible to use SPIDRV in Slave mode as it conflicts with how FreeRTOS uses the RTC.
As such, if you need to implement SPI Slave functionality in the Z-Wave framework, you need to use the lower-level USART driver from EMLIB.
Z-Wave 700 End-device framework KBs
Z-Wave 700: How to implement I2C into the Z-Wave Embedded Framework
Z-Wave 700: How to use Software Timers
Z-Wave 700: How to implement SPI into the Z-Wave Embedded Framework (this guide)
Z-Wave 700: How to implement UART with interrupt into the Z-Wave Embedded Framework
Linked documentation (found in Simplicity Studio)
This document also describes how to setup the Z-Wave region and serial debug, which is not covered by this KB.
Z-Wave 700: How to implement I2C into the Z-Wave Embedded Framework
How to implement I2C into the Z-Wave Embedded Framework
Several peripheral drivers are available (EMDRV and EMLIB) and can be linked to the Z-Wave application EMDRV exist on top of the lower level EMLIB.
The following resources are great places to look for more information:
Software Documentation (e.g., EMDRV and EMLIB)
32-bit Peripheral Examples (EMLIB)
In this KB, we will be using a Si7021 Relative Humidity and Temperature Sensor. This sensor is already mounted on the WSTK mainboard that is part of the Z-Wave 700 development kit. The sensor is briefly described in section 5.4 in document ZGM130S Zen Gecko Wireless Starter Kit User's Guide.
In order to implement I2C into the Z-Wave framework, we will be using the I2C API from EMLIB.
Since the same main development board is widely used amount the various Silabs boards, it is possible to find an example in the Gecko_SDK github reporsitory, called "humitemp":
MCU Example: humitemp
The goal of this KB is to interface to the Si7021 sensor using the I2C API from EMLIB by following the "humitemp" example and demonstrates how to get I2C implemented in the Z-Wave framework.
Step 1: Include header files
You need to include the following header files to the search path of the project.
The needed include paths are:
Include path: ${StudioSdkPath}/hardware/kit/common/drivers
File location: C:\SiliconLabs\SimplicityStudio\v4_ga\developer\sdks\zwave\v7.11.0\hardware\kit\common\drivers
Include path: ${StudioSdkPath}/hardware/kit/EFR32FG13_BRD4256A/config
Location: C:\SiliconLabs\SimplicityStudio\v4_ga\developer\sdks\zwave\v7.11.0\hardware\kit\EFR32FG13_BRD4256A\config
Include path: ${StudioSdkPath}/hardware/kit/common/drivers (NB; no need to add, same location as i2cspm.h)
Location: C:\SiliconLabs\SimplicityStudio\v4_ga\developer\sdks\zwave\v7.11.0\hardware\kit\common\drivers
It is worth noting that em_i2c is also referenced to from i2cspm.h. This means, this example is based on the I2C API from EMLIB. The em_i2c.h is already in the include path, so we do not need to add it. For sake of completeness, the include path is:
${StudioSdkPath}/platform/emlib/inc (NB; no need to add, already in the added)
Step 2: Link the needed source files
With the header files added to the project, we need to link the source files.
You need to do the steps above (A-F) for the following source files:
File location: C:\SiliconLabs\SimplicityStudio\v4_ga\developer\sdks\zwave\v7.11.0\hardware\kit\common\drivers
File location: C:\SiliconLabs\SimplicityStudio\v4_ga\developer\sdks\zwave\v7.11.0\hardware\kit\common\drivers
File location: C:\SiliconLabs\SimplicityStudio\v4_ga\developer\sdks\zwave\v7.11.0\platform\emlib\src
Step 3: Include in Z-Wave framework
Add the following include to the main file of the Z-Wave Sample App you are using.
Step 4: Build solution
Now build the solution. If everything went well when adding include paths and linking to source files, you should not get any build errors.
Step 5: Initialize I2C and Sensor
Step 6: Build solution and test
Build the solution and flash the new firmware image to the device.
If you enable serial debug output, you should now see that the sensor is initialized and found.
Step 7: Perform a measurement
In the PRIVATE FUNCTIONS section add the function performMeasurements() from the main-file from "humitemp" example that takes a measurement.
You will get a warning because the function is currently unused. So, let’s try to use it.
Step 8: Tie it all together
We need to call the performMeasurements() function. You would normally make a temperature reading whenever a Multilevel Sensor Get Command has been received if you were to develop a Temperature Sensor.
In this KB, we use the Switch On Off sample application from the Z-Wave SDK. We want to make a measurement, whenever we turn on and off the LED and print it to the debug log.
Locate appBinarySwitchSet(). This function is called whenever a Binary Switch Set command is received on the Z-Wave radio.
After the call to RefreshMMI(), insert the code to call performMeasurements().
Step 9: Build solution and see the result.
Build the solution and flash the new firmware image to the device.
Include the device into a Z-Wave network, e.g by using the PC Controller.
Closing comments
This KB is a quick demonstration in how to add support for I2C in the Z-Wave Framework. In the specific event of interacting with a Temperature & Humidity sensor, one should look into the Multilevel Sensor command class for reporting the value on the Z-Wave radio.
In addition, with this implementation, we only read out the temperature on requests. It is possible to use a timer to do a periodical readout, but this is not covered in this KB.
Z-Wave 700 End-device framework KBs
Z-Wave 700: How to implement I2C into the Z-Wave Embedded Framework (this guide)
Z-Wave 700: How to use Software Timers
Z-Wave 700: How to implement SPI into the Z-Wave Embedded Framework
Z-Wave 700: How to implement UART with interrupt into the Z-Wave Embedded Framework
Linked documentation (found in Simplicity Studio)
This document also describes how to setup the Z-Wave region and serial debug, which is not covered by this KB.
Z-Wave 700: Where are the S2 keypair stored?
Question
How do I generate the needed S2 Public/Private keypair and where are they stored?
Answer
The S2 Public/Private keypair and the responding QR code are all stored in the Lock Bits page with the following manufacturing tokes:
The Z-Wave application is responsible for calculating the S2 Public/Private keypair based on Curve25519, constructing the QR code based on the public key and writing these to the Lock Bits page.
When finish an additional manufacturing token is written to the Lock Bits page to symbolize the completion of this process.
As such, this process is only started if the Lock Bits page is erased and the TOKEN_MFG_ZW_INITIALIZED is therefore not in place.
When this process has finished, it is possible to read out the QR code in order to generate the QR image to print on the product.
Related KBs
Secure S2 key exchange methods during inclusion
Secure S2 DSK
Z-Wave 700: How to readout the DSK for S2 inclusion
Linked Documentation
UG162: Simplicity Commander Reference Guide
INS14285 - Manufacture Z-Wave 700 product in volume (Available through Simplicity Studio)
Z-Wave 700: OTA of End-Device
Question
How do I OTA update an end-device?
Answer
OTA capabilities are a mandatory feature for all Z-Wave 700 end-devices. The Z-Wave 700 Embedded Framework already implements the feature, but you need to make sure to flash the OTA bootloader and a set of encryption keys.
Example: Firmware update of Switch On Off Sample Application
It is worth knowing the following default locations:
C:\SiliconLabs\SimplicityStudio\v4\developer\adapter_packs\commander*
C:\SiliconLabs\SimplicityStudio\v4\developer\sdks\zwave\v7.11.0\Apps\bin
C:\Users\almunkha\SimplicityStudio\v4_workspace\SwitchOnOff\GNU ARM v7.2.1 - Debug
The serial number / Device ID of the device must also be known (e.g. can be seen in Simplicity Studio). The board we are using in this example have ID 440147067.
--- Pre-work: KEYS
Step A: Generate the needed keys
This generates 3 files in the same location as the commander.
* vendor_sign.key
* vendor_sign.key.pub
* vendor_sign.key-tokens.txt
Step B: Generate encryption key
This generates 1 file in the same location as the commander
* vendor_encrypt.key
--- Pre-work: Create firmware for initial setup
Step C: Using Simplicity Studio, open Switch On Off sample app and compile.
This generates a Hex file that we are flashing the device with for initial setup (will be covered in Step 6).
--- Setup device with bootloader and initial firmware
The Z-Wave chips ships without bootloader, so the first step is to prepare the chip with an OTA bootloader and the initial image we will firmware update.
Step 1: Erase Flash
Step 2: Reset
Step 3: Erase bootloader
Step 4: Erase Lock Bits page
Info: This step is not required. If you erase the Lock Bits page, a new set of S2 Private/Public key will be generated automatically by the application image. For more info on Lock Bits page, refer to Z-Wave 700: Where are the S2 keypair stored?.
In addition: If you do erase the Lock Bits page, then it is important to flash the bootloader (step 5) and the application image (step 6) before flashing the generated keys (step 7) just like instructed in this KB.
Step 5: Flash the OTA bootloader image
The Device is now ready to be flashed with firmware image.
--- Flash initial device firmware.
We will be using the Commander for this as well, but it can also be done using Simplicity Studio.
Step 6: Write sample app to flash
NB: You must have completed Step C.
--- Flash keys
Step 7: Program the generated keys from the pre-work
Step 8: Reset device
--- Include device into Z-Wave network
The chip is now setup with OTA bootloader and an initial image.
Step 9: Readout DSK
Readout the DSK by either using Commander or Simplicity Studio.
Step 10: Include DUT into network
Using PC Controller.
Step 11: Get version to prepare for OTA
Using 'OTA Firmware Update' tab in PC Controller.
The firmware version should be (for Z-Wave SDK 7.11): 10.11
--- Pre-work: Create OTA firmware image
Before proceeding with the firmware update, we need to build a new version of the sample app.
Step D: In Simplicity Studio, make sure to increment the version of the firmware.
Eg change version to:
This will increment the firmware version to (for Z-Wave SDK 7.11): 10.12
Build to generate a new hex file.
Step E: Create gbl file to be used for OTA.
This generates 1 new file that we will be using for OTA update
* appname_mySwitch.gbl
--- And finally; the OTA update
Step 12: OTA update
Use PC Controller to start OTA update using location for file appname_mySwitch.gbl.
When file is selected, click on 'Update' which starts the OTA update.
NB: If using the PC Controller for the OTA update, make sure to use version 5.38 or later.
--- RESULT
Firmware Update Md Status Report can be seen in both PC Controller GUI or in Zniffer trace.
Status 0xFF = success