5.3 Cortex-M0 Guide

This chapter describes Cortex-M0 core usage on the N32G033, together with the 2 examples (ProcessStack and SysTick). The core has no separate standard peripheral driver and the related operations come from the CMSIS layer; read the system chapter of the user manual for the core clock, clock tree, and core exceptions, and the errata sheet for known chip issues.

5.3.1 Related files

Relative path Purpose
firmware/CMSIS/core/core_cm0.h Defines the Cortex-M0 core registers and the CMSIS inline functions __set_PSP, __set_CONTROL, __ISB, SysTick_Config, and others that the examples call directly
firmware/CMSIS/device/system_n32g033.c System initialization of the device and the implementation of SystemCoreClockUpdate and SystemCoreClock, which the examples use to obtain the core clock
projects/n32g033_EVAL/examples/Cortex-M0/ Cortex-M0 example root directory, with 2 examples: ProcessStack and SysTick
projects/n32g033_EVAL/examples/Cortex-M0/SysTick/ Project layout of this example: MDK-ARM/, EWARM/, inc/, src/, and readme.txt
projects/n32g033_EVAL/bsp/ Board support files shared by the examples: the serial log interface in log.h

5.3.2 API reference

The Cortex-M0 core provides no separate standard peripheral driver library, so this module has no :::devkit-api entries and no function cards. All core operations come from CMSIS: firmware/CMSIS/core/core_cm0.h defines the control-register accessors and inline functions such as SysTick_Config, while firmware/CMSIS/device/system_n32g033.c provides system initialization and the core-clock update. The two examples call these interfaces directly to switch the thread-mode stack and to configure the system tick, so porting only needs to carry the matching inline functions and the core-clock variable.

5.3.3 Demo descriptions

This section describes the 2 Cortex-M0 examples: ProcessStack switches the thread-mode stack from the main stack to the process stack and back after an exception, and SysTick configures a 10 ms system tick interrupt.

5.3.3.1 ProcessStack Thread-mode stack switch

Example directory: projects/n32g033_EVAL/examples/Cortex-M0/ProcessStack/

Declare the stack size and stack-value macros→Clear the process stack area→Set the process stack pointer and switch to the process stack→Run the synchronization instruction to flush the pipeline→Trigger a software exception to check that the interrupt context uses the main stack→Read the control register back to confirm the switch

Item Source analysis
Function Switches the thread-mode stack from the main stack to the process stack and back automatically after an exception: after switching it reads the control register to confirm the process stack, the interrupt then uses the main stack, and the process stack is restored on return.
Source files main in src/main.c performs the stack switch and checks and defines the inline assembly for the software exception call;
SVC_Handler in src/n32g033_it.c records the stack used in the interrupt context;
inc/main.h and inc/n32g033_it.h give the declarations;
readme.txt gives the test steps;
the project files are in MDK-ARM/ and EWARM/.
Key configuration The process stack area is 0x200 bytes;
the control register takes 0x02 to select the process stack and 0x00 for the main stack;
the system clock is 64 MHz and the UART is 115200 with TX on PA9 and RX on PA10.
Program and data path main -> log_init -> clear the process stack area -> __set_PSP sets the top of the process stack -> __set_CONTROL switches to the process stack -> __ISB flushes the pipeline -> read CONTROL to check -> trigger the software exception -> SVC_Handler reads back the interrupt-context stack -> after the return CONTROL is read again to confirm the process stack.
Main APIs __set_PSP, __set_CONTROL, __ISB, __get_CONTROL, __get_PSP
Verification The hardware is the N32G033K8Q7-1_STB V1.0 evaluation board with the UART at 115200 baud;
after downloading, resetting, and running, the serial port prints Cortex-M0 ProcessStack Test Success, which means the switch and the automatic switch-back are both correct.
Use note The system clock is 64 MHz;
the Cortex register window of the compiler can also be used to view the thread-mode stack and the code access level.
Core-code walkthrough and porting

The example switches the thread-mode stack from the main stack to the process stack, then uses a software exception to check that the exception context uses the main stack and switches back automatically.

Data path: macros declare the stack size and stack values → clear the process stack area → __set_PSP sets the top of the process stack → __set_CONTROL switches to the process stack → __ISB flushes the pipeline → read CONTROL and PSP back to check → after the software exception SVC_Handler reads back the interrupt-context stack

1. Set the stack size and stack values with macros first. Both the process stack area size and the values of the two stacks are macros, so the switch and the check share the same set of constants.

src/main.csrc/main.c
#define SP_PROCESS_SIZE          0x200 /* Process stack size */
#define SP_PROCESS               0x02  /* Process stack */
#define SP_MAIN                  0x00  /* Main stack */

SP_PROCESS_SIZE set to 0x200 makes the process stack area 512 bytes; the two values map directly onto the stack-select bit of the control register.

2. Set the process stack pointer, switch the stack, and read back to check. The process stack pointer is pointed at the top of the stack first, then the control register selects the process stack, after which a synchronization instruction flushes the pipeline and the value is read back to confirm.

src/main.csrc/main.c · main
    /* Set Process stack value */
    __set_PSP((uint32_t)PSPMemAlloc + SP_PROCESS_SIZE);

    /* Select Process Stack as Thread mode Stack */
    __set_CONTROL(SP_PROCESS);

    /* Execute ISB instruction to flush pipeline as recommended by Arm */
    __ISB();

    /* Get the Thread mode stack used */
    CurrentStack = (__get_CONTROL() & 0x02);

    /* Get process stack pointer value */
    PSPValue = __get_PSP();

