The AWS IoT platform consists of many products and services: Greengrass, IoT Core, Amazon FreeRTOS, and Device Defender to name a few. It can be difficult to know where to start when piecing together each of the offerings to create an IoT solution. This guide covers automating Amazon FreeRTOS building and development as well as some of the Iot Core services.
A good place to start is with selecting a development device. Devices can take time to ship. Selecting a device before doing any other work will ensure that you have actual hardware to test on as soon as you are ready. This guide will use the NXP IoT module and an NXP LPC Link2 debugger.
Any hardware from the list of Amazon FreeRTOS supported devices can be automated. But, the setup for each device will vary dramatically. If you plan on following the rest of this guide it is recommended that you get the NXP IoT module. The debugger, while optional, is recommended.
The debugger makes flashing the device very simple. It also allows you to attach to the device and set breakpoints as well as step through the code if you have issues. The Link2 debugger will also make flashing the final Release build easier.
Getting Started With Amazon FreeRTOS
Amazon has done a great job providing documentation on getting started with any of the recommended hardware. Before you can automate building the firmware you’ll want to follow the Amazon guide here. The basic setup covered in that guide for the NXP module is:
- Choose an IDE
- Download Amazon FreeRTOS
- Download NXP SDK’s for the device
- Run a demo application on the device
- Test the MQTT connection using IoT Core Test
Make sure to use the MCUXpresso steps. MCUXpresso is an IDE by NXP. This is the same manufacturer of the MCU and debugger.
The getting started guide from Amazon does not cover setting up a release build. After completing the guide you can create a Release build by copying the provided Debug build.
- Right clicking on the project in the IDE
- Select build configurations > manage.
- Add a new configuration and name it Release.
- Copy the settings from the debug build then click OK.
- Select the Release configuration and create a new build.
Make sure your Release build finishes without issues before continuing.
Automating Our MCUXpresso Build
Automating the Release build early will save a lot of headache later. The ability to reproduce a build becomes harder as a project grows and dependencies are added. Automating the build is straightforward with CodePipeline and CodeBuild. Use the Launch Stack button below to create a new CloudFormation stack containing a CodePipeline pipeline with a CodeCommit source stage and CodeBuild project using a custom Docker image.
There are a few options to choose when launching the stack. It is recommended you stick with the defaults and leave all other options empty when getting started.
The CloudFormation stack creates an EC2 Container Registry for Docker images in addition to a pipeline and codebuild project.
Turn your project into a git repository. Push the contents to your private CodeCommit repository created by CloudFormation. Read the Amazon documentation here for detailed instructions on using Git and CodeCommit.
Warning: your project contains a certificate to connect to AWS IoT Core and may also have your wifi SSID and password. If you choose GitHub you should use a private repository only.
There are other source control options in the CloudFormation template. CodeCommit gives you an easy way to get started with private repositories. A private repository is a good way to ensure you do not expose any secrets. CodeCommit is the default source in the stack.
Create A Docker Image
Download the MCUXpresso IDE and SDK from the getting started guide from Amazon again. Download the MCUXpresso IDE for Linux as well as the SDK. These two files are used in a custom image for AWS Codebuild.
- Create a new folder on your computer
- Add the IDE .deb.bin file
- Add the SDK .zip file
- Download and modify the Dockerfile
- Change lines 5 and 6 to the SDK and IDE version you are using
This Dockerfile will set up all the dependencies required to run MCUXpresso in a Docker container. It is possible to just use gcc-arm to make a Release build. It would reduce the size of the image considerably. However, using the IDE with a few, simple, cli flags will produce a working build. It uses the same tools you are already using. This should ensure the builds are consistent and work for both development and production releases.
Build the Docker image locally:
docker build -t nxp-lpc54018-iot-module .
Push Docker Image To ECR
To use the Docker image in CodeBuild it needs to be hosted in a registry. The Cloudformation Stack that was launched earlier created a registry for you. Get the value of ECRImageName in the Outputs tab of the CloudFormation stack. Next, use the AWS CLI to login to the registry and push the Docker image into it.
Login to the registry:
$(aws ecr get-login --no-include-email --region us-west-2)
Tag the local image:
docker tag nxp-lpc54018-iot-module:latest 000000000000.dkr.ecr.us-west-2.amazonaws.com/nxp-lpc54018-iot-module:latest
Push the image into the registry:
docker push 000000000000.dkr.ecr.us-west-2.amazonaws.com/nxp-lpc54018-iot-module:latest
Replace 000000000000.dkr.ecr.us-west-2.amazonaws.com/nxp-lpc54018-iot-module with the value of ECRImageName.
The image size is a few GB in size and will take some time to upload.
Trigger The Pipeline
CodePipeline handles all the orchestration for building code. It will take a source from a repository (S3, CodeCommit, or GitHub), build the code, and produce an artifact (build).
CodePipeline can do more than this though. Actions like testing, approvals, security, and using custom environments are all possible. The MCUXpresso Docker image you built and pushed to ECR earlier is the custom build environment. This was setup automatically through CloudFormation earlier.
Make a change to the local IoT project files. Add a new line to a single file or create a new empty file to test this process. Add, commit, and push your code to CodeCommit. Head over to the CodePipeline pipeline and the source stage should start to process.
Test The Build
Once the CodeBuild project has completed you can download the build artifacts and test it on the local device. Open the CodeBuild project and click on the latest successful build. Click on the link to the Output Artifacts in the build status box. The link takes you to S3. In S3 you can download the zip file CodeBuild created. Download the file and unzip it. In the archive is a file named aws_demos.axf. AXF is an arm executable file that normally needs to be converted to run on the NXP device. However, you can use MCUXpresso to deploy directly to the device if you have the LPC Link2 debugger.
In the editor there is a button that looks like a book that opens the GUI flash tool. Click the GUI flash tool icon to open up the probe discovery dialog box. Select the LPC Link2 debugger then click ok. The next screen has a lot of settings and options available. Fortunately, you only need to worry about a couple of them. In the Target Operations sections there is a subsection titled Options. Click the File System button to choose the file to program. Make sure the format to use is set to axf. Click Run to start the process of loading the axf file onto the board.
Once the build is flashed to the device a couple of new dialogs will open in the editor. Do not close these. Once the dialogs are closed the debugger will stop and the board will no longer send messages to IoT Core.
Open the AWS IoT core test console. Enter freertos/demos/echo in the subscription topic then subscribe to topic. After a few seconds you should start receiving ACK test messages from the device.
This article goes into more detail about flashing the device.
Here are some suggestions for more work that would improve this pipeline. The very first thing you should do is remove the secrets. Keeping secrets in source control is a huge security risk. The secrets are in plain text. If the repository code accidentally enters a public repository you could leak secrets to anyone. CodeBuild supports secrets from the SSM Parameter Store. After you secure the secrets you could add some unit tests.
Unit testing the code will improve the quality of the code. Also, unit testing will give you confidence when introducing new changes. Unit tests prevent bugs and help avoid regressions. And, you will gain increased stability of the deployed application. An automated pipeline is the perfect place to run unit tests.
After adding unit tests you might consider adding a buildspec file to your repository. The CloudFormation stack that was launched contained the CodeBuild stages in the stack. Separate concerns by moving the CodeBuild stages to the code. This will allow you to put the file under version control. Changes to your code may require new build steps, tests, or linting. The configuration for how to build logically belongs next to the code to be built.
One more thing to consider is switching to gcc-arm for builds. This is a minor optimization for the build process. However, the docker image with MCUXpresso is ~4.5gb. Updating, building, and pushing changes to an image that large takes time. If you can reduce the size of the image you will reduce the cycle time of updates to that image.
Stelligent Amazon Pollycast