Tutorial: Build and debug partner applications

This tutorial shows how to build and debug a sample project that includes both a high-level application and a real-time capable application, where the two apps communicate between the high-level A7 core and real-time M4 core. See Overview of Azure Sphere applications for basic information about high-level applications and real-time capable applications.

In this tutorial, you will learn how to:

  • Install the GNU Arm toolchain
  • Set up hardware to display output
  • Enable development and debugging
  • Clone the Azure Sphere sample repo
  • Start a terminal emulator to view output
  • Build, run, and debug a pair of partner applications

Important

These instructions assume you are using hardware that follows the MT3620 reference board design (RDB) hardware, such as the MT3620 Dev Kit from Seeed Studios. If you are using different Azure Sphere hardware, consult the manufacturer's documentation to find out whether the UART is exposed and how to access it. You might need to set up hardware to display output differently and update the sample code and the Uarts field of the app_manifest.json file to use a different UART.

Prerequisites

Install the GNU Arm Embedded Toolchain

  • Visual Studio 2022: If you're using Visual Studio 2022, install the GNU Arm Embedded Toolchain (arm-none-eabi) from the Arm developer website.
  • Visual Studio 2019: The toolchain is automatically installed with the Azure Sphere extension for Visual Studio on Visual Studio 2019. If you're using Visual Studio 2019, proceed to Set up hardware to display output. However, if you installed the GNU Arm Embedded Toolchain manually, Visual Studio will use the version you installed.

To install the toolchain on the Arm developer website, find the GNU Arm Embedded Toolchain (arm-none-eabi) that includes the compiler for the ARM Cortex-M4 processor. Follow the instructions there to download and install the compiler for your OS platform.

By default, Visual Studio Code searches for the toolchain and should find the version you installed. If you encounter build problems related to the toolchain, check Preferences > Settings > Extensions > AzureSphere to ensure that "Azure Sphere: Arm Gnu Path" identifies the GNU Arm Embedded Toolchain installation directory.

Set up hardware to display output

Currently, each real-time core supports a TX-only UART. RTApps can use this UART to send log output from the device. During application development and debugging, you typically need a way to read and display the output. The HelloWorld_RTApp_MT3620_BareMetal sample shows how an application can write to the UART.

Use a USB-to-serial adapter such as the FTDI Friend, to connect the UART on the real-time core to a USB port on your machine. You will also need a terminal emulator to establish a serial connection with 115200-8-N-1 terminal settings (115200 bps, 8 bits, no parity bits, one stop bit) to display the output.

To set up the hardware to display output from an RTApp, follow these steps. You'll need to refer to the documentation from your hardware manufacturer to determine the pin locations. If you're using hardware that follows the MT3620 reference board design (RDB) hardware, like the MT3620 Dev Kit from Seeed Studios, then looking at the RDB interface headers may help you to determine the pin locations.

  1. Connect GND on the USB-to-serial adapter to GND on your dev kit. On MT3620 RDB hardware, GND is Header 3, pin 2.

  2. Connect RX on the USB-to-serial adapter to IOM4-0 TX on your dev kit. On MT3620 RDB hardware, IOM4-0 TX is Header 3, pin 6.

  3. Connect the USB-to-serial adapter to a free USB port on your development machine and determine which port the serial device is connected to.

    • On Windows, start Device Manager, select View > Devices by container, and look for 'USB UART". For example, FT232R USB UART indicates the FTDI Friend adapter.

    • On Linux, type the following command:

      dmesg | grep ttyUSB
      

      The port should be named ttyUSBn, where n indicates the port number. If the dmesg command lists several USB ports, the one that is connected to the typically the last one reported as attached. For example, in the following, you would use ttyUSB4:

    ~$ dmesg | grep ttyUSB
    [  144.564350] usb 1-1.1.2: FTDI USB Serial Device converter now attached to ttyUSB0
    [  144.564768] usb 1-1.1.2: FTDI USB Serial Device converter now attached to ttyUSB1
    [  144.565118] usb 1-1.1.2: FTDI USB Serial Device converter now attached to ttyUSB2
    [  144.565593] usb 1-1.1.2: FTDI USB Serial Device converter now attached to ttyUSB3
    [  144.570429] usb 1-1.1.3: FTDI USB Serial Device converter now attached to ttyUSB4
    [  254.171871] ftdi_sio ttyUSB1: FTDI USB Serial Device converter now disconnected from ttyUSB1
    
  4. Start a terminal emulator program and open a 115200-8-N-1 terminal to the COM port used by the adapter. See the documentation for the terminal emulator to find out how to specify the port and speed.

