CMSIS-Core (Cortex-M)  
CMSIS-Core support for Cortex-M processor-based devices
 
Loading...
Searching...
No Matches
Using CMSIS-Core

To use the CMSIS-Core (Cortex-M) in an embedded software project at the following CMSIS-Core Device Files need to be added to the application:

Using CMSIS-Core (Cortex-M) in a project

The Startup File startup_<Device>.c is executed after reset and calls SystemInit() in the reset hander. After the system initialization the control is transferred to the C/C++ run-time library which performs initialization and calls the main function in the user code. In addition the Startup File startup_<Device>.c contains all exception and interrupt vectors and implements a default function for every interrupt. It may also contain stack and heap configurations for the user application.

The System Configuration Files system_<Device>.c and system_<Device>.h performs the setup for the processor clock. The variable SystemCoreClock indicates the CPU clock speed. In addition the file may contain functions for the memory BUS setup and clock re-configuration.

Note

The Device Header File <Device.h> provides access to the following device-specific functionalities:

Usage in CMSIS-Packs

The easiest way to use CMSIS-Core in a project is with CMSIS Packs.

The CMSIS-Core Device Files are typically provided in a CMSIS Device Family Pack (DFP) that is maintained by the chip vendor for the target device family. The list of public CMSIS packs (including DFPs) can be found at keil.arm.com/packs.

A Device Family Pack (DFP) usually has a requirement for using the CMSIS:CORE component from the CMSIS Software pack that contains the CMSIS-Core Standard Files. In such case the CMSIS Software pack needs to be installed as well.

The files Startup File startup_<Device>.c and System Configuration Files system_<Device>.c and system_<Device>.h are typically provided in the DFP as part of Device class in the Startup group and are defined as configuration files, meaning they are copied from the pack into a project folder and can be modifed there if necessary.

The use of Device Header File <Device.h> can be abstracted with the #define CMSIS_header_file provided in RTE_Components.h. This allows to have uniform include code in the application independent of the target device.

#include "RTE_Components.h" // include information about project configuration
#include CMSIS_device_header // include <Device>.h file

Thereafter, the functions described under API Reference can be used in the application.

For example, the following files are provided by the STM32F10x device family pack:

File Description
".\Device\Source\ARM\startup_stm32f10x_cl.s" Startup File startup_<Device>.c for the STM32F10x device variants
".\Device\Source\system_stmf10x.c" System Configuration Files system_<Device>.c and system_<Device>.h for the STM32F10x device families
".\Device\Include\stm32f10x.h" Device Header File <Device.h> for the STM32F10x device families

Delivery in CMSIS-Packs provides more information on how CMSIS-Core files can be delivered in CMSIS Packs.

Usage Examples

Examples

Also see Using TrustZone for Armv8-M that details CMSIS-Core support for Arm TrusZone operation on Cortex-M.

Basic CMSIS Example

A typical example for using the CMSIS layer is provided below. The example is based on a STM32F10x Device.

#include <stm32f10x.h> // File name depends on device used
uint32_t volatile msTicks; // Counter for millisecond Interval
void SysTick_Handler (void) { // SysTick Interrupt Handler
msTicks++; // Increment Counter
}
void WaitForTick (void) {
uint32_t curTicks;
curTicks = msTicks; // Save Current SysTick Value
while (msTicks == curTicks) { // Wait for next SysTick Interrupt
__WFE (); // Power-Down until next Event/Interrupt
}
}
void TIM1_UP_IRQHandler (void) { // Timer Interrupt Handler
; // Add user code here
}
void timer1_init(int frequency) { // Set up Timer (device specific)
NVIC_SetPriority (TIM1_UP_IRQn, 1); // Set Timer priority
NVIC_EnableIRQ (TIM1_UP_IRQn); // Enable Timer Interrupt
}
void Device_Initialization (void) { // Configure & Initialize MCU
if (SysTick_Config (SystemCoreClock / 1000)) { // SysTick 1mSec
: // Handle Error
}
timer1_init (); // setup device-specific timer
}
// The processor clock is initialized by CMSIS startup + system file
void main (void) { // user application starts here
Device_Initialization (); // Configure & Initialize MCU
while (1) { // Endless Loop (the Super-Loop)
__disable_irq (); // Disable all interrupts
Get_InputValues (); // Read Values
__enable_irq (); // Enable all interrupts
Calculation_Response (); // Calculate Results
Output_Response (); // Output Results
WaitForTick (); // Synchronize to SysTick Timer
}
}
void __enable_irq(void)
Globally enables interrupts and configurable fault handlers.
void __disable_irq(void)
Globally disables interrupts and configurable fault handlers.
void NVIC_EnableIRQ(IRQn_Type IRQn)
Enable a device specific interrupt.
void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
Set the priority for an interrupt.
uint32_t SysTick_Config(uint32_t ticks)
System Tick Timer Configuration.
void __WFE(void)
Wait For Event.
uint32_t SystemCoreClock
Variable to hold the system core clock value.
Definition: ref_system_init.txt:68

