Using NMSIS in Embedded Applications

Introduction

To use the NMSIS-Core, the following files are added to the embedded application:

Note

The best example usage of NMSIS device template is our Nuclei SDK project’s evalsoc support source code, it is modified based on NMSIS device template and may contains newer experimental features not in this device template, and it also provided very good user experience for both command line and IDE itegration like Nuclei Studio and IAR Workbench.

The files Startup File startup_<Device>.S, Interrupt and Exception Handling File: intexc_<Device>.S, Device Linker Script: gcc_<device>.ld and System Configuration Files system_<Device>.c and system_<Device>.h may require application specific adaptations and therefore should be copied into the application project folder prior configuration.

The Device Header File <Device.h> is included in all source files that need device access and can be stored on a central include folder that is generic for all projects.

The Startup File startup_<Device>.S is executed right after device reset, it will do necessary stack pointer initialization, exception and interrupt entry configuration, then call SystemInit(), after system initialization, will return to assemble startup code and do c/c++ runtime initialization which includes data, bss section initialization, c++ runtime initialization, then it will call main() function in the application code.

In the Interrupt and Exception Handling File: intexc_<Device>.S, it will contain 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. Systick Timer(SysTimer) describes the minimum feature set. In addition the file may contain functions for the memory BUS setup and clock re-configuration.

The Device Header File <Device.h> is the central include file that the application programmer is using in the C source code. It provides the following features:

NMSIS-Core User Files

NMSIS-Core User Files

The NMSIS-Core system files are device specific.

In addition, the Startup File startup_<Device>.S is also compiler vendor specific, currently only GCC version is provided. The versions provided by NMSIS are only generic templates. The adopted versions for a concrete device are typically provided by the device vendor through the according device familiy package.

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

Files provided by GD32VF103 device family pack

File

Description

./Device/Source/GCC/startup_gd32vf103.S

Startup File startup_<device>.S
for the GD32VF103 device variants.

./Device/Source/GCC/intexc_gd32vf103.S

Exception and Interrupt Handling File
intexc_<device>.S for the GD32VF103 device variants.

./Device/Source/GCC/gcc_gd32vf103.ld

Linker script File gcc_<device>.ld
for the GD32VF103 device variants.

./Device/Source/system_gd32vf103.c

System Configuration File system_<device>.c
for the GD32VF103 device families

./Device/Include/system_gd32vf103.h

System Configuration File system_<device>.h
for the GD32VF103 device families

./Device/Include/gd32vf103.h

Device Header File <device.h>
for the GD32VF103 device families.

Note

The silicon vendors create these device-specific NMSIS-Core files based on NMSIS-Core Device Templates provided by Nuclei.

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

Basic NMSIS Example

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

gd32vf103_example.c
 1#include <gd32vf103.h>                           // File name depends on device used
 2
 3uint32_t volatile msTicks;                       // Counter for millisecond Interval
 4#define SysTick_Handler     eclic_mtip_handler
 5#define CONFIG_TICKS        (SOC_TIMER_FREQ / 1000)
 6
 7void SysTick_Handler (void) {                    // SysTick Interrupt Handler
 8  SysTick_Reload(CONFIG_TICKS);
 9  msTicks++;                                     // Increment Counter
10}
11
12void WaitForTick (void)  {
13  uint32_t curTicks;
14
15  curTicks = msTicks;                            // Save Current SysTick Value
16  while (msTicks == curTicks)  {                 // Wait for next SysTick Interrupt
17    __WFI ();                                    // Power-Down until next Event/Interrupt
18  }
19}
20
21void TIMER0_UP_IRQHandler (void) {               // Timer Interrupt Handler
22  ;                                              // Add user code here
23}
24
25void timer0_init(int frequency) {                // Set up Timer (device specific)
26  ECLIC_SetPriorityIRQ (TIMER0_UP_IRQn, 1);      // Set Timer priority
27  ECLIC_EnableIRQ (TIMER0_UP_IRQn);              // Enable Timer Interrupt
28}
29
30
31void Device_Initialization (void)  {             // Configure & Initialize MCU
32  if (SysTick_Config (CONFIG_TICKS)) {
33       ; // Handle Error
34  }
35  timer0_init ();                                // setup device-specific timer
36}
37
38// The processor clock is initialized by NMSIS startup + system file
39void main (void) {                               // user application starts here
40  Device_Initialization ();                      // Configure & Initialize MCU
41  while (1)  {                                   // Endless Loop (the Super-Loop)
42    __disable_irq ();                            // Disable all interrupts
43    Get_InputValues ();                          // Read Values
44    __enable_irq ();                             // Enable all interrupts
45    Calculation_Response ();                     // Calculate Results
46    Output_Response ();                          // Output Results
47    WaitForTick ();                              // Synchronize to SysTick Timer
48  }
49}

Using Interrupt and Exception/NMI

Nuclei processors provide NMI(Non-Maskable Interrupt), Exception, Vector Interrupt and Non-Vector Interrupt features.

Using NMSIS with generic Nuclei Processors

Nuclei provides NMSIS-Core Device template files for the supported Nuclei Processors and for various compiler vendors. These files can be used as templates, and you can modify based on it to match your processor design.

And you can also refer to Nuclei SDK project for an quick and easily startup project to work with Nuclei RISC-V processor, it is based on NMSIS project and support build/debug c/c++ project in both command line or many different IDEs such as Nuclei Studio.

The table below lists the template folder.

NMSIS Device Templates for the Nuclei processors

Folder

Processor

RISC-V

Description

./Device/_Template_Vendor

  • 200

  • 300

  • 600

  • 900

RV32

RV64

Contains Include and Source template files configured for the
Nuclei RISC-V processor.


Create generic Libraries with NMSIS

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

To build a generic library set the define __NMSIS_GENERIC and include the nmsis_core.h NMSIS CPU & Core Access header file for the processor.

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

Example

The following code section shows the usage of the nmsis_core.h header files to build a generic library for N200, N300, N600, NX600.

One of these defines needs to be provided on the compiler command line.

By using this header file, the source code can access the functions for Core CSR Register Access, CPU Intrinsic Functions and Intrinsic Functions for SIMD Instructions.

core_generic.h
1#define __NMSIS_GENERIC   // Disable Eclic and Systick functions
2#include <nmsis_core.h>