Enable development and debugging

Before you can build a sample application on your Azure Sphere device or develop new applications for it, you must enable development and debugging. By default, Azure Sphere devices are "locked"; that is, they do not allow applications under development to be loaded from a PC, and they do not allow debugging of applications. Preparing the device for debugging removes this restriction and loads software required for debugging and unlocks device capabilities .

To debug on the real-time cores, use the az sphere device enable-development command. This command configures the device to accept applications from a PC for debugging and assigns the device to the Development device group, which does not allow cloud application updates. During application development and debugging, you should leave the device in this group so that cloud application updates do not overwrite the application under development.

On Windows, you must add the --enable-rt-core-debugging parameter, which loads the debugging servers and required drivers for each type of core onto the device.

  1. Log in to Azure Sphere if you haven't already done so:

    az login
    
  2. Open a command-line interface using PowerShell or Windows Command Prompt with administrator privileges. The --enable-rt-core-debugging parameter requires administrator privilege because it installs USB drivers for the debugger.

  3. Enter the following command:

    az sphere device enable-development --enable-rt-core-debugging  --catalog <CatalogName>  --resource-group <ResourceGroupName>
    
  4. Close the window after the command completes because administrator privilege is no longer required. As a best practice, you should always use the lowest privilege that can accomplish a task.

If the az sphere device enable-development command fails, see Troubleshoot Azure Sphere problems for help.

Download the sample application

You can download the InterCore Communications applications as follows:

  1. Point your browser to Microsoft Samples Browser.
  2. Type "Azure Sphere" in the Search box.
  3. Select Azure Sphere - Inter-core Communications from the search results.
  4. Select Download ZIP.
  5. Open the downloaded file and extract to a local directory.

Build and run the partner applications

  1. Start Visual Studio. Select Open a local folder, and navigate to the folder where you extracted the IntercoreComms applications.

    Important

    If you are using Visual Studio 2022 version 17.1 or later, and you extracted the IntercoreComms sample prior to the 22.02 Azure Sphere release, you must add a CMakeWorkspaceSettings.json file to your top-level project folder.

  2. If you are not using an MT3620 RDB, update the app_manifest.json files for both applications and the hardware definition file and CMakeLists.txt file for the high-level application to match your hardware.

  3. If CMake generation does not start automatically, select the CMakeLists.txt file.

  4. In Visual Studio, View > Output > Show output from: CMake output should show the messages CMake generation started and CMake generation finished.

  5. Select Build > Build All. If the menu is not present, open Solution Explorer, right-click the CMakeLists.txt file, and select Build. The output location of the IntercoreComms_HL & IntercoreComms RT applications appear in the Output window.

  6. Select Select Startup Item > IntercoreComms (All cores).

  7. Select Debug > Debug or press F5 to deploy and debug the applications.

  8. In the Output window, Select output from menu, select Device Output. The Output window should show the high-level application output:

    Remote debugging from host 192.168.35.1, port 58817
    High-level intercore comms application
    Sends data to, and receives data from a real-time capable application.
    Received 19 bytes: rt-app-to-hl-app-07
    Sending: hl-app-to-rt-app-00
    Sending: hl-app-to-rt-app-01
    
  9. The connected terminal emulator should display output from the real-time capable program:

    Sender: 25025d2c-66da-4448-bae1-ac26fcdd3627
    Message size: 19 bytes:
    Hex: 68:6c:2d:61:70:70:2d:74:6f:2d:72:74:2d:61:70:70:2d:30:30
    Text: hl-app-to-rt-app-00
    Sender: 25025d2c-66da-4448-bae1-ac26fcdd3627
    Message size: 19 bytes:
    Hex: 68:6c:2d:61:70:70:2d:74:6f:2d:72:74:2d:61:70:70:2d:30:31
    Text: hl-app-to-rt-app-01
    
  10. Use the debugger to set breakpoints, inspect variables, and try other debugging tasks.

  1. In Visual Studio Code, open the folder where you extracted the IntercoreComms applications. Visual Studio Code detects the intercore.code-workspace file and asks if you want to open the workspace. Select Open Workspace to open both the real-time application and high-level application at once.

  2. If you are not using an MT3620 RDB, update the app_manifest.json files for both applications and the hardware definition file and CMakeLists.txt file for the high-level application to match your hardware.

  3. Press F5 to start the debugger. If the project has not previously been built, or if files have changed and rebuild is required, Visual Studio Code will build the project before debugging starts.

  4. The Azure Sphere output window should show "Deploying image..." followed by the paths to the SDK and compiler.

  5. The output window should show the high-level application output:

    Remote debugging from host 192.168.35.1, port 58817
    High-level intercore comms application
    Sends data to, and receives data from a real-time capable application.
    Received 19 bytes: rt-app-to-hl-app-07
    Sending: hl-app-to-rt-app-00
    Sending: hl-app-to-rt-app-01
    
  6. The connected terminal emulator should display output from the real-time capable program:

    Sender: 25025d2c-66da-4448-bae1-ac26fcdd3627
    Message size: 19 bytes:
    Hex: 68:6c:2d:61:70:70:2d:74:6f:2d:72:74:2d:61:70:70:2d:30:30
    Text: hl-app-to-rt-app-00
    Sender: 25025d2c-66da-4448-bae1-ac26fcdd3627
    Message size: 19 bytes:
    Hex: 68:6c:2d:61:70:70:2d:74:6f:2d:72:74:2d:61:70:70:2d:30:31
    Text: hl-app-to-rt-app-01
    
  7. Use Visual Studio Code debugging features to set breakpoints, inspect variables, and try other debugging tasks.