Using Interrupt Vector Remap

Most Cortex-M processors provide VTOR register for remapping interrupt vectors. The following example shows a typical use case where the interrupt vectors are copied to RAM and the SysTick_Handler is replaced.

#include "ARMCM3.h" // Device header
#define VECTORTABLE_SIZE (240) /* size of the used vector tables */
/* see startup file startup_ARMCM3.c */
#define VECTORTABLE_ALIGNMENT (0x100U) /* 16 Cortex + 32 ARMCM3 = 48 words */
/* next power of 2 = 256 */
/* externals from startup_ARMCM3.c */
extern uint32_t __VECTOR_TABLE[VECTORTABLE_SIZE]; /* vector table ROM */
/* new vector table in RAM, same size as vector table in ROM */
uint32_t vectorTable_RAM[VECTORTABLE_SIZE] __attribute__(( aligned (VECTORTABLE_ALIGNMENT) ));
/*----------------------------------------------------------------------------
SysTick_Handler
*----------------------------------------------------------------------------*/
volatile uint32_t msTicks = 0; /* counts 1ms timeTicks */
void SysTick_Handler(void) {
msTicks++; /* increment counter */
}
/*----------------------------------------------------------------------------
SysTick_Handler (RAM)
*----------------------------------------------------------------------------*/
volatile uint32_t msTicks_RAM = 0; /* counts 1ms timeTicks */
void SysTick_Handler_RAM(void) {
msTicks_RAM++; /* increment counter */
}
/*----------------------------------------------------------------------------
MAIN function
*----------------------------------------------------------------------------*/
int main (void) {
uint32_t i;
for (i = 0; i < VECTORTABLE_SIZE; i++) {
vectorTable_RAM[i] = __VECTOR_TABLE[i]; /* copy vector table to RAM */
}
/* replace SysTick Handler */
vectorTable_RAM[SysTick_IRQn + 16] = (uint32_t)SysTick_Handler_RAM;
/* relocate vector table */
SCB->VTOR = (uint32_t)&vectorTable_RAM;
__DSB();
SystemCoreClockUpdate(); /* Get Core Clock Frequency */
SysTick_Config(SystemCoreClock / 1000ul); /* Setup SysTick Timer for 1 msec */
while(1);
}
@ SysTick_IRQn
Exception 15: System Tick Interrupt.
Definition: ref_nvic.txt:398
#define __VECTOR_TABLE
Symbol name used for the (static) interrupt vector table.
Definition: ref_compiler_ctrl.txt:520
void __DSB(void)
Data Synchronization Barrier.
void SystemCoreClockUpdate(void)
Function to update the variable SystemCoreClock.

Use generic Arm Devices

Test and example projects of many software components have a need for implementations that are independent from specific device vendors but still have adaptations for various Arm Cortex-M cores to benefit from their architectural differenceis.

The Cortex_DFP pack provides generic device definitions for standard Arm Cortex-M cores and contains corresponding CMSIS-Core Device Files. These generic Arm devices can be used as a target for embedded programs, with execution, for example, on processor simulation models.

Validation suits and example projects for such components as CMSIS-DSP, CMSIS-RTOS and CMSIS-Core itself use that approach already.

Create generic libraries

The CMSIS Processor and Core Peripheral files allow also to create generic libraries. The CMSIS-DSP libraries are an example for such a generic library.

To build a generic Library set the define __CMSIS_GENERIC and include the relevant core_<cpu>.h CMSIS CPU & Core Access header file for the processor.

The define __CMSIS_GENERIC disables device-dependent features such as the SysTick timer and the Interrupt System.

Refer to Configuration of the Processor and Core Peripherals for a list of the available core_<cpu>.h header files.

Example:

The following code section shows the usage of the core_<cpu>.h header files to build a generic library for Cortex-M0, Cortex-M3, Cortex-M4, or Cortex-M7 devices.

To select the processor, the source code uses the defines CORTEX_M7, CORTEX_M4, CORTEX_M3, CORTEX_M0, or CORTEX_M0PLUS. One of these defines needs to be provided on the compiler command line. By using this header file, the source code can access the correct implementations for Core Register Access, Intrinsic Functions for CPU Instructions, Intrinsic Functions for SIMD Instructions, and Debug Access.

#define __CMSIS_GENERIC /* disable NVIC and Systick functions */
#if defined (CORTEX_M7)
#include "core_cm7.h"
#elif defined (CORTEX_M4)
#include "core_cm4.h"
#elif defined (CORTEX_M3)
#include "core_cm3.h"
#elif defined (CORTEX_M0)
#include "core_cm0.h"
#elif defined (CORTEX_M0PLUS)
#include "core_cm0plus.h"
#else
#error "Processor not specified or unsupported."
#endif