This Getting Started Guide (GSG) walks you through steps to run the demo. For more details on the features of the demo, see the NXP Featured IoT Reference Integration page on FreeRTOS.org.
This project and the GSG are tested using specific MCUXpresso IDE/SDK version as listed in 1.2 Software Requirements section. You can use later versions. For reporting issues with the project, please use FreeRTOS forum or FreeRTOS contact.
The following sequence describes a workflow suitable for a development environment. Many of these steps are automated in production environments.
1 Prerequisites
1.1 Hardware Requirements
1.2 Software Requirements
2 Hardware and Software Setup
2.1 Setting up Device
2.2 Importing and Building Projects
2.3 Running an Application Project from the Debugger
3 Prepare and Run the Bootloader
3.1 Creating Signing Keys for the Bootloader
3.2 Building and Running the Bootloader
3.3 Preparing an Executable Image Sent to the Device via OTA
4 Provision Device and Setup AWS Account
4.1 Provisioning the Device
4.2 Preparing AWS Account
5 Run the MQTT Publish Subscribe Demo
5.1 Demo Introduction
5.2 Running the Publish Subscribe Demo
6 Perform Firmware Over-The-Air Updates with AWS IoT
6.1 Setting up Prerequisites for OTA Cloud Resources
6.2 Creating an Application Code Signing Certificate
6.3 Provisioning the Application Code Signing Key to the Device
6.4 Creating and Running an OTA Update (AWS IoT console)
7 Run the Shadow Demo
8 Run the Defender Demo
9 Troubleshooting Guide
- Mini/micro USB cable
- MIMXRT1060-EVKB board. To order, visit MIMXRT1060-EVKB Buying Options. Note: The projects and instructions here are validated on MIMXRT1060-EVKB board only.
- OM-SE050ARD Development kit. To order, visit OM-SE050ARD Buy Options.
- Personal Computer with the Windows platform.
- Network cable RJ45 standard (Network with Internet access).
- MCUXpresso IDE version 11.4.x or later to build and debug demo projects. To download, visit the MCUXpresso IDE page. (A user account is required to download.)
- SDK version 2.10 for MIMXRT1060-EVKB to get the board configuration for the MCU i.MX RT1060. This project and the GSG were tested using SDK v2.10. You can use later version. To download, visit the MCUXpresso Software Development Kit (SDK) page. (A user account is required to download and download with the default option selected.) The projects use board support libraries directly from the NXP github repository, however, the SDK is required to be able to get the correct board configuration and for the build and flash tool to work correctly.
- Python3 and the Package Installer for Python pip to use the AWS CLI to import certificates and perform OTA Job set up. Pip is included when you install from Python 3.10.
- OpenSSL for Windows to create the OTA signing key and certificate. If you have git installed on your machine, you can also use the openssl.exe that comes with the git installation.
- AWS CLI Interface to import your code-signing certificate, private key, and certificate chain into the AWS Certificate Manager, and used for OTA firmware update job set up. Refer to Installing or updating the latest version of the AWS CLI for installation instructions. After installation, follow the steps in Configuration basics to configure the basic settings (security credentials, the default AWS output format and the default AWS Region) that AWS CLI uses to interact with AWS.
- A serial terminal application, such as Tera Term.
-
Plug in the OM-SE050ARD development kit to the arduino headers on the MIMXRT1060-EVKB board. Make sure all the jumpers are in the correct positions as shown in the figure below.
-
Connect the USB cable between the personal computer and the open SDA USB port (J1) on the board. The serial COM port setting is as below:
-
Connect the RJ45 cable to the ethernet port.
-
Open the MCUXpresso IDE and for the "Workspace" choose the location of the root folder where the repository was cloned.
-
Click on "Import...", select "General >> Existing Projects into Workspace" then click "Next". A list of all supported projects are shown as below. Click "Finish" to import. This will import all projects into the workspace. Alternatively, you can select individual projects one at a time.
Note: Make sure to import the SDK 2.10.x for board support configuration.
-
Confirm the MCU and Memory settings under "Project Settings" are correct.
-
Select the project you want to build, right click and then select "Build Project" to build. Note: All projects use MCU libraries under the "core" folder which is submoduled from the NXP MCU SDK on github. However, you must install the SDK package to get the correct part configuration file for the IDE with the integrated GUI Flash Tool to properly perform build and flash operations. If you get the error message shown below, it is because you do not have the required SDK package installed.
All application projects are configured to flash the demo to an address known to the bootloader. The instructions here are common to run all application projects, including pub/sub, shadow, defender demo. You must have bootloader installed before running application projects using the following steps. See 3 Prepare and Run the Bootloader section for details.
To boot a new application image from IDE, we have to jump-start the application from the debugger.
-
Launch the application as normal from the debugger IDE. The debugger goes into an endless loop after it flashes the image.
-
Click the "Suspend" icon to pause the debugger.
-
Go to the
Debugger Console
in the bottom pane, typejump ResetISR
to jump to the application starting address. The debugger now should jump to the start of main. From here, click the "Resume" icon to continue.
The project uses the MCUBoot python script called imgtool.py
to create signing keys,
and sign and verify the image locally. You can use the Command Prompt in Windows or the Terminal
in MAC or Linux machines.
-
Install the necessary requirements for the image tool. From the repo root folder, run:
py -m pip install -r Middleware\mcuboot\scripts\requirements.txt
-
Create the RSA bootloader signing credentials. Currently, the repository only supports RSA signature based validation. From root folder, run the following commands:
py Middleware\mcuboot\scripts\imgtool.py keygen -k examples\evkbmimxrt1060\bootloader\signing_key.pem -t rsa-2048 py Middleware\mcuboot\scripts\imgtool.py getpub -k examples\evkbmimxrt1060\bootloader\signing_key.pem --lang c > examples\evkbmimxrt1060\bootloader\signing_pub_key.c
Note: Make sure write permission is enabled for this root folder. Confirm that the files
signing_key.pem
andsign-rsa2048-pub.c
were generated.You will need to use the
signing_key.pem
file created above to sign the application image created during the firmware update. Thesign-rsa2048-pub.c
file is used to build the MCUBoot bootloader.
-
From the MCUXpresso IDE workspace where the projects were imported, select the "Bootloader" project.
-
Right Click and then select "Build Project".
-
Click the "GUI Flash Tool" icon, then click "OK". Go to the "Erase" tab, check "Mass erase" and then click "Run.." to erase the flash before you program the Bootloader image. Wait until "MassErase completed" shows up on the IDE Console. Note: if you previously provisioned the board with the endpoint and thing name, this action will erase this configuration information on the flash and will require you to provision the board again.
-
Click the blue "Start Debugging" icon to run the Bootloader.
The bootloader program is loaded onto the board and stopped at the main function.
-
Click the "Run" icon to start.
On the serial terminal console, the bootloader start-up message is printed out. The bootloader is successfully programmed into the board. Notes:
- Alternatively, you can also use the Flash GUI Tool to program the bootloader binary into the flash.
- Upon boot, the bootloader checks for any image in the primary slot. If there is no application image it simply waits in an infinite loop. You can observe the message "Unable to find bootable image" on the serial terminal reflecting that status.
-
Now you can go ahead and flash the application image to be booted. Refer to the next section, "Running Application projects", for details.
For a succesful OTA, follow the below steps to prepare the executable image:
- The version number of the image sent via OTA must be higher than that already running on the device, so temporarily update the executable image's version number.\
- Build the executable image.\
- Sign the executable image with the key used by the bootloader to validate the image.\
- Reset the executable image's version number so it is lower than the version number in the executable image signed in the previous step.\
To update version number of the image:
- Under each example folder, navigate to the
include\ota_config.h
, update the following macros:APP_VERSION_MAJOR
APP_VERSION_MINOR
APP_VERSION_BUILD
To create a signed application image:
- Build the project to create a new image binary.
- Sign the new binary image using the MCUBoot key-pair generated as part of setting up the
bootloader project. From the repository root folder, run the following command:
Replace "MM.mm.bb" with the corresponding firmware major version (MM), minor version (mm) and build version (bb). This will create a new signed MCUboot image named
py Middleware\mcuboot\scripts\imgtool.py sign \ -k examples\evkbmimxrt1060\bootloader\keys\signing_key.pem --align 4 \ --header-size 0x400 --pad-header --slot-size 0x200000 --max-sectors 800 \ --version "MM.mm.bb" projects\evkmimxrt1060\pubsub\Debug\aws_iot_pubsub.bin \ aws_iot_pubsub_signed.bin
aws_iot_pubsub_signed.bin
The project requires a one time setup, both in your AWS account and on the device, to enable the device to connect to AWS IoT core. These steps include:
- Register a device certificate with AWS IoT Core using your AWS account.
- Create a "thing" in your AWS account and associate it with the device certificate and the appropriate device policy.
The project requires a one time device provisioning to be able to connect to AWS IoT Core. For this, you will:
- Provision the MQTT broker endpoint onto the device.
- Provision the "thing" name registered in your account onto the device.
The aws-iot-pubsub project can be used to provision the board. By default, the project boots
into a provision mode at startup where all the configuration options can be set up. The
provisioning mode can be enabled/disabled using the flag appmainPROVISIONING_MODE
in the examples/evkbmimxrt1060/pubsub/app_main.c
file.
Follow the steps below to set up an AWS account and provision the device:
-
Connect to the USB port using a serial terminal. Follow "Starting application project" for the "aws-iot-pubsub" project with flag
appmainPROVISIONING_MODE = 1
. Note: the application expects the Ethernet cable to be connected, or else it will enter a loop to negotiate the physical connection.When the application is started correctly, it enters provisioning mode and waits for user input commands from a CLI task.
-
Run the following command to get the pre-provisioned X.509 certificate from the secure element:
pki get cert sss:F0000001
sss:F0000001
is the slot where the certificate is stored in the secure element. -
Copy the PEM certificate from the terminal console and save to a file. Log into your AWS account, go to the AWS IoT Console, choose "Security", choose "Certificates", and then click on the drop down "Add Certificate" and choose "Register Certificate". Choose "CA is not registered with AWS IoT" and select the PEM file you just created. Select "Activate" then choose "Register". For more detailed instructions, see Register a client certificate signed by an unregistered CA (console).
-
To get the AWS IoT MQTT broker endpoint for your account, go to the AWS IoT console and in the left navigation pane choose
Settings
. Copy the endpoint listed under the "Device data endpoint". -
From serial terminal console, run the following command to provision the endpoint:
conf set mqtt_endpoint <endpoint>
Confirm that the application responds "OK".
(Note: Make sure to wait for the command prompt ">" to type in the command.)
-
In the AWS IoT Core console, create a new thing (using "Skip certificate and create thing") as described in Create AWS IoT resources.
-
In the left navigation pane, select "Secure", select "Certificates", and then select the certificate you created. Click "Actions >> Attach thing", select the thing you created and then choose "Attach".
-
Go to "Secure >> Policies" and create a device policy like the one below:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "*", "Resource": "*" } ] }
Note: This policy should only used for development and must not be used for production. Save the policy.
-
Go back to "Security >> Certificates" and select the device certificate you created. Choose "Actions >> Attach policy", select the created policy, then choose "Attach" to attach the policy to the certificate. Confirm that the thing and policy are attached to the certificate correctly.
-
Go back to the serial terminal console. Provision the new thing name to the device using the following command:
conf set thing_name <thing name>
Confirm that the application responds "OK".
You have now successfully completed board provisioning.
-
Once the configurations are set up, turn off the provisioning mode by setting
appmainPROVISIONING_MODE
to0
, then recompile and flash the image onto the board.
This example demonstrates multiple MQTT publish/subscribe tasks running concurrently with an Over-The-Air firmware update background task. It uses the coreMQTT agent library to manage thread safety for the MQTT connection. Each publish/subscribe task runs in a loop to publish a message to the AWS IoT MQTT broker on a topic, and receive the same message back by subscribing to the same topic. Topics are constructed per device and per task for this demo. You can view the number of messages published by each task by logging in to the AWS IoT console and subscribing to their respective topics. The OTA firmware update task runs an OTA Agent loop which polls for, and subscribes to, OTA job requests from the AWS IoT OTA service. The OTA agent task receives firmware chunks and sends control packets over MQTT, concurrently using the coreMQTT agent task for thread safety.
The board should be successfully provisioned at this time. To turn off provisioning mode, set
appmainPROVISIONING_MODE
to 0
in examples/evkbmimxrt1060/pubsub/app_main.c
.
On startup, the demo establishes a TLS connection with the AWS IoT MQTT broker and runs the
publish/subscribe demo tasks using the coreMQTT agent. By default, two pubsub tasks are created.
You can adjust the number of tasks created by setting the config
appmainMQTT_NUM_PUBSUB_TASKS
in examples/evkbmimxrt1060/pubsub/app_main.c
to the desired value. Follow these steps to run the demo:
-
On the serial terminal console, confirm that the TLS handshake was successful and that MQTT messages are published.
-
On the IoT console, select "Test" then select "MQTT test client". In the "Subscription topic" section, type "#", select "Subscribe to topic", and confirm that the MQTT messages from the device are received.
-
To publish a message to the device, go to the "Publish to a topic" section, type "/pubsub_demo/<thing_name>/task" enter a message in the message payload section, then select "Publish to a topic".
-
On the serial console, confirm that the device receives the message.
*Notes:
- Running the MQTT pub/sub demo will incur messaging cost.\
- Stopping from debugger will not stop the demo from running on the device and publishing messages.
This demo leverages OTA client library and the AWS IoT OTA service for code signing and secure download of firmware updates. A safe and secure boot process along with root of trust verification is performed using the open source MCUBoot secondary bootloader. The secure boot and over-the-air update process include two code signing stages. The first one mentioned in Prepare an executable image that will be sent to the device via OTA is for the bootloader to verify the image on the primary slot prior to execution. The code signing in this section is for the application to verify the image prior to downloading it into the device. As a pre-requisite, you should have built and flashed the bootloader project from this repository as in Prepare and Run the Bootloader.
Before you create an OTA job, the following resources are required:
- An Amazon S3 bucket to store your firmware update.
- An OTA update service role to create and manage OTA update jobs on your behalf.
- An OTA user policy to grant your IAM user permission to perform over-the-air updates.
This is a one time setup required for performing OTA firmware updates. Follow the steps listed in OTA update pre-requisites (using MQTT) in the FreeRTOS User Guide to set up the required OTA resources.
The demos support a code-signing certificate with an ECDSA P-256 key and SHA-256 hash to perform OTA updates.
-
In your working directory, copy the following text and create a file named
cert_config.txt
. In the text, replace[email protected]
with your email address.[ req ] prompt = no distinguished_name = my_dn [ my_dn ] commonName = [email protected] [ my_exts ] keyUsage = digitalSignature extendedKeyUsage = codeSigning
-
Create an ECDSA code-signing private key.
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -pkeyopt \ ec_param_enc:named_curve -outform PEM -out ecdsasigner.key
-
Create an ECDSA code-signing certificate.
openssl req -new -x509 -config cert_config.txt -extensions my_exts -nodes \ -days 365 -key ecdsasigner.key -out ecdsasigner.crt
-
Import the code-signing certificate, private key, and certificate chain into the AWS Certificate Manager.
aws acm import-certificate --certificate fileb://ecdsasigner.crt --private-key fileb://ecdsasigner.key --region=<aws_iot_region_for_account>
-
Confirm the ARN for your certificate. You need this ARN when you create an OTA update job.
-
Get the ECDSA public key from the code signing credentials generated in 6.2:
openssl ec -in ecdsasigner.key -pubout -outform PEM -out ecdsasigner-pub-key.pem
-
Confirm that the file
esdsaigner-pub-key.pem
has been created correctly. -
Open the target MCUExpressoIDE aws_iot_pubsub project. To switch to device provisioning mode set
appmainPROVISIONING_MODE
to1
, recompile and download the firmware to the board. -
On the terminal CLI, run the following command:
pki set pub_key sss:00223344
-
The CLI waits for you to input the public key. Copy the contents of the PEM public key created in above step and paste it to the serial terminal, then press
Enter
. (Note: Paste the whole content, including from "-----BEGIN PUBLIC KEY-----" to "-----END PUBLIC KEY-----".) -
On successful provisioning, the CLI should print
OK
. At this point, you can switch back to device normal mode by turning off theappmainPROVISIONING_MODE
flag.
To perform an OTA firmware update, you must go through these steps:
- Increment the version of the firmware and create the signed binary image (section 4.3).
- Create an OTA Update Job on the AWS IoT console.
- Restore the original version (lower version number) and run it from the debugger (section 4.1).
After the first successful OTA where a signed binary image is loaded as the primary image, you can perform subsequent OTA updates without running the last step above using the debugger.
The following steps walk you through OTA job creation and monitoring the OTA process.
-
In the navigation pane of the AWS IoT console, choose Manage, then Remote Actions, and then choose Jobs.
-
Choose Create a job.
-
Next to Create a FreeRTOS Over-the-Air (OTA) update job, choose Create OTA update job.
-
You can deploy an OTA update to a single device or a group of devices. Under Select devices to update, choose Select. To update a single device, choose the Things tab. To update a group of devices, choose the Thing Groups tab.
-
If you are updating a single device, select the check box next to the IoT thing associated with your device. If you are updating a group of devices, select the check box next to the thing group associated with your devices. Choose Next.
-
Under Select the protocol for firmware image transfer, choose MQTT, or choose both MQTT and HTTP to allow each device to determine the protocol it will use.
-
Under Select and sign your file, choose Sign a new file for me.
-
Under Code signing profile, choose Create.
-
In Create a code signing profile:
- Type in a name for this profile.
- For the Device hardware platform, select: "Windows Simulator". (This is the generic template that do not tight to any specific hardware platform and allow customize in the subsequent steps).
- Under Code signing certificate, choose "Select", then choose the certificate that you created with AWS CLI earlier.
- Under "Path name of code signing certificate on device", enter "sss:00223344". This is the slot address of the secure element where the key for the code signing certificate is stored.
- Click "Create". Confirm that the code signing profile was created successfully. Note: Currently the slot id is hardcoded in the code. If you want to change to a different slot, you can update it.
-
Back on the FreeRTOS OTA Job console:
-
Under "Code signing profile", select the code signing profile that was just created from the drop down list.
-
Under "File", choose "Upload a new file" then click "Choose file". A file browser pops up. Select the signed binary image (
aws_iot_pubsub_signed.bin
). Note: the version of the new image must be later than the current image on the board or else OTA will not proceed. -
Under "File upload location in S3", click "Browse S3", then select the S3 bucket that you created for this job.
-
Under "Path name of file on device", type "NA"
-
Under "IAM role for OTA update job", choose the role that you created earlier for the OTA update from the drop down list.
Then, click "Next" to create OTA job. Confirm if the Job was created successfully. Note: If it fails to create an OTA job, make sure the role for this OTA job update has the correct permissions (policies) attached. Below is the list of managed policies used and custom policies defined for the account ID, role and S3 bucket resource.
GetSetRolePolicy:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iam:GetRole", "iam:PassRole" ], "Resource": "arn:aws:iam::<account ID>:role/<role name>" } ] }
NXP-FreeRTOS-OTA-Policy:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObjectVersion", "s3:PutObject", "s3:GetObject" ], "Resource": "arn:aws:s3:::<S3 bucket name>*" }, { "Effect": "Allow", "Action": [ "signer:StartSigningJob", "signer:DescribeSigningJob", "signer:GetSigningProfile", "signer:PutSigningProfile" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "s3:ListBucketVersions", "s3:ListBucket", "s3:ListAllMyBuckets", "s3:GetBucketLocation" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "iot:DeleteJob", "iot:DescribeJob" ], "Resource": "arn:aws:iot:*:*:job/AFR_OTA*" }, { "Effect": "Allow", "Action": [ "iot:DeleteStream" ], "Resource": "arn:aws:iot:*:*:stream/AFR_OTA*" }, { "Effect": "Allow", "Action": [ "iot:CreateStream", "iot:CreateJob" ], "Resource": "*" } ] }
-
-
Once the job is created successfully, the demo should start downloading the firmware chunks. The process can be monitored using logs from the serial terminal console. Note: make sure the device is running with the older version of the application image.
-
Once all the firmware image chunks are downloaded and the signature is validated, the demo resets by itself. The MCUBoot loader verifies the new image using the signing public key created as part of bootloader project. Once the image is verified, the bootloader swaps the image and boots up with the new image. On booting up, the new image verifies the image version with AWS IoT and marks the job as completed successfully.
-
On the device side, check that the device reboots, and the bootloader verifies, swaps, then erases the new image in the secondary slot and jumps to the application. Verify the version of the new application.
-
Verify that the bootloader updates the primary and secondary slots correctly and jumps to the application correctly.
-
On the AWS IoT console, confirm that the "Status" of the OTA job is "Completed".
- From the MCUXpressoIDE workspace where the aws_iot_shadow project was imported, do the following:
- Set
appmainPROVISIONING_MODE
inapp_main.c
to 0. - Set
appmainINCLUDE_OTA_UPDATE_TASK
inapp_main.c
to 1. - If you update the shadow firmware into device via OTA, pump version up in
include\ota_config.h
.
- Set
- Build and sign the binary image. See section 4.3 "Create a Signed Application Image".
- Update this new firmware using OTA. See section 6 "Perform Firmware Over-The-Air Updates with AWS IoT".
- Or you can run from the debugger. See section 4.1 "Running an Application Project from the Debugger".
- On AWS IoT console, Select "Manage >> Things", click on the thing you created to represent this device, then select "Device Shadows >> Classic Shadow".
You should see the device shadow state "powerOn" toggled every few minutes. To update this state, click the "Edit" button, and update the "powerOn" value. You should see the device sync with the updated state.
{
"state": {
"desired": {
"powerOn": 1
},
"reported": {
"powerOn": 1
}
}
}
Device Shadow metadata
{
"metadata": {
"desired": {
"powerOn": {
"timestamp": 1648692896
}
},
"reported": {
"powerOn": {
"timestamp": 1648692896
}
}
}
}
- From the MCUXpressoIDE workspace where aws_iot_defender project was imported:
- Set
appmainPROVISIONING_MODE
inapp_main.c
to 0. - Set
appmainINCLUDE_OTA_UPDATE_TASK
inapp_main.c
to 1. - If you update the shadow firmware on the device via OTA, increment the version in
include\ota_config.h
.
- Set
- Build and sign the binary image. See section 4.3 "Create a Signed Application Image".
- Update this new firmware using OTA. See section 6 "Perform Firmware Over-The-Air Updates with AWS IoT".
- Or you can run from the debugger. See section 4.1 "Running an Application Project from the Debugger".
- On the AWS IoT console, Select "Manage >> Things", click on the thing you created to represent this device, then
select "Defender metrics". Select the Metric you want to see from the drop down menu. Supported metrics are:
- Bytes in
- Bytes out
- Packets in
- Packets out
Note: At power up, the device will wait for a few minutes before it starts sending the metrics. On device side, you can observe it publishing messages to the device defender topic.
Besides the Defender metrics graph on the console, you can also use the MQTT Client Test and subscribe to the defender topic to receive the message.
* Topic: $aws/things/<Thing Name>/defender/metrics/cbor
.
-
The device can not do an OTA update again after failing the first OTA running with the debugger.
When running with the debugger, the image was not signed. If the first OTA fails, the bootloader will try to recover by loading the prior good image and this will fail as the image loaded by debugger is not signed. The bootloader will update memory status as bad (“magic=bad”. Both Primary and Secondary image status should be either “good” or “unset”. If you see the state as “bad”, you will need to use Flash GUI tool and perform “mass erase” for the bootloader to recover.
-
The OTA job status is Completed but Failed.
Please check device log for specific reason as why it fails. Some conditions can be:
- The version of the new image is not higher than the current one. Recreate the signed binary with a higher version.
- The image is not signed with a valid signature. Recreate the signed binary with a correct signature.
- The device encounters a niche error condition, such as receiving duplicate blocks, or the OTA buffer is not available to handle these error conditions. In these instances, you can retry OTA job from the console.