Troubleshooting

The application might begin executing before OpenOCD makes a connection. As a result, breakpoints set early in the code might be missed. A simple workaround for this is to delay the start of the app until OpenOCD connects.

  1. Insert the following code at the beginning of the application entry point RTCoreMain. This will cause the application to enter and remain in a while loop until variable f is set to true.

    static _Noreturn void RTCoreMain(void)
    {
      .
      .
      .
     volatile bool f = false;
     while (!f) {
        // empty.
     }
      .
      .
      .
    }
    
  2. Press F5 to start the app with debugging and then break into execution.

  3. In the Locals debug pane, change the value of f from zero to one.

  4. Step through the code as usual.

When building with the CLI, you first build and deploy the real-time capable application, then build and deploy the high-level application.

Build and deploy the real-time capable application

  1. Navigate to the folder where you extracted the IntercoreComms applications and then select the IntercoreComms/IntercoreComms_RTApp_MT3620_BareMetal folder.

  2. Open the app_manifest.json file and verify that the high-level app's component ID is shown in the AllowedApplicationConnections capability.

  3. Open a command-line interface using PowerShell, Windows Command Prompt, or Linux command shell. Navigate to your project build directory.

  4. From your project build directory, at the command prompt, run CMake with the following parameters:

    cmake --preset <preset-name> <source-path>
    
    • --preset <preset-name>

      The build configuration preset name as defined in CMakePresets.json.

    • --build <cmake-path>

      The binary directory that contains the CMake cache. For example, if you run CMake on an Azure Sphere sample, the build command would be cmake --build out/ARM-Debug.

    • <source-path>

      The path of the directory that contains the source files for the sample application. In the example, the Azure Sphere samples repository was downloaded to a directory called AzSphere.

      CMake parameters are separated by spaces. The line continuation character (^ for Windows command line, \ for Linux command line, or ` for PowerShell) can be used for readability, but is not required.

    The following examples show the CMake commands for the IntercoreComms RTApp:

    Windows Command Prompt

     cmake ^
    --preset "ARM-Debug" ^
     "C:\AzSphere\azure-sphere-samples\Samples\IntercoreComms\IntercoreComms_RTApp_MT3620_BareMetal"
    

    Windows PowerShell

     cmake `
    --preset "ARM-Debug" `
     "C:\AzSphere\azure-sphere-samples\Samples\IntercoreComms\IntercoreComms_RTApp_MT3620_BareMetal"
    
  5. From your project build directory, at the command prompt, run Ninja to build the application and create the image package file.

    ninja -C out/ARM-Debug
    

    Ninja places the resulting application and .imagepackage files in the specified directory.

    You can also invoke Ninja through CMake with the following command:

    cmake --build out/<binary-dir>
    

    Set <binary-dir> to the binary directory that contains the CMake cache. For example, if you run CMake on an Azure Sphere sample, the build command would be cmake --build out/ARM-Debug.

    When troubleshooting, especially after making any changes to your CMake commands, delete your entire build and try again.

  6. Delete any applications that are already deployed to the device:

    az sphere device sideload delete
    
  7. From your project build directory, at the command prompt, load the image package that ninja created:

    az sphere device sideload deploy --image-package <path-to-imagepackage>
    

    The application will start to run soon after it's loaded.

  8. Get the component ID for the image:

    az sphere image-package show --image-package <path-to-imagepackage>
    

    The command returns all the metadata for the image package. The component ID for the application appears in the Identity section for the Application Image Type. For example:

    ...
      "Identity": {
        "ComponentId": "<component-id>",
        "ImageId": "<image-id>",
        "ImageType": "Application"
      },
    ...
    

Build and deploy the high-level application

  1. Navigate to the folder where you extracted the IntercoreComms applications and then select the IntercoreComms/IntercoreComms_HighLevelApp folder.

  2. Open the app_manifest.json file and verify that the RTApp's component ID is shown in the AllowedApplicationConnections capability.

  3. Open a command-line interface using PowerShell, Windows Command Prompt, or Linux command shell. Navigate to your project build directory.

  4. From your project build directory, at the command prompt, run CMake with the following parameters:

    cmake --preset <preset-name> <source-path>
    
    • --preset <preset-name>

      The build configuration preset name as defined in CMakePresets.json.

    • --build <cmake-path>

      The binary directory that contains the CMake cache. For example, if you run CMake on an Azure Sphere sample, the build command would be cmake --build out/ARM-Debug.

    • <source-path>

      The path of the directory that contains the source files for the sample application. In the example, the Azure Sphere samples repository was downloaded to a directory called AzSphere.

      CMake parameters are separated by spaces. The line continuation character (^ for Windows command line, \ for Linux command line, or ` for PowerShell) can be used for readability, but is not required.

    The following examples show the CMake commands for the IntercoreComms high-level application.

    Windows Command Prompt

     cmake ^
     --preset "ARM-Debug" ^
     "C:\AzSphere\azure-sphere-samples\Samples\IntercoreComms\IntercoreComms_HighLevelApp"
    

    Windows PowerShell

     cmake `
     --preset "ARM-Debug" `
     "C:\AzSphere\azure-sphere-samples\Samples\IntercoreComms\IntercoreComms_HighLevelApp"
    
  5. From your project build directory, at the command prompt, run Ninja to build the application and create the image package file.

    ninja -C out/ARM-Debug
    

    Ninja places the resulting application and .imagepackage files in the specified directory.

    You can also invoke Ninja through CMake with the following command:

    cmake --build out/<binary-dir>
    

    Set <binary-dir> to the binary directory that contains the CMake cache. For example, if you run CMake on an Azure Sphere sample, the build command would be cmake --build out/ARM-Debug.

    When troubleshooting, especially after making any changes to your CMake commands, delete your entire build and try again.

  6. From your project build directory, at the command prompt, load the image package that ninja created:

    az sphere device sideload deploy --image-package <package-name>
    

    The application will start to run soon after it's loaded.

  7. Get the component ID for the image:

    az sphere image-package show --image-package <path-to-imagepackage>
    

    The command returns all the metadata for the image package. The component ID for the application appears in the Identity section for the Application Image Type. For example:

    ...
      "Identity": {
        "ComponentId": "<component-id>",
        "ImageId": "<image-id>",
        "ImageType": "Application"
      },
    ...
    

