top of page
Writer's pictureSunil Kumar Yadav

Getting Started with ARM Cortex-M

Updated: Oct 17, 2023



Whether you're a layperson when it comes to technology or a passionate tech aficionado, it's highly probable that you're familiar with or have come across ARM, one of the most prevalent computer architectures in today's digital landscape. It's likely that the smartphone in your pocket or the credit card you use at a shopping center incorporates a microprocessor rooted in ARM architecture. If you share my enthusiasm for delving into how the intricate technologies and software in our everyday devices shape our digital world, then this article, as well as the upcoming ones, will serve as an introduction to the fascinating realm of embedded systems.


In this article, I will provide a brief overview of the ARM architecture and guide you on how to initiate your journey with an ARM Cortex-M based microprocessor, even if you possess limited knowledge of embedded systems. Armed with this knowledge, you can begin crafting your solutions for intricate challenges.


What is ARM?

ARM (Advance Risc Machine) is a family of Reduced Instruction Set Computer (RISC) instruction set architecture for computer processors. ARM develops the architecture and licenses them to other companies, who design their own product based on ARM architecture. Depending upon the industry and use case, ARM has multiple processor series and they can be classified broadly into three wide buckets.



Cortex-A

These are a family of 32-bit and 64-bit RISC ARM cores that are used in high-performance and highly efficient applications.


Cortex-R

These are a family of 32-bit and 64-bit RISC ARM processor cores and are optimized for hard real-time and safety-critical applications.


Cortex-M

These are a group of 32-bit RISC ARM processor cores optimized for low-cost and energy-efficient integrated circuits which are embedded in tens of billions of consumer devices. These cores can be found embedded in other high-power processor cores in SoC.


In this article series, we'll use ARM Cortex-M based devices as these are very affordable and require minimum effort to set up. Another advantage of using Cortex-M device is that many of the chip vendors provide SDK which is either free to use or has a version with limited code size readily available. In my case, I'm using the STM32F411 discovery board from STM but you can opt for any Cortex-M based board to get started. Only in the case of GPIO or specific hardware-oriented configuration, you may need to modify your code to align with your board design or available feature.

Image : STM32F411 Discovery Board

Hello World Programm on Cortx M


In programming, it's a tradition to start any programming project by starting with a simple Hello world example program that simply prints "Hello world" on a computer screen. Since Cortex-M controllers are targeted toward embedded applications, which do not have access to displays, we need to use another mechanism to achieve similar results. We can either use Semihosting to print the message on the console or use SWD with ITM trace functionality to print messages in IDE's dedicated window.


So let's get started. Please refer below gif on how to create a simple project using STM32 Cube studio. Please note, we are using STM32 IDE as it's free to use but if you are using a different semiconductor vendor and/or toolchain then follow the appropriate steps to create a project.


The below gif highlights the process of creating STM32 based empty project.


Creating STM32 project

Once we've created the empty project then update the main.c file by including stdio.h header file and call printf with Hello World string. Below is the snippet of main.c


/* main.c */
#include <stdint.h>
#include <stdio.h>

#if !defined(__SOFT_FP__) && defined(__ARM_FP)
  #warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif

int main(void)
{
	printf("Hello world STM32\n");
    /* Loop forever */
	for(;;);
}


Configuring ITM and SWV

Once done with the above changes, compile/build the project and it should compile cleanly as shown below. If we proceed with executing on the STM32 Discovery board it will not print anything on the STM32 IDE's console as we need one crucial setup to redirect printf output via SWD to the console.

Image 1: Building STM32 Project

Add below code snippet inside syscalls.c file which will use the ITM buffer to collect a stream of data and the SWD debugger will redirect to STM32 IDE.

/* Excerpts of syscalls.c*/
/***************************************************
* Implementation of printf like feature using ARM Cortex M3/M4.
* ITM functionality function will not work for ARM Cortex M0/M0+.
* Note: Use semihosting feature of OpenOCD for Cortex M0.
***************************************************/
// Debug Exception and Monitor Control Register base address
#define DEMCR        			*((volatile uint32_t*) 0xE000EDFCU )

/* ITM register addresses */
#define ITM_STIMULUS_PORT0   	*((volatile uint32_t*) 0xE0000000U )
#define ITM_TRACE_EN          	*((volatile uint32_t*) 0xE0000E00U )

void ITM_SendChar(uint8_t ch) {

	DEMCR |= ( 1 << 24);                 /* Enable TRCENA*/

	ITM_TRACE_EN |= ( 1 << 0);          /* Enable stimulus port 0*/

	/* read FIFO status in bit [0]: */
	while(!(ITM_STIMULUS_PORT0 & 1));

	ITM_STIMULUS_PORT0 = ch;           /* Write to ITM stimulus port0*/
}

.
.
.
.

/* Comment out __io_putchar() and add ITM_SendChar() */
__attribute__((weak)) int _write(int file, char *ptr, int len)
{
	int DataIdx;

	for (DataIdx = 0; DataIdx < len; DataIdx++)
	{
		//__io_putchar(*ptr++);
		ITM_SendChar(*ptr++);   /* using ITM FIFO register to extract
		                          data when printf calls _write() */
	}
	return len;
}

Once done with the above-mentioned changes, build the project as shown in Image 1. Now to run the compiled binaries connect the USB C end to PC and USB A to the STM32 Discovery board and configure the debugger with SWV as shown below image. Please note, STM32 discovery or other similar boards come with a debugger inbuilt and hence there is no need to use additional hardware for this example.

Image 2: Configuring Debugger

After doing the above changes, start the debugging session by clicking the 'bug' symbol in the tools menu. This will cause STM32 IDE to launch the STlink debugger and flash the new program into memory and restart the target. Once in debugging session add the SWV ITM Data console window from Window -> Show View -> SWV and enable port 0 of ITM port as shown below. Once configured, click on the continue or play button symbol on the toolbar to start the execution.


Image 3: Configuring SWV to view output of printf

Voilà we've successfully executed the Hello World program on the Cortex M device and viewed the text output inside SWV ITM Data Console.

169 views0 comments

Comments


bottom of page