# Setting Up your Development Environment ## Step 1: Setup your development board ![Board layout](https://user-images.githubusercontent.com/1633960/164777317-d9f922cf-8019-4b29-8145-c92b0c4a5b85.png) 1. Verify that the 5V_USB_STLK jumper on JP4 is bridged 2. Verify that the JP3 jumper is bridged 3. Remaining jumpers should not be bridged. 4. Verify that the SW1_BOOT0 switch is in the ‘0’ position (slide to the right as shown by the blue arrow). 5. Connect a USB micro-B cable between the USB_STLK (CN8) connector and your computer. The USB_STLK port is located to the right of the MXCHIP WiFi module in the figure. It is used for power supply, programming, debugging, and interacting with the application via UART over USB. ### Update the WiFi module Firmware Depending on the board revision in use, you may need to update the wifi firmware for your board. For more information, visit the [EMW3080](https://www.st.com/en/development-tools/x-wifi-emw3080b.html) page on the ST Microelectronics website. 1. Download the [EMW3080 update tool](https://www.st.com/content/ccc/resource/technical/software/firmware/group1/48/a2/e8/27/7f/ae/4b/26/x-wifi-emw3080b/files/x-wifi-emw3080b.zip/jcr:content/translations/en.x-wifi-emw3080b.zip) from the STMicroelectronics website. 1. Unzip the archive. 1. Set the BOOT switch of SW2 to 0. 1. Connect a serial terminal program to the port connected to the STlink USB->UART. Some common options are terraterm, putty, screen, minicom, and picocom. The settings are Speed 115200, No parity, 8 bit data, 1 parity bit. >Note: You may need to remap line endings for it to display correctly. > >Input: LF -> CRLF > >Output CR -> CRLF > >For picocom, the correct mapping arguments are: ```--imap lfcrlf --omap crcrlf``` 1. Drag and drop the EMW3080updateVxxxxxx.bin binary from the archive that was unzipped in step 2 to the DIS_U585AI usb mass storage device. 1. Wait for the mass storage device to disconnect and then reconnect. 1. Press the reset (black) button to put the EMW3080 in flash mode 1. Press the user (blue) button to start flashing, and see the firmware update utility main menu on the serial console 1. Wait until the end of the flash procedure. The green LED flashes quickly during the flash procedure, and slowly when the flash procedure is over and successful. A red LED means failure. 1. Switch the SW2 BOOT switch back to the NC position. 1. Press the RST button again. [ide_url_windows]: https://www.st.com/content/ccc/resource/technical/software/sw_development_suite/group0/1e/53/08/15/0f/e2/4c/a6/stm32cubeide_win/files/st-stm32cubeide_1.9.0_12015_20220302_0855_x86_64.exe.zip/jcr:content/translations/en.st-stm32cubeide_1.9.0_12015_20220302_0855_x86_64.exe.zip [ide_url_mac]: https://www.st.com/content/ccc/resource/technical/software/sw_development_suite/group0/05/31/11/3e/76/1d/40/01/stm32cubeide_mac/files/st-stm32cubeide_1.9.0_12015_20220302_0855_x86_64.dmg.zip/jcr:content/translations/en.st-stm32cubeide_1.9.0_12015_20220302_0855_x86_64.dmg.zip [ide_url_rpm]: https://www.st.com/content/ccc/resource/technical/software/sw_development_suite/group0/e1/03/5a/6d/f4/f5/45/2c/stm32cubeide_rpm/files/st-stm32cubeide_1.9.0_12015_20220302_0855_amd64.rpm_bundle.sh.zip/jcr:content/translations/en.st-stm32cubeide_1.9.0_12015_20220302_0855_amd64.rpm_bundle.sh.zip [ide_url_deb]: https://www.st.com/content/ccc/resource/technical/software/sw_development_suite/group0/13/d4/6b/b0/d2/fd/47/6d/stm32cubeide_deb/files/st-stm32cubeide_1.9.0_12015_20220302_0855_amd64.deb_bundle.sh.zip/jcr:content/translations/en.st-stm32cubeide_1.9.0_12015_20220302_0855_amd64.deb_bundle.sh.zip [ide_url_lin]: https://www.st.com/content/ccc/resource/technical/software/sw_development_suite/group0/6c/ed/b5/05/5d/2f/44/f3/stm32cubeide_lnx/files/st-stm32cubeide_1.9.0_12015_20220302_0855_amd64.sh.zip/jcr:content/translations/en.st-stm32cubeide_1.9.0_12015_20220302_0855_amd64.sh.zip ## Step 2: Install Prerequisites Packages Using your platform's package manager, install the following prerequisites: - Python 3.10 with pip - perl - cmake - git ### Windows There are many options for downloading and installing packages on windows. Use the approach you are most comfortable with. #### Windows: Decide which shell you will use Windows has a wide variety of unix or posix-like shells available. This guide will assume you are using GitBash which is included in the git for windows package. #### Windows: Manual Installation without a Package Manager Download and install the latest version of each of the following packages: - [python](https://www.python.org/downloads/) (with pip) - [perl](https://www.perl.org/get.html) - [cmake](https://cmake.org/download/) - [git](https://git-scm.com/downloads) #### Windows: Installation with Scoop Package Manager With [scoop](https://scoop.sh/) package manager installed, run the following command from your preferred shell. ``` scoop install python cmake perl git wget ``` #### Windows: Installation with Chocolatey Package Manager With [chocolatey](https://chocolatey.org/install) installed, run the following commands from your preferred shell. ``` choco install cmake choco install wget choco install git choco install python3 choco install perl ``` #### Windows: Enable the git longpaths option: On windows, long path names can present problems with some programs that utilize legacy APIs. Enable long path support in git so that git knows long paths are supported by STM32CubeIDE and the included toolchain. Open GitBash or a similar unix-like shell environment and run the following command: ``` git config --system core.longpaths true ``` #### Windows: Add bash.exe to your Path: In order to use the stm32u5_tool.sh script and the related STM32CubeIDE launch files, you must include bash.exe in your system path. 1. Locate your preferred version of bash.exe and determine the windows path to it. For reference, the default location for GitBash is ```C:\Program Files\Git\bin```. 2. Run the following command to open the environment variable editor from Control Panel: ``` rundll32 sysdm.cpl,EditEnvironmentVariables ``` 3. Select the "Path" user environment variable and click "Edit". 4. Select "New" and then paste the path to the directory containing bash.exe found above. 5. Press OK and OK to exit the environment variable editor. 6. Log out of your windows session and then log back in to allow the environment variable changes to take effect. ### Linux Install dependencies using your distribution's package manager: #### Debian based (.deb / apt) ``` sudo apt install build-essential cmake python3 git libncurses5 libusb-1.0-0-dev ``` #### Redhat (.rpm / dnf / yum) ``` sudo dnf install -y cmake python3 git ncurses-libs libusb sudo dnf groupinstall -y "Development Tools" "Development Libraries" --skip-broken ``` ### Mac OS #### With Homebrew package manager Install the hombrew package manager from [brew.sh](https://brew.sh/) ``` brew install python cmake git libusb greadlink coreutils ``` #### Link GNU core utilities into system bin directory ``` sudo ln -s /usr/local/Cellar/coreutils/9.0_1/bin/realpath /usr/local/bin/realpath sudo ln -s /usr/local/Cellar/coreutils/9.0_1/bin/readlink /usr/local/bin/readlink ``` ## Step 3: Clone the repository and submodules Using your favorite unix-like console application, run the following commands to clone and initialize the git repository and its submodules: ``` cd git clone https://github.com/FreeRTOS/iot-reference-stm32u5.git git -C iot-reference-stm32u5 submodule update --init ``` ## Step 4: Setup your AWS account with awscli Download awscli for your platform from the [AWS website](https://aws.amazon.com/cli/) or using your preferred package manager. Follow your organization's policy regarding configuring aws cli with temporary or long term IAM credentials. If not such policy exists, refer to the instructions on the [Set up your AWS account](https://docs.aws.amazon.com/iot/latest/developerguide/setting-up.html) for details on your options. Refer to the following guides for configuring awscli depending on how your AWS account is set up: * [Configuring the AWS CLI to use AWS IAM Identity Center](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html) * [Quick configuration with aws configure](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html) ## Step 5: Install STM32CubeIDE Download the latest version of STM32CubeIDE from the [STMicroelectronics website](https://www.st.com/en/development-tools/stm32cubeide.html). Note that the projects in this repository have been verified with versions 1.8.0 and 1.9.0 of STM32CubeIDE. - [Windows][ide_url_windows] - [Mac OS][ide_url_mac] - [Debian Package bundle][ide_url_deb] - [Redhat Package bundle][ide_url_rpm] - [Generic Linux Bundle][ide_url_lin] Abridged installation instructions are included below. Please refer to the [STM32CubeIDE Installation guide](https://www.st.com/resource/en/user_manual/um2563-stm32cubeide-installation-guide-stmicroelectronics.pdf) and the included instructions for your platform if additional help is needed. ### Windows Normal Install 1. Download the [STM32CubeIDE windows zip archive][ide_url_windows]. 2. Unzip the package by double-clicking. 3. Run the extracted installer executable. ### Ubuntu Linux, Debian Linux, etc (deb package) Open a terminal window and follow the steps below to install STM32CubeIDE on a Debian based Linux machine. 1. Navigate to the [STM32CubeIDE page](https://www.st.com/en/development-tools/stm32cubeide.html) 2. Click on **Get Software** 3. In the table that is displayed, choose the row corresponding to STM32CubeIDE Generic Linux Installer 4. From the Select version dropdown, click on the download icon next to **1.9.0** to download it. 5. The installation guide is available [online](https://www.st.com/resource/en/user_manual/um2563-stm32cubeide-installation-guide-stmicroelectronics.pdf) 6. The quick start guide is available [online](https://www.st.com/resource/en/user_manual/um2553-stm32cubeide-quick-start-guide-stmicroelectronics.pdf) Extract the package ``` unzip en.st-stm32cubeide_*_amd64.deb_bundle.sh.zip ``` Add execute permissions to the install package ``` chmod +x st-stm32cubeide_*_amd64.deb_bundle.sh ``` Extract the debian packages from the bundle: ``` mkdir -p cubeide_install ./st-stm32cubeide_1.9.0_12015_20220302_0855_amd64.deb_bundle.sh --tar xvf --directory cubeide_install . ``` Install the debian packages ``` export LICENSE_ALREADY_ACCEPTED=1 sudo apt install -y ./cubeide_install/st-stm32cubeide-1.9.0-12015-20220302-0855_amd64.deb ./cubeide_install/st-stlink-udev-rules-1.0.3-2-linux-all.deb ./cubeide_install/st-stlink-server-2.1.0-1-linux-amd64.deb ``` Start the IDE ``` /opt/st/stm32cubeide_1.9.0/stm32cubeide_wayland # Or /opt/st/stm32cubeide_1.9.0/stm32cubeide ``` ### Redhat derivatives (rpm package) Open a terminal window and follow the steps below to install STM32CubeIDE on a Redhat based linux machine. Download the [STM32CubeIDE linux rpm installer package][ide_url_rpm] ``` wget ``` Extract the package ``` unzip en.st-stm32cubeide_*amd64.rpm_bundle.sh.zip ``` Add execute permissions to the install package ``` chmod +x st-stm32cubeide_*amd64.rpm_bundle.sh ``` Start the installation script and follow the prompts on the command line. ``` sudo ./st-stm32cubeide_1.9.0_12015_20220302_0855_amd64.rpm_bundle.sh ``` ### Linux - Generic Installer Open a terminal window and follow the steps below to install STM32CubeIDE on a generic linux machine. Download the STM32CubeIDE [linux generic installer package][ide_url_lin]: ``` wget ``` Extract the package ``` unzip en.st-stm32cubeide*amd64.sh.zip ``` Add execute permissions to the install package ``` chmod +x st-stm32cubeide_*amd64.sh ``` Start the installation script and follow the prompts on the command line. ``` ./st-stm32cubeide_1.9.0_12015_20220302_0855_amd64.sh ``` ### Mac OS 1. Download the [STM32CubeIDE Mac package file][ide_url_mac]: ``` wget ``` 2. Unzip the package: ``` unzip st-stm32cubeide*.dmg.zip ``` 3. Mount the resulting dmg disk image by double clicking on it. 4. Install the ST-link and/ or J-link debug tools. 5. Copy the STM32CubeIDE package to your /Applications directory. 5. Some releases of the STM32CubeIDE MacOS application is not properly signed and notarized, so the following command must be run after copying the .app to /Applications. ``` xattr -c /Applications/STM32CubeIDE.app ``` 6. Finally, open STM32CubeIDE from the Applications directory. ## Step 6: Import Projects into STM32CubeIDE 1. Open STM32CubeIDE. > NOTE - when asked to open a workspace directory, you **must** select the location in which you cloned this git repository (CODE-BASE-DIRECTORY) as the workspace directory. > > If you are not asked to select a workspace when STM32CubeIDE starts, you may access this dialog via the ***File -> Switch Workspace -> Other*** menu item. 1. Click **Launch** 2. Close the **Information Center** tab if needed 3. Select ***File -> Import***. 4. In the Import dialog box, under ***Select an Import Wizard***, select ***General -> Existing Projects Into Workspace*** and click *** Next >*** 5. Click **Browse** next to the *Select root directory* box and navigate to the root of this repository . 6. Click the check box next to both the *b_u585i_iot02a_ntz* and *b_u585i_iot02a_tfm* projects > Ensure that *copy projects into workspace* is not selected 7. Click **Finish** to import the projects. ## Step 7: Build Firmware image and Flash your development board After importing the two demo projects into STM32CubeIDE, decide which one you will build and deploy first and follow the instructions below to do so. ### Building In the **Project Explorer** pane of STM32CubeIDE, Right click on the project and select **Build Project** > Note: You may also build the current project using the **Project**->**Build Project** menu item. ### Non-TrustZone Project Review the README.md file for the [Non TrustZone](Projects/b_u585i_iot02a_ntz) project for more information on the setup and limitations of this demo project. To flash the b_u585i_iot02a_ntz project to your STM32U5 IoT Discovery Kit: 1. Choose Run -> Run Configurations 1. Choose C/C++ Application 1. Select the Flash_ntz configuration 1. Click on the Run button ### TrustZone / TF-M Enabled Project Review the README.md file for the [TrustZone Enabled](Projects/b_u585i_iot02a_tfm) project for more information on the setup and limitations of this demo project. To flash the b_u585i_iot02a_tfm project to your STM32U5 IoT Discovery Kit, select the *Flash_tfm_bl2_s_ns* configuration from the **Run Configurations** menu. ## Step 8: Provision Your Board ### Option 8A: Provision automatically with provision.py The simplest way to provision your board is to run the tools/provision.py script. After sourcing the tools/env_setup.sh script, run the folloing command: > Note: When running interactive python scripts in GitBash on Microsoft Windows, you must add "winpty " to the beginning of the command you wish to run. ``` % python tools/provision.py --interactive Target device path: /dev/cu.usbmodem143303 Connecting to target... [ INFO ] Found credentials in shared credentials file: ~/.aws/credentials (credentials.py:load) Interactive configuration mode: Press return to use defaults (displayed in brackets) time_hwm[1651013601]: mqtt_port[8883]: wifi_ssid[]: my_ssid wifi_credential[]: password mqtt_endpoint[xxxxxxxxxxxxxx-ats.iot.us-west-2.amazonaws.com]: thing_name[xxxxxxxxxxxxxxxx]: Commiting target configuration... Generating a new public/private key pair Generating a self-signed Certificate Attaching thing: xxxxxxxxxxxxxxxx to principal: arn:aws:iot:us-west-2:XXXXXXXXXXXXXX:cert/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Attaching the "AllowAllDev" policy to the device certificate. Importing root ca certificate: "Starfield Services Root Certificate Authority - G2" Provisioning process complete. Resetting target device... ``` #### Commandline Options The provision.py script has a variety of command line options that may be used to modify it's behavior. The *--verbose* option is particularly useful for debugging. The *--cert-issuer* option may be set to either *self* to generate a self-signed certificate on the device or *aws* to generate a Certificate Signing Request and issue the cert using the AWS IoT CreateCertificateFromCsr API. The *--aws* options may be used to provide AWS credentials to the script. By default, provision.py will source AWS credentials from the following sources in order: * Commandline Arguments * Environment Variables * The ~/.aws/config file, with the Profile Name specified or *default* if not specified. | Argument | Cli Argument | Env Variable | Lifetime | Description | |-------------------|---------------------------|---------------------------|----------|-------------| | Profile Name | --aws-profile | AWS_PROFILE | | Profile name for the target account used in ~/.aws/config. Only needed when authenticating via a configuration in ~/.aws/config. | | Region Name | --aws-region | AWS_DEFAULT_REGION | Long | AWS Region to connect to | | Access Key ID | --aws-access-key-id | AWS_ACCESS_KEY_ID | Short or Long | ID of a long term Access Key tied to a particular [IAM User](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html) or a short term Access Key tied to a particular [IAM Role](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html) | | Secret Access Key | --aws-secret-access-key | AWS_SECRET_ACCESS_KEY | Short or Long | The corresponding secret to the given Access Key ID | | Session Token | --aws-session-token | AWS_SESSION_TOKEN | Short | Used with temporary access credentials for an [IAM Role](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html) issued by the AWS [Security Token Service](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html) | ``` usage: provision.py [-h] [-i] [-v] [-d DEVICE] [--wifi-ssid WIFI_SSID] [--wifi-credential WIFI_CREDENTIAL] [--thing-name THING_NAME] [--cert-issuer {self,aws}] [--aws-profile AWS_PROFILE] [--aws-region AWS_REGION] [--aws-access-key-id AWS_ACCESS_KEY_ID] [--aws-secret-access-key AWS_SECRET_ACCESS_KEY] [--aws-session-token AWS_SESSION_TOKEN] optional arguments: -h, --help show this help message and exit -i, --interactive -v, --verbose -d DEVICE, --device DEVICE --wifi-ssid WIFI_SSID --wifi-credential WIFI_CREDENTIAL --thing-name THING_NAME --cert-issuer {self,aws} --aws-profile AWS_PROFILE --aws-region AWS_REGION --aws-access-key-id AWS_ACCESS_KEY_ID --aws-secret-access-key AWS_SECRET_ACCESS_KEY --aws-session-token AWS_SESSION_TOKEN ``` ### Option 8B: Provision manually via CLI Open the target board's serial port with your favorite serial terminal. Some common options are terraterm, putty, screen, minicom, and picocom. Additionally a serial terminal is included in the pyserial package installed in the workspace python environment. To use the pyserial utility, run the following command to interactively list available serial devices: > Note: When running interactive python scripts in GitBash, you must prepend "winpty " to the command you wish to run. ``` % source tools/env_setup.sh % python -m serial - 115200 --- Available ports: --- 1: /dev/cu.Bluetooth-Incoming-Port 'n/a' --- 2: /dev/cu.usbmodem143303 'STLINK-V3 - ST-Link VCP Data' --- Enter port index or full name: 2 --- Miniterm on /dev/cu.usbmodem143303 115200,8,N,1 --- --- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- ``` And select your b_u585i_iot02a board from the list by number or port name. #### Thing Name First, configure the desired thing name / mqtt device identifier: ``` > conf set thing_name my_thing_name thing_name="my_thing_name" ``` #### WiFi SSID and Passphrase Next, configure you WiFi network details: ``` > conf set wifi_ssid ssidGoesHere wifi_ssid="ssidGoesHere" > conf set wifi_credential MyWifiPassword wifi_credential="MyWifiPassword" ``` #### MQTT Endpoint Next, set the mqtt endpoint to the endpoint for your account: ``` > conf set mqtt_endpoint xxxxxxxxxxxxxx-ats.iot.us-west-2.amazonaws.com mqtt_endpoint="xxxxxxxxxxxxxx-ats.iot.us-west-2.amazonaws.com" ``` > Note: You can determine the endpoint for your AWS account with the ```aws iot describe-endpoint``` command or on the *Settings* page of the AWS IoT Core console. #### Commit Configuration Changes Finally, commit the staged configuration changes to non-volatile memory. ``` > conf commit Configuration saved to NVM. ``` #### Import the Amazon Root CA Certificate Use the *pki import cert root_ca_cert* command to import the Root CA Certificate. For this demo, we recommend you use the ["Starfield Services Root Certificate Authority - G2](https://www.amazontrust.com/repository/SFSRootCAG2.pem) Root CA Certificate which has signed all four available Amazon Trust Services Root CA certificates. Copy/Paste the contents of [SFSRootCAG2.pem](https://www.amazontrust.com/repository/SFSRootCAG2.pem) into your serial terminal after issuing the ```pki import cert``` command. ``` > pki import cert root_ca_cert -----BEGIN CERTIFICATE----- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -----END CERTIFICATE----- ``` #### Generate a private key Use the *pki generate key* command to generate a new ECDSA device key pair. The resulting public key will be printed to the console. ``` > pki generate key SUCCESS: Key pair generated and stored in Private Key Label: tls_key_priv Public Key Label: tls_key_pub -----BEGIN PUBLIC KEY----- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX= -----END PUBLIC KEY----- ``` #### Generate a self-signed certificate Next, use the *pki generate cert* command to generate a new self-signed certificate: ``` > pki generate cert -----BEGIN CERTIFICATE----- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX== -----END CERTIFICATE----- ``` Save the resulting certificate to a new file. #### Reset the target device ``` > reset Resetting device. ``` ### Register the device with AWS IoT Core: #### Register the certificate Follow the instructions at the AWS IoT Core Developer Guide to [register a client certificate](https://docs.aws.amazon.com/iot/latest/developerguide/manual-cert-registration.html#manual-cert-registration-noca-cli). ``` aws iot register-certificate-without-ca \ --status ACTIVE \ --certificate-pem file://device_cert_filename.pem ``` #### Register the Thing Name ``` aws iot create-thing \ --thing-name SampleIoTThing ``` #### Attach the Certificate to the thing ``` aws iot attach-thing-principal \ --principal certificateArn \ --thing-name thingName ``` #### Register a policy if none exists: ``` aws iot create-policy \ --policy-name="AllowAllDev" \ --policy-document="{ \"Version\": \"2012-10-17\", \"Statement\": [{\"Effect\": \"Allow\", \"Action\": \"iot:*\", \"Resource\": \"*\"}]}" ``` > Note: This policy allows very broad access to AWS IoT MQTT APIs. Use a more restrictive policy for any production environments. #### Attach a security policy ``` aws iot attach-policy \ --target certificateArn \ --policy-name AllowAllDev ``` # Observe MQTT messages on the AWS IoT Core Console. Log in to the [AWS console](https://console.aws.amazon.com) with the IAM User created earlier in this guide. Navigate to the **IoT Core** service using the search box at the top of the page. Using the menu on the left side of the screen, select **Test**->**MQTT test client** Set the topic filter to *#* and click the *Subscribe* button. 23 You will soon see sensor data streaming from your test device. > Note: You may first need to reset the board using the black *RST* button. 24 # Setting up FreeRTOS OTA ## Generate a Code Signing key Devices use digital signatures to verify the authenticity of the firmware updates sent over the air. Images are signed by an authorized source who creates the image, and a device can verify the signature of the image, using the corresponding public key of the signer. The steps below show how to setup and provision the code signing credentials so as to enable an image to be signed in the cloud and the device to verify the image signature before boot. 1. In your working directory, use the following text to create a file named *cert_config.txt*. Replace *test_signer@amazon.com* with your email address: ``` [ req ] prompt = no distinguished_name = my_dn [ my_dn ] commonName = test_signer@amazon.com [ my_exts ] keyUsage = digitalSignature extendedKeyUsage = codeSigning ``` 2. 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-priv-key.pem ``` 3. Generate the corresponding public key from the private key: ``` openssl ec -inform pem -in ecdsasigner-priv-key.pem -pubout -outform pem -out ecdsasigner-pub-key.pem ``` 4. Create an ECDSA code-signing certificate to be uploaded to the AWS ACM service: ``` openssl req -new -x509 -config cert_config.txt -extensions my_exts -nodes -days 365 -key ecdsasigner-priv-key.pem -out ecdsasigner.crt ``` 5. Import the code-signing certificate and private key into AWS Certificate Manager: > Note: This command displays an ARN for your certificate. You will need this ARN when you create an OTA update job later. ``` aws acm import-certificate --certificate fileb://ecdsasigner.crt --private-key fileb://ecdsasigner-priv-key.pem ``` 6. Connect to the target device via a serial terminal. On the command line prompt type following command to import the OTA signing key: ``` > pki import key ota_signer_pub # Press `Enter` then paste the contents of the PEM public key file `ecdsasigner-pub-key.pem` into the terminal. # Press `Enter` again. ``` > Note: `ota_signer_pub` is the label used to refer to the code signing key during verification of the firmware update. 7. Create a signing profile in AWS to sign the firmware image. ``` aws signer put-signing-profile --profile-name --signing-material certificateArn= --platform AmazonFreeRTOS-Default --signing-parameters certname=ota_signer_pub ``` ## Setup Amazon S3 bucket for OTA, Service role and policies in AWS 1. Amazon S3 bucket is used to store the new firmware image to be updated. To create a new S3 bucket follow the steps here: https://docs.aws.amazon.com/freertos/latest/userguide/dg-ota-bucket.html 2. Create a service role which grants permission for OTA service to access the firmware image: https://docs.aws.amazon.com/freertos/latest/userguide/create-service-role.html 3. Create an OTA update policy using the documentatio here: https://docs.aws.amazon.com/freertos/latest/userguide/create-ota-user-policy.html 4. Add a policy for AWS IoT to access the code signing profile: https://docs.aws.amazon.com/freertos/latest/userguide/code-sign-policy.html ## Create a code signed firmware update job 1. Bump up the version of the new firmware image to be updated. From the demo project, open File `Src/ota_pal/ota_firmware_version.c` and set APP_VERSION_MINOR (or APP_VERSION_MAJOR) to 1 higher than the current version. 1. Build the firmware image using STM32Cube IDE as detailed in section 7. 1. Upload the new image to the S3 bucket created in the previous section. ``` aws s3 cp s3:/// ``` Get the latest s3 file version of the binary image by executing the command below. The command returns an array of json structs containing details of all version. To get the latest version ID, look for *VersionId* field in the json struct where *isLatest* field is *true*. ``` aws s3api list-object-versions --bucket --prefix ``` 3. Create a new OTA Update job configuration json file (Example: ota-update-job-config.json) in your filesystem as below. Substitue the parameters with the output obtained from steps above. ``` { "otaUpdateId": "", "targets": [ "arn:aws:iot:::thing/" ], "targetSelection": "SNAPSHOT", "files": [{ "fileName": "", "fileVersion": "1", "fileLocation": { "s3Location": { "bucket": "", "key": "", "version": "" } }, "codeSigning": { "startSigningJobParameter": { "signingProfileName": "", "destination": { "s3Destination": { "bucket": "" } } } } }], "roleArn": "" } ``` Create a new OTA update job from the configuration file: ``` aws iot create-ota-update --cli-input-json file:// ``` The command on success returns the OTA Update identifier and status of the Job as `CREATE_PENDING`. To get the corresponding job ID of the OTA Job, execute the following command and look for `awsIotJobId` field in json document returned. ``` aws iot get-ota-update --ota-update-id= ``` Note down the job ID to check the status of the job later. #### Monitoring and Verification of firmware update Once the job is created on the terminal logs, you will see that OTA job is accepted and device starts downloading image. Create a new OTA update job from the configuration file: ``` aws iot create-ota-update --cli-input-json file:// ``` The command on success returns the OTA Update identifier and status of the Job as *CREATE_PENDING*. To get the corresponding job ID of the OTA Job, execute the following command and look for *awsIotJobId* field in json document returned. ``` aws iot get-ota-update --ota-update-id= ``` Note down the job ID to check the status of the job later. ## Monitoring and Verification of firmware update 1. Once the job is created on the terminal logs, you will see that OTA job is accepted and device starts downloading image. ``` 16351 [OTAAgent] Current State=[WaitingForFileBlock], Event=[RequestFileBlock], New state=[WaitingForFileBlock] (ota.c:2834) 15293 [OTAAgent] Extracted parameter: [key: value]=[execution.jobDocument.afr_ota.streamname: AFR_OTA-eb53bc47-6918-4b2c-9c85-a4c74c44a04c] (ota.c:1642) 15294 [OTAAgent] Extracted parameter: [key: value]=[execution.jobDocument.afr_ota.protocols: ["MQTT"]] (ota.c:1642) 15296 [OTAAgent] Extracted parameter: [key: value]=[filepath: b_u585i_iot02a_ntz.bin] (ota.c:1642) 17784 [OTAAgent] Current State=[WaitingForFileBlock], Event=[RequestFileBlock], New state=[WaitingForFileBlock] (ota.c:2834) 15297 [OTAAgent] Extracted parameter: [key: value]=[fileid: 0] (ota.c:1683) 15298 [OTAAgent] Extracted parameter: [key: value]=[certfile: ota_signer_pub] (ota.c:1642) 15300 [OTAAgent] Extracted parameter [ sig-sha256-ecdsa: MEUCIGWRkFqcumdPZhoZ93ov5Npvsjj7... ] (ota.c:1573) 15301 [OTAAgent] Extracted parameter: [key: value]=[fileType: 0] (ota.c:1683) 15301 [OTAAgent] Job document was accepted. Attempting to begin the update. (ota.c:2199) 16533 [OTAAgent] Number of blocks remaining: 306 (ota.c:2683) 15450 [OTAAgent] Setting OTA data interface. (ota.c:938) 15450 [OTAAgent] Current State=[Creating ``` 2. Once the full image has been downloaded, the OTA library verifies the image signature and activates the new image in the alternate flash bank. ``` 67405 [OTAAgent] Received final block of the update. (ota.c:2633) 67405 [OTAAgent] Validating the integrity of OTA image using digital signature. (ota_pal.c:681) 69643 [OTAAgent] Received entire update and validated the signature. (ota.c:2654) ``` 3. The New image boots up and performs a self test, where it checks the version is higher than the current version. If yes, it sets the new image as valid. ``` 15487 [OTAAgent] In self test mode. (ota.c:2102) 15487 [OTAAgent] New image has a higher version number than the current image: New image version=1.9.0, Previous image version=0.9.0 (ota.c:1932) ``` 4. Checking the job status, should show the job as succeeded: ``` aws iot describe-job-execution --job-id= --thing-name= ```