Run the partner applications with debugging enabled

  1. Stop the real-time application if it's running.

    az sphere device app stop --component-id <component id>
    
  2. Re-start the application for debugging.

    az sphere device app start -- --debug-mode true --component-id <component id>
    

    This command returns the core on which the application is running.

      <component id>
      App state: running
      Core        : Real-time 0
    
  3. Navigate to the Openocd folder for the sysroot that the application was built with. The sysroots are installed in the Azure Sphere SDK installation folder. For example, on Windows the folder is installed by default at C:\Program Files (x86)\Microsoft Azure Sphere SDK\Sysroots\*sysroot*\tools\openocd and on Linux, at /opt/azurespheresdk/Sysroots/*sysroot*/tools/sysroots/x86_64-pokysdk-linux.

  4. Run openocd as the following example shows. The example assumes the app is running on core 0. If the app is running on core 1, replace "targets io0" with "targets io1".

       openocd -f mt3620-rdb-ftdi.cfg -f mt3620-io0.cfg -c "gdb_memory_map disable" -c "gdb_breakpoint_override hard" -c init -c "targets io0" -c halt -c "targets"
    
  5. Open a new Azure Sphere Command Prompt (Windows Azure Sphere classic CLI), standard command prompt or PowerShell (Windows Azure CLI), or terminal window (Linux).

  6. Navigate to the folder that contains the real-time capable application .out file and start arm-none-eabi-gdb, which is part of the GNU Arm Embedded Toolchain:

    Windows Command Prompt

    "C:\Program Files (x86)\GNU Arm Embedded Toolchain\9 2020-q2-update\bin\arm-none-eabi-gdb" IntercoreComms_RTApp_MT3620_BareMetal.out
    

    Windows PowerShell

     & "C:\Program Files (x86)\GNU Arm Embedded Toolchain\9 2020-q2-update\bin\arm-none-eabi-gdb" IntercoreComms_RTApp_MT3620_BareMetal.out
    
  7. The OpenOCD server provides a GDB server interface on :4444. Set the target for debugging.

    target remote :4444

  8. You can now run gdb commands to the real-time capable application. Add a breakpoint at the function HandleSendTimerDeferred:

    break HandleSendTimerDeferred
    
  9. The connected terminal emulator should display output from the real-time capable application.

  10. Open a new Azure Sphere Command Prompt (Windows Azure Sphere classic CLI), standard command prompt or PowerShell (Windows Azure CLI), or terminal window (Linux).

  11. Navigate to the folder that contains the high-level application .imagepackage file.

  12. Stop the high-level application if it's running.

    az sphere device app stop --component-id <component id>
    
  13. Re-start the high-level application with debugging.

    az sphere device app start --debug-mode true --component-id <component id> --debug-mode
    
  14. Open a terminal emulator and establish a Telnet or TCP connection to 192.168.35.2 at port 2342 to view the high-level app's output.

  15. Start gdb with the following command:

    Windows Command Prompt

    "C:\Program Files (x86)\Microsoft Azure Sphere SDK\Sysroots\*sysroot*\tools\gcc\arm-poky-linux-musleabi-gdb.exe" IntercoreComms_HighLevelApp.out
    

    Windows PowerShell

    & "C:\Program Files (x86)\Microsoft Azure Sphere SDK\Sysroots\*sysroot*\tools\gcc\arm-poky-linux-musleabi-gdb.exe" IntercoreComms_HighLevelApp.out
    

    Note

    The Azure Sphere SDK ships with multiple sysroots so that applications can target different API sets, as described in Application runtime version, sysroots, and Beta APIs. The sysroots are installed in the Azure Sphere SDK installation folder under Sysroots.

  16. Set the remote debugging target to IP address 192.168.35.2 on port 2345:

    target remote 192.168.35.2:2345

  17. Add a breakpoint at the function SendMessageToRTApp:

    break SendMessageToRTApp

  18. Type c to continue, observe the output in your Telnet/TCP terminal, then switch to the command prompt or terminal window containing your real-time application debugging session.

  19. Type c to continue and observe the output in your connected serial session.

You can work back and forth between debugging sessions, switching between the real-time capable application and the high-level application. You should see output similar to the following in the two output windows:

Starting debugger....
                     Process /mnt/apps/25025d2c-66da-4448-bae1-ac26fcdd3627/bin/app created; pid = 40
                     Listening on port 2345
                                           Remote debugging from host 192.168.35.1, port 56522
              High-level intercore comms application
                                                    Sends data to, and receives data from a real-time capable application.
                                          Sending: hl-app-to-rt-app-00
                                                                      Sending: hl-app-to-rt-app-01
IntercoreComms_RTApp_MT3620_BareMetal
App built on: Nov 17 2020, 09:25:19
Sender: 25025d2c-66da-4448-bae1-ac26fcdd3627
Message size: 19 bytes:
Hex: 68:6c:2d:61:70:70:2d:74:6f:2d:72:74:2d:61:70:70:2d:30:30
Text: hl-app-to-rt-app-00

To end each debugging session, type q at the gdb prompt.

Next steps