In this chapter, we will set up a software development toolchain and install the platform libraries that we will use to create our device. To test out the board, we will try a simple Hello World program that uses a real-time operating system (RTOS) and go through the compile, download, and debug cycle. Once we have the basics working, we will set up a base project that adds a WiFi connection to your local network and add a file system to read and store data on an SD card. This will give us a basic platform that we can expand through the course of this book.
CMSIS driver; WiFi module; File system; MDK ARM
In this chapter, we will set up a software development toolchain and install the platform libraries that we will use to create our device. To test out the board, we will try a simple Hello World program that uses a real-time operating system (RTOS) and go through the compile, download, and debug cycle. Once we have the basics working, we will set up a base project that adds a WiFi connection to your local network and add a file system to read and store data on an SD card. This will give us a basic platform that we can expand through the course of this book.
The examples in this book are designed to run on an NXP LPC55S69 XPRESSO evaluation board, which has been fitted with an ESP-Wroom-2 Mikro Click WiFi module and an SD memory card, as shown in Fig. 3.1.
Full details of the hardware are available from the URL’s below:
The NXP LPC55S69 microcontroller was one of the first Cortex-M33 based microcontrollers available. As we will see in the second half of this book, it contains many security features that complement the Arm Platform Security Model.
To build the examples, we will use the Keil MDK-ARM, which is a reference toolchain for both the CMSIS standards and the Arm Platform Security Architecture.
This installs the core toolchain, which includes the Microvision IDE, ArmM Compiler, RTX RTOS, and the Microvision debugger.
While the MDK-ARM is a commercial toolchain, a community license is available, that allows it to build and debug large projects. This version of the toolchain is to be used for learning projects and other noncommercial projects only.
Full instructions for obtaining and installing the community license are provided on the Tutorial Exercises download page shown below.
All of the exercises in this book are provided as a software pack that can be downloaded from
https://github.com/DesignersGuide/IoT_Security_Examples
This is a simple project that blinks the user RGB LED. It also writes to a console using the Instrumentation Trace debug channel rather than a hardware USART.
In The Pack Installer select the Boards tab and locate IoT_Device:Security
Now select the examples tab and load the first Example 1.1 Test project by pressing the copy button.
Select a suitable exercise directory and press the OK button (Fig. 3.2).
This will copy the blinky project to your hard disk and start the Microvision IDE.
Connect a USB cable to the USB socket labelled Debug Link P6 and a PC USB socket.
Check Jumper J3 is set to the “Loc” position (default).
This connects the debugger and powers the board.
The Core MDK-ARM toolchain does not include any support for specific microcontrollers. We can add support for specific devices by downloading and installing software packs that are stored in a cloud server. Fortunately, this is easy to do through a built-in pack installer utility.
When the pack installer utility starts it will connect to the cloud and update its list of software packs, this may take a few minutes.
Software pack | Description |
---|---|
ARM::mbedTLS | Cryptographic library for Cortex-M devices |
ARM::mbedCrypto | Cryptographic Library for TrustZone Secure Partition |
ARM:: CMSIS-Driver Validation | Test Suite for peripheral drivers based on the CMSIS-Driver specification |
ARM::TF-M | Reference implementation of the PSA Trusted Firmware security services core files |
Keil::ARM_Compiler | STDIO interface files for ARM compiler |
Keil::LPC55S69xTFM_PF | Trusted Firmware platform files for the NXP LPC55S69 family |
MDK-Packs::AWS_IoT_Device | Support files for AWS services |
MDK-Packs::IoT Socket | Simple IP socket implementation |
MDK-Packs::Paho_MQTT | Embedded MQTT client |
MDK-Packs::CJSON | JSON data format parser |
MDK-Packs::TinyCbor | CBOR data format parser |
Install each of the packs listed in the table.
In addition to the MDK-ARM toolchain, you will need a terminal emulator. While any should work, the exercises have been tested with Tera Term.
The project workspace contains two projects. A fully configured project for reference and a shell project which we will build up to gain some experience with the IDE (Fig. 3.6).
The shell project is an empty project that has been created using the following steps:
From this state we can start to expand the shell project by adding software components through a “Run Time Environment” (RTE) manager.
The RTE provides a tree of installed software components that can be added to a project by using the tick boxes in the selection (sel.) column. This dialog allows us to create and manage complex software platforms (Fig. 3.9).
When a selected component has all its necessary dependencies provided, the sel. tick box will appear green. If further options are required, it will appear orange. The validation output window will list the missing files and will show any options available to create a full project. To help this process, RTE also provides a resolve button that can be used to add missing dependencies as far as is possible for the toolchain. Any remaining selections then need to be resolved by the developer. So, for example, you may need to select which low-level peripheral is going to be used with a particular software component.
Device::SDK_Utilities::assert (2)
Device::SDK_Utilities::Serial Manager_uart (3)
This sets a path to the CMSIS-Core support files, which are then included by the device header file.
This adds a small footprint RTOS, which will be used in most of the examples in this book.
If this is not the case check the reference project for the correct settings.
The software components will be added to the project, as shown in Fig. 3.12.
In the project window, the component branches are shown with a green diamond (dark gray in print version) and the user source code branches are shown as a file folder.
Within the Software component branches, the source code is held in the pack repository as read-only files. The write protection is shown as a yellow key icon (light gray in print version).
Any configuration options are held in read/write header or source files which have _config as part of their name.
Most of the configuration files can be viewed through a configuration wizard, which is enabled through a tab that is located bottom left of the editor window (Fig. 3.13).
The final image layout is controlled using a linker scatter file. These files have the extension .scf. Several scatter files are provided for different build configurations. In this project, we are using the LPC55S69_cm33_flash.scf, which defines a basic image layout for the internal flash memory.
This view contains a set of dialogs that hold all the global project options.
The default memory layout has been disabled, and instead, the linker will use our custom linker scatter file (Fig. 3.15).
Have a look through the other dialogs but for now don’t change any options.
This will download the image to the target FLASH and run the code to main.
Explore the debugger toolbar using the options shown below.
You can set a breakpoint by clicking on the dark gray boxes next to the source code (Fig. 3.17).
A breakpoint is shown as a red dot (dark gray in print version).
The state of the RTOS can be seen in a similar component viewer window.
The code will also enable the debug "Serial Wire Out" SWO pin, which allows the debugger to use the Instrumentation Trace and Data Watch Trace, which are part of the Cortex-M Coresight debug architecture.
This will launch the new connection dialog.
The Cortex-M33 debug architecture contains an “Instrumentation Trace.” This provides a serial interface from the processor to a serial terminal via a virtual serial port created by the built-in debug hardware on the Xpresso evaluation board. Now within our code, STDIO used by printf and scanf will be redirected to the Tera Term console.
This will execute the code and display a startup message on the Tera Term console. You can now type characters within Tera Term and they will be echoed back the RGB LED is toggled on and off as each character is typed.
The default terminal window in Tera Term is white text on a black background. In this book, the display has been transposed to black text on white for better printing results.
This example should have familiarized you with the MDK-ARM toolchain and help prove out the hardware. Before we leave this exercise, it is worth noting one more thing:
If you are experimenting with this board, you may do something that locks up the microcontroller preventing the debugger from connecting. Typically, this can occur if you add low power code or miss configure the processor clock tree.
If you get into this predicament, it is possible to erase the internal FLASH by holding down the ISP button and then powering the board. This will start the internal bootloader running rather than the FLASH code. You should then be able to connect the debugger and erase the FLASH memory. This will recover the board, and you can continue.
The LPC55S69 contains a PSACertified compliant secure boot ROM, and we will have a detailed look at this later. Needless to say, this technique does not work if the secure boot has been enabled. You have been warned!
The CMSIS WiFi driver is designed to provide a common interface to supported WiFi “System on Chip” SoC devices. Currently, the following devices are supported (Table 3.2).
Device | Interface | Data bypass mode |
---|---|---|
ESP32 | UART | No |
ESP8266 | UART | No |
ISM43362 | SPI | No |
WizFi360 | UART | No |
QCA400x | UART/SPI | Yes |
The CMSIS WiFi driver is a compound driver that uses a further CMSIS driver for low-level communication to the module. This will typically use an SPI or USART as the module interface (Fig. 3.23).
Each WiFi module contains its own TCP/IP stack. This allows the module to manage all network communications while providing a socket interface for the microcontroller. However, WiFi modules often have limitations in the size of IP packets they can send and receive. Many IoT devices only need to transfer relatively small amounts of data, so this is not usually a problem, but it is something to bear in mind when selecting a module. If the module supports “Data Bypass Mode,” the onboard TCP/IP stack can be replaced by a TCP/IP stack such as LwIP or the Keil network component running on the application microcontroller. This removes many of the modules limitations and allows us to develop a wider range of more sophisticated network applications.
We can add WiFi support to our project through the run time environment manager. Since we are configuring two CMSIS drivers which are acting in concert, we need a methodical way of configuring and testing the drivers with minimal effort. Fortunately, the CMSIS WiFi driver is well supported within the CMSIS driver validation suite, and this provides an ideal way to bring up the driver for the first time.
In this exercise, we will set up a module that uses a UART interface and then have a look at the more complex configuration for a module with an SPI interface.
This is a multiproject workspace with a fully configured project for reference and a shell project, which we will use to add and test the CMSIS drivers.
This module uses a UART interface, so we also need to add a CMSIS USART driver. In this case, we need to add support for a plain hardware USART, which is supported by the CMSIS DriverUSART(API)flexcomm_usart_cmsis driver (Fig. 3.24).
Next, we need to add to the CMSIS driver validation framework.
If you have new or unknown hardware you could also add the USART validation tests (Fig. 3.25).
The validation framework is designed to run bare metal or with the CMSIS RTOS2. In this exercise, we will need to add the RTOS as well.
Depending on your installation, you may have several RTOS choices available. In this book, we are going to use the Keil RTX5 RTOS as this has a small footprint and native support for the CMSIS-RTOS2 API.
Now we can use the configuration wizards to setup the CMSIS drivers and validation framework.
First, select the DeviceRTE_Device.h file and enable the UART, which will be used to communicate with the WiFi module. As we are using the LPC55S69 expresso board, this will be UART 2.
For initial testing, use the default settings, but we do need to adjust the USART driver number to match the hardware configuration on the Xpresso board. In this case, the USART driver value must be set to “2.” We must also allocate 1024 bytes to the WiFi driver RTOS thread (Fig. 3.28).
The WiFi driver will configure the CMSIS USART driver so we have nothing further to do at the USART driver level.
To configure the validation environment, we need to setup the RTOS and debug components.
Here, we must have a global memory pool of at least 8096 bytes and a default thread stack size to 2048 bytes (Fig. 3.30).
Now we can configure the validation framework in dv_config.h header. The first section allows us to set the global framework options. For this test, we can again use the defaults with the print output format set to XML for the final report.
Open CMSIS Driver ValidationDV_WiFi_Config.h and select the wizard
During the validation tests, data packets will be sent to a “socket server” running on a network PC. The socket server is a dedicated executable that is designed to run in a Windows environment. The socket server is located in the following directory:
As this may change I have also included the socketserver executable in a folder within the current example. The socket server is an executable, which just needs to be started without any further configuration. However, you will need to create an exception rule in your firewall to allow a remote device to connect. Once started, its IP address will be displayed on the console screen (Fig. 3.33).
The socket server provides a number of testing services that are used by the CMSIS driver validation suite. Each service supports both TCP and UDP protocols (Table 3.3).
Service | Port | Description |
---|---|---|
Echo | 7 | Echo’s back received data packets |
Discard | 19 | Accepts remote socket connection |
Chargen | 19 | Send continuous character stream |
Assistant | 5000 | Connects to remote server socket |
The final section of the validation configuration wizard allows us to enable a wide range of tests for both the WiFi module features and communication. For initial testing, we can use the default test settings, and this will exercise most of the driver features (Fig. 3.35).
Once the driver and test framework are configured we can invoke the test framework from main() as follows:
#include "cmsis_dv.h" #include "cmsis_os2.h" int main(void) { SystemCoreClockUpdate(); osKernelInitialize (); //app_initialize(); osKernelStart(); /* Start thread execution */ while(1); }
This code is provided in a module main.c located in the project directory.
Compared to a normal development project, there are a couple of settings that can be used to make this project a more efficient test environment. First, the project is configured to start the debugger after a build by setting the “Start debugging” option in the Options for target/User dialog (Fig. 3.36).
A script file has been added to the debugger dialog, and the script will execute when the debugger is started. This is very important as this “automates” the build and test loop, which can then be executed with a single button press (Fig. 3.37).
The script file controls execution of the test framework and logs the test results to a file in the project directory. When XML format is selected, a schema is also saved.
When using a standalone debug adapter such as Ulink or Jlink, the test results can be displayed in a console window in microvision. The SLOG command can be used to store the results in a file automatically.
The validation tests report can be copied from the Tera Term console and saved to a file in the project directory. This file can then be viewed with a HTML browser (Fig. 3.38).
If the WiFi module has an SPI interface, it will include a slave select line, which must be managed at the start and end of communication from the MCU. Since the SPI interface is synchronous, the module uses a “Data_Ready” line to signal the MCU that data are ready to be read from the WiFi module. The data ready line should be connected to an MCU GPIO pin that can generate an interrupt when the data ready line becomes active (Fig. 3.39).
The driver for SPI based modules provides an extra hardware interface file that contains stub functions that allow these features to be managed by the MCU GPIO pins (Fig. 3.40).
The MCU GPIO pin connected to the data ready line should be configured to trigger when the data ready line becomes active. Its interrupt function can then signal the driver that new data are ready using the function provided as shown below:
The hardware interface file contains stub functions to control the MCU GPIO pins connected to the reset line and slave select lines.
void WiFi_ISM43362_Pin_RSTN (uint8_t rstn) { GPIO_WritePin(GPIOE, GPIO_PIN_8, rstn ? GPIO_PIN_RESET : GPIO_PIN_SET);} void WiFi_ISM43362_Pin_SSN (uint8_t ssn) { GPIO_WritePin(GPIOE, GPIO_PIN_0, ssn ? GPIO_PIN_RESET : GPIO_PIN_SET); } uint8_t WiFi_ISM43362_Pin_DATARDY (void) { return (GPIO_ReadPin(GPIOE, GPIO_PIN_1) == GPIO_PIN_SET); }
Once the hardware interface file is configured, you can test the driver as shown in the previous example.
Once the WiFi driver has passed the validation tests, we can remove the validation framework and access the driver from our application code.
Open the RTE and remove the CMSIS validation framework options and click OK
In the project window, open main.c
osThreadNew(cmsis_dv, NULL, NULL);
The app_main thread will be used to first initialize and power up the WiFi module using the socket_startup() function
The code will then activate the WiFi module so that it attempts to connect to the network. If this is successful, we can run a main application that will be able to send and receive TCP/IP packets using the WiFi module.
The project also contains a port of the FATFS file system, which can be used to read and write files to an SD card that has been inserted into the SDIO socket on the evaluation board.
Once the WiFi module has been connected to the local network, the application code will initialize the file system and create a test file on the SD card.
The code will now initialize the file system and create a test file on the SD card.
You should now be able to view and read the test file on your PC to check that the file system is working.
We now have our evaluation board set up with a WiFi interface to a local network that allows us to send and receive TCP packets through a socket interface. We can also build applications with a professional toolchain and debug them on the evaluation board. Over the next two chapters, we will look at building a secure communications channel that can be used by our IoT devices to communicate with a cloud server.
18.227.161.225