The synchronization instruction is required after the switch, otherwise later instructions may still use the old stack value.

3. Use a software exception to check that the interrupt context uses the main stack. After a software exception is triggered, the handler reads back the control register and confirms that the exception context no longer uses the process stack.

src/n32g033_it.csrc/n32g033_it.c · SVC_Handler
void SVC_Handler(void)
{
    IsrStack = (__get_CONTROL() & 0x02);
}

On exception entry the hardware switches to the main stack automatically and restores the previous stack selection on return to thread mode, so this check logic can be carried over directly when porting.

Corresponding source files: src/main.c, src/n32g033_it.c, firmware/CMSIS/core/core_cm0.h

5.3.3.2 SysTick System tick interrupt

Example directory: projects/n32g033_EVAL/examples/Cortex-M0/SysTick/

Update the core-clock variable→Compute and set the SysTick reload value for 10 ms→Enable the SysTick interrupt→The tick interrupt increments the counter→Print the count over the serial port when it is even

Item Source analysis
Function Configures SysTick to raise an interrupt every 10 ms, increments a counter in the service routine, and prints over the serial port when the count is even.
Source files main in src/main.c updates the core clock and configures SysTick;
SysTick_Handler in src/n32g033_it.c increments the counter and prints when needed;
inc/main.h and inc/n32g033_it.h give the declarations;
readme.txt gives the test steps;
the project files are in MDK-ARM/ and EWARM/.
Key configuration The system clock is 64 MHz;
the divisor is 100, which makes the tick period 10 ms;
the UART is 115200 with TX on PA9 and RX on PA10.
Program and data path main -> log_init -> SystemCoreClockUpdate updates the core clock -> SysTick_Config configures and starts the 10 ms tick -> the main loop is empty -> every 10 ms SysTick_Handler increments Tick_num -> the count is printed when it is even.
Main APIs SystemCoreClockUpdate, SystemCoreClock, SysTick_Config
Verification The hardware is the N32G033K8Q7-1_STB V1.0 evaluation board with the UART at 115200 baud;
after downloading, resetting, and running, the serial port prints one count line about every 20 ms.
Use note The system clock is 64 MHz;
adjust the divisor together with the tick period so the reload value stays within the counter width.
Core-code walkthrough and porting

The example works out a 10 ms tick period from the core clock and starts SysTick, then increments a counter and prints on the even condition inside the interrupt.

Data path: macros declare the divisor and the count variable → SystemCoreClockUpdate updates the core clock → SysTick_Config configures and starts the 10 ms tick → the main loop is empty → every 10 ms SysTick_Handler increments the count → the value is printed when even

1. Set the divisor and the count variable first. The divisor fixes the tick period and the count variable reflects how often the interrupt has fired; both are declared at file scope.

src/main.csrc/main.c
#define SYSTICK_10MS           ((uint32_t)100)

uint32_t Tick_num = 0;

SYSTICK_10MS set to 100 divides the core clock into 100 parts, giving a 10 ms tick period; change this macro to change the period.

2. Update the core clock and configure SysTick for 10 ms. The current core clock is recomputed from the registers first, then divided by the divisor to set the reload value and start the tick interrupt.

src/main.csrc/main.c · main
int main(void)
{
    /* USART Init */
    log_init();
    log_info("Cortex-M0 SysTick \r\n");

    /* Get SystemCoreClock */
    SystemCoreClockUpdate();

    /* Config 10ms SysTick  */
    SysTick_Config(SystemCoreClock/SYSTICK_10MS);

    while (1)
    {
    }
}

The core clock must be updated first, otherwise the reload value is computed from the old clock and the actual tick period differs from the intended one.

3. Increment the count and print on the condition inside the interrupt. Each tick interrupt adds one to the count variable and prints one line when the count is even, which keeps the printing from being too frequent.

src/n32g033_it.csrc/n32g033_it.c · SysTick_Handler
void SysTick_Handler(void)
{
    Tick_num++;
    if((Tick_num%2) == 0)
    {
        log_info("Cortex-M0 SysTick IRQ %d\r\n",Tick_num);
    }
}

Printing inside the interrupt takes some time; when the tick period is short, buffer the messages and output them from the main flow instead.

Corresponding source files: src/main.c, src/n32g033_it.c, firmware/CMSIS/core/core_cm0.h

5.3.4 Notes and troubleshooting

Scenario Check & action Source
Reading the core clock The system chapter of the user manual states that the core clock comes from the clock configuration and that SystemCoreClockUpdate recomputes SystemCoreClock from the registers;
update the core clock before computing the tick reload value after a clock-tree change.
User manual
Thread-mode access level The core chapter of the user manual states that thread mode can run privileged or unprivileged;
configure the peripherals that need access before switching to unprivileged mode.
User manual
Exception-context stack The core chapter of the user manual states that the main stack is used on exception entry and the previous stack selection is restored on return to thread mode;
use this to check the behaviour after switching stacks.
User manual
SysTick reload value The core chapter of the user manual states that SysTick is a down counter with a width limit;
keep the reload value within the counter width.
User manual

Errata sheet V1.0.0 (2025.9.25) covers revision A silicon and lists no Cortex-M0 entries.

Nations Technologies DevKit Docs

Datasheets, SDK, driver APIs and demo guides for Nations Technologies MCU development kits, organized by chip series.

© 2026 Nations Technologies Inc. All rights reserved.粤ICP备11069485号This site uses cookie-free anonymous analytics.