3B Infrastructure home

All subjects

Embedded System Design and Implement (Nuvoton 140)

Professional embedded C on the Nuvoton NUC140, a 32-bit Arm Cortex-M0: clocks, registers, GPIO, timers and interrupts. Press play on any sketch to watch it happen.

1 Meet the NUC140

The NUC140 is a 32-bit Arm Cortex-M0 microcontroller, running at up to 50 MHz with 128 KB of flash and 16 KB of SRAM, and with USB and CAN built in. Unlike Arduino, nothing is hidden: you set up the clocks and peripherals yourself.

  • Tools: commonly Keil MDK to compile, and a Nu-Link adapter to flash and debug.
  • Board support package: Nuvoton's BSP gives you startup code and drivers.
  • Clock tree: choose a clock source, then enable the clock of each peripheral you use.
  • Protected registers: key system registers must be unlocked before writing them.
int main(void) {
    SYS_UnlockReg();
    // set up clocks and pins here
    SYS_LockReg();

    while (1) {
        // your application
    }
}

Boot sequence

ResetStartupcodeUnlockregistersSet upclocksLockregistersmain loop

1/6 Power on. The Cortex-M0 reads its first instructions from flash.

Rule of thumb: If a peripheral seems dead, check its clock first. A peripheral with no clock does nothing at all.

2 Registers and GPIO

Hardware is controlled through registers: special addresses where writing a bit changes something physical. A driver call such as GPIO_SetMode sets those bits for you, and PC12 is a macro that reads or writes one pin.

  • Memory-mapped I/O: peripherals appear as addresses, so C pointers can reach them.
  • Mode: each pin must be set as input, output and so on before use.
  • Bit masks: BIT12 selects one bit, so the other pins stay untouched.
  • Active low: on many boards an LED lights when the pin is 0, so check your schematic.
#include "NUC100Series.h"

int main(void) {
    GPIO_SetMode(PC, BIT12, GPIO_PMD_OUTPUT);

    while (1) {
        PC12 = 0;                 // LED on, if active low
        CLK_SysTickDelay(200000); // 200 ms
        PC12 = 1;
        CLK_SysTickDelay(200000);
    }
}

Register diagram

PC12 = 0;Data registerbit 12 = 1Pin PC123.3 VLED off

1/4 GPIO_SetMode first makes the pin an output.

Rule of thumb: Keep the reference manual open. Every register bit is explained there.

3 Timers and interrupts

Delay loops waste the processor. A hardware timer counts on its own and raises an interrupt when it reaches its target, so timing stays exact while the main loop does other work. The NVIC decides which interrupts run.

  • Timer clock: give the timer a clock source and enable it first.
  • Periodic mode: the timer fires again and again at a set rate.
  • NVIC: the Cortex-M interrupt controller, which enables interrupts and sets priorities.
  • Clear the flag: if you do not, the interrupt will fire again as soon as you return.
void TMR0_IRQHandler(void) {
    TIMER_ClearIntFlag(TIMER0);
    PC12 ^= 1;                 // toggle the LED
}

// after setting up clocks
CLK_EnableModuleClock(TMR0_MODULE);
CLK_SetModuleClock(TMR0_MODULE, CLK_CLKSEL1_TMR0_S_HXT, 0);

TIMER_Open(TIMER0, TIMER_PERIODIC_MODE, 2);   // 2 Hz
TIMER_EnableInt(TIMER0);
NVIC_EnableIRQ(TMR0_IRQn);
TIMER_Start(TIMER0);

Interrupt flow

TIMER0countingNVICTMR0_IRQHandlermain() keeps working

1/5 main() does its work while the timer counts by itself in hardware.

Rule of thumb: Every interrupt needs three things: the peripheral enabled, the NVIC enabled, and the flag cleared.