Using NMSIS in Embedded Applications

Introduction

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

Note

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
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <gd32vf103.h>                           // File name depends on device used

uint32_t volatile msTicks;                       // Counter for millisecond Interval
#define SysTick_Handler     eclic_mtip_handler
#define CONFIG_TICKS        (SOC_TIMER_FREQ / 1000)

void SysTick_Handler (void) {                    // SysTick Interrupt Handler
  SysTick_Reload(CONFIG_TICKS);
  msTicks++;                                     // Increment Counter
}

void WaitForTick (void)  {
  uint32_t curTicks;

  curTicks = msTicks;                            // Save Current SysTick Value
  while (msTicks == curTicks)  {                 // Wait for next SysTick Interrupt
    __WFI ();                                    // Power-Down until next Event/Interrupt
  }
}

void TIMER0_UP_IRQHandler (void) {               // Timer Interrupt Handler
  ;                                              // Add user code here
}

void timer0_init(int frequency) {                // Set up Timer (device specific)
  ECLIC_SetPriorityIRQ (TIMER0_UP_IRQn, 1);      // Set Timer priority
  ECLIC_EnableIRQ (TIMER0_UP_IRQn);              // Enable Timer Interrupt
}


void Device_Initialization (void)  {             // Configure & Initialize MCU
  if (SysTick_Config (CONFIG_TICKS)) {
       ; // Handle Error
  }
  timer0_init ();                                // setup device-specific timer
}

// The processor clock is initialized by NMSIS 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
  }
}

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 files for the supported Nuclei Processors and for various compiler vendors. These files can be used when standard Nuclei processors should be used in a project. The table below lists the folder and device names of the Nuclei processors.

Folder and device names of the Nuclei processors

Folder

Processor

RISC-V

Description

./Device/Nuclei/NUCLEI_N

  • N200

  • N300

  • N600

RV32

Contains Include and Source template files configured for the
Nuclei N200/N300/N600 processor. The device name is NUCLEI_N
and the name of the Device Header File <device.h> is <NUCLEI_N.h>.

./Device/Nuclei/NUCLEI_NX

NX600

RV64

Contains Include and Source template files configured for the
Nuclei NX600 processor. The device name is NUCLEI_NX
and the name of the Device Header File <device.h> is <NUCLEI_NX.h>.

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
2
#define __NMSIS_GENERIC   // Disable Eclic and Systick functions
#include <nmsis_core.h>