Skip to content

Arm-Examples/Hello_World

Repository files navigation

License

Hello, World! (CMSIS Solution Example)

This is a minimal Hello, World! application for Arm Cortex-M devices using the CMSIS Solution project format.

This example demonstrates:

  • A portable CMSIS-Core based application.
  • Build, load, and debug using Arm Keil Studio for VS Code.
  • Simple retargetable output (“Hello, World!”) via a serial I/O message channel.

The project is intentionally simple and designed to scale: changing the board, serial I/O, RTOS , or debug adapter is straightforward using Arm Keil Studio.

Current Setup

The setup in this repository is for the Infineon XMC2Go development board using serial I/O via semihosting to a Telnet port. If you are using a different board refer to Change Target Hardware.

Note

STM32 boards use typically a STM32CubeMX based configuration with different startup code. Refer to an STM32 based example, i.e. Hello_B-U585I-IOT02A.

Quick Start

  1. Install Keil Studio for VS Code from the VS Code marketplace.

  2. Clone this Git repository into a VS Code workspace.

  3. The related tools and software packs are downloaded and installed. Review progress with View - Output - CMSIS Solution.

  4. In the CMSIS view, use the Action buttons to build, load and debug the example on the hardware.

  5. In the VS Code Panel, click on SERIAL MONITOR. Select the Monitor Mode "TCP" and set Host to localhost and Port to 4444. Observe the output:

    SEGGER J-Link GDB Server V9.10 - Terminal output channel
    Hello, World!
    Hello, World!
    Hello, World!
    ...

Change Target Hardware

This application is a generic CMSIS example that will run on any target hardware. If you want to change to another development board/device, edit the following.

In the Hello.csolution.yml file, add the device's/board's CMSIS-Packs:

  packs:
    - pack: ARM::CMSIS
    - pack: Infineon::XMC1000_DFP # Change to the right CMSIS-Pack

Then, change the target-type:/- type to a new name and enter the correct device:/board: names:

  # List different hardware targets that are used to deploy the solution.
  target-types:
    - type: XMC1100-Q024x0064  # Change to a meaningful name
      target-set:
        - set:
          images:
            - project-context: Hello.Debug
          debugger:
            name: J-Link Server
            clock: 4000000
            protocol: swd
      device: XMC1100-Q024x0064  # Change to actual device
      board: XMC 2Go:V1          # Change to actual board

Change the RTOS

This example is using the CMSIS-RTOS v2 API with CMSIS-FreeRTOS as the underlying real-time operating system kernel.

To change the kernel to Keil RTX5 exchange in the file Hello.cproject.yml:

  components:
    - component: CMSIS:RTOS2:FreeRTOS&Cortex-M
    - component: RTOS&FreeRTOS:Config&CMSIS RTOS2
    - component: RTOS&FreeRTOS:Core&Cortex-M
    - component: RTOS&FreeRTOS:Event Groups
    - component: RTOS&FreeRTOS:Timers
    - component: RTOS&FreeRTOS:Heap&Heap_4

  packs:
    - pack: ARM::CMSIS-FreeRTOS

with:

  components:
    - component: CMSIS:RTOS2:Keil RTX5&Source

  packs:
    - pack: ARM::CMSIS-FreeRTOS

Serial I/O via UART

While semihosting requires not hardware configuration and can be easily used for quick debugging, it is not recommended for production systems (due to intrusive and slow communication). A viable option is to use a UART (serial port) instead. The following explains how to use the on-chip UART which is available through the Segger J-Link debug adapter for printf output.

Caution

The following is specific for the XMC2Go development board. If you have changed the target hardware, consult your board specific documentation to select the right software components and CMSIS-Packs.

To redirect the output to a UART:

  1. Add the following pack and software components in the Hello.cproject.yml file:
  packs: 
    - pack: ARM::CMSIS-Compiler

  components:
    - component: CMSIS-Compiler:CORE
    - component: CMSIS-Compiler:STDOUT:Custom
    - component: CMSIS Driver:USART
    - component: Device:RTE_Device
    - component: Device:XMClib:GPIO
    - component: Device:XMClib:SCU
    - component: Device:XMClib:UART
  1. Add the interface code to UART channel

In the Keil Studio CMSIS view, click on the + sign next to Application and select Add From Component Code Template:

Add code template

Then, select CMSIS-Compiler:STDOUT:Custom which adds a stdout_user.c file to the Application group. Add this code in the file:

#include "retarget_stdout.h"
#include "Driver_USART.h"

#include <stdint.h>

extern ARM_DRIVER_USART Driver_USART0;

static ARM_DRIVER_USART * const stdout_usart = &Driver_USART0;
static uint8_t stdout_usart_initialized;

#ifndef STDOUT_USART_BAUDRATE
#define STDOUT_USART_BAUDRATE 115200U
#endif

static int stdout_usart_ensure_initialized (void) {
  int32_t status;

  if (stdout_usart_initialized != 0U) {
    return 0;
  }

  status = stdout_usart->Initialize(NULL);
  if (status != ARM_DRIVER_OK) {
    return -1;
  }

  status = stdout_usart->PowerControl(ARM_POWER_FULL);
  if (status != ARM_DRIVER_OK) {
    return -1;
  }

  status = stdout_usart->Control(
    ARM_USART_MODE_ASYNCHRONOUS |
    ARM_USART_DATA_BITS_8       |
    ARM_USART_PARITY_NONE       |
    ARM_USART_STOP_BITS_1       |
    ARM_USART_FLOW_CONTROL_NONE,
    STDOUT_USART_BAUDRATE
  );
  if (status != ARM_DRIVER_OK) {
    return -1;
  }

  status = stdout_usart->Control(ARM_USART_CONTROL_TX, 1U);
  if (status != ARM_DRIVER_OK) {
    return -1;
  }

  stdout_usart_initialized = 1U;
  return 0;
}

/**
  Put a character to the stdout

  \param[in]   ch  Character to output
  \return          The character written, or -1 on write error.
*/
int stdout_putchar (int ch) {
  uint8_t c;

  if (stdout_usart_ensure_initialized() != 0) {
    return -1;
  }

  /* If caller prints bare '\n', emit CRLF on the wire. */
  if ((uint8_t)ch == (uint8_t)'\n') {
    (void)stdout_putchar('\r');
  }

  /* Serialize by waiting for any previous send to complete. */
  while (stdout_usart->GetStatus().tx_busy != 0U) {
  }

  c = (uint8_t)ch;
  if (stdout_usart->Send(&c, 1U) != ARM_DRIVER_OK) {
    return -1;
  }

  while (stdout_usart->GetStatus().tx_busy != 0U) {
  }

  return ch;
}
  1. Configure UART pins

The UART that is connected to the Segger J-Link uses the the ports P2.1 and P2.2 on the device. You need to configure this in the RTE_Device.h file.

  • In the CMSIS view, expand Device_RTE_Device and click on the RTE_Device.h file. This file is annotated for Configuration Wizard view which can be enabled by pressing the Open configuration wozard view button at the top right corner.
  • In this view, enable UART0 and set the UART0_TX_Pin to P2_1 and the UART0_RX_Pin to P2_2.
  • Save the file.
  1. Build and Run Application

If you now build the application and run it on the target, you need to change the SERIAL MONITOR to the following:

  • Monitor Mode: Serial
  • Port: the Segger J-Link
  • Baud rate: 115200

Press Start Monitoring to view the printf massages.

More Examples

Similar examples which are pre-configured for the UART output are available on GitHub:

About

Simple "Hello, World!" example to get you started.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •