Nuvoton from scratch, the bare minimum

I do not use register based programming actively in my daily life. However, if i need to meet a new platform, i try this way. In this way, i can understand whether the datasheet of the relevant platform is good.  To be honest, the datasheet of the Nuvoton products came out poor. I could not find some generalized keywords like “register boundary address ” in the datasheet. Finding relevant addresses and offset values was a waste of time really. Today, we will build a project from scratch. We will use GNU ARM Embedded as toolchain. We will write the linker file. After the compilation and linking process, we will transfer the .bin extension file that we will obtain through the utility to our development card with program named NUMicro ICP Programming Tool. If you have used the stm32 series before you can understand it easily. The development card i have (NuMaker – PFM – M487) using Cortex-M4.

Let’s start with startup file as named startup.c

#include "stdint.h"

#define sp 0x20000800 

#define __IO volatile

typedef struct
{
    __IO uint32_t MODE;          /* Offset: 0x00/0x40/0x80/0xC0/0x100/0x140/0x180/0x1C0  Port A-H I/O Mode Control                       */
    __IO uint32_t DINOFF;        /* Offset: 0x04/0x44/0x84/0xC4/0x104/0x144/0x184/0x1C4  Port A-H Digital Input Path Disable Control     */
    __IO uint32_t DOUT;          /* Offset: 0x08/0x48/0x88/0xC8/0x108/0x148/0x188/0x1C8  Port A-H Data Output Value                      */
    __IO uint32_t DATMSK;        /* Offset: 0x0C/0x4C/0x8C/0xCC/0x10C/0x14C/0x18C/0x1CC  Port A-H Data Output Write Mask                 */
    __IO uint32_t PIN;           /* Offset: 0x10/0x50/0x90/0xD0/0x110/0x150/0x190/0x1D0  Port A-H Pin Value                              */
    __IO uint32_t DBEN;          /* Offset: 0x14/0x54/0x94/0xD4/0x114/0x154/0x194/0x1D4  Port A-H De-Bounce Enable Control Register      */
    __IO uint32_t INTTYPE;       /* Offset: 0x18/0x58/0x98/0xD8/0x118/0x158/0x198/0x1D8  Port A-H Interrupt Trigger Type Control         */
    __IO uint32_t INTEN;         /* Offset: 0x1C/0x5C/0x9C/0xDC/0x11C/0x15C/0x19C/0x1DC  Port A-H Interrupt Enable Control Register      */
    __IO uint32_t INTSRC;        /* Offset: 0x20/0x60/0xA0/0xE0/0x120/0x160/0x1A0/0x1E0  Port A-H Interrupt Source Flag                  */
    __IO uint32_t SMTEN;         /* Offset: 0x24/0x64/0xA4/0xE4/0x124/0x164/0x1A4/0x1E4  Port A-H Input Schmitt Trigger Enable Register  */
    __IO uint32_t SLEWCTL;       /* Offset: 0x28/0x68/0xA8/0xE8/0x128/0x168/0x1A8/0x1E8  Port A-H High Slew Rate Control Register        */
    __IO uint32_t RESERVE0[1];
    __IO uint32_t PUSEL;         /* Offset: 0x30/0x70/0xB0/0xF0/0x130/0x170/0x1B0/0x1F0  Port A-H Pull-up and Pull-down Enable Register  */

} GPIO_T;

#define PERIPH_BASE                 (( uint32_t)0x40000000)     /*!< Perip. Control Register */
#define GPIOH_BASE                  (PERIPH_BASE + 0x041C0UL)   /*!< PORT H Control Register */
#define PH                          ((GPIO_T *)  GPIOH_BASE)    /*!< Casting to PORT H Control Register */
#define GPIO_MODE_OUTPUT            (0x1UL)                     /*!< Output Mode ideinitializer */
#define BIT0                        (0x00000001UL)              //< Bit 0 mask of an 32 bit integer

int main(void);

uint32_t *vector_table[2] __attribute__  ((section("vectors"))) = 
{
    (uint32_t*) sp, //stack pointer
    (uint32_t*) main,
};

int main()
{    
    PH -> MODE |= BIT0; //PH0 Output Mode
    
    while(1)
    {
        PH -> DOUT = 0x00; //low PH-0.bit
        for (int i = 0; i < 50000; ++i); //for delay
        PH -> DOUT = 0x01; //high PH-0.bit
        for (int i = 0; i < 50000; ++i); //for delay
    }       
}


Since the stack is a downward-going structure and the ram start address is 0x20000000. I’ve set a small stack. Now we can compile this file, so tiny : just 84 bytes.

arm-none-eabi-gcc -I. -c -fno-common -O0 -g -mcpu=cortex-m4 -mthumb startup.c
MEMORY
{
    ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
    rom (rx)  : ORIGIN = 0x00000000, LENGTH = 40K
}

SECTIONS
{
    .  = 0x0;         /* From 0x00000000 */
    .text :
    {
        *(vectors)    /* Vector table */
        *(.text)      /* Program code */
        *(.rodata)    /* Read only data */
    } >rom

    .  = 0x20000000;  /* From 0x20000000 */
    .data :
    {
        *(.data)      /* Data memory */
    } >ram AT > rom

    .bss :
    {
        *(.bss)       /* Zero-filled run time allocate data memory */
    } >ram AT > rom
}


I did not write the original ram and rom sizes, I did not need that much, so I used my existing linker file. Lets linking.

arm-none-eabi-ld -Tnuvoton.ld -nostartfiles -o startup.elf startup.o

Converting the binary file.

arm-none-eabi-objcopy -Obinary startup.elf startup.bin


After uploading the file to our development card with the numicro program, we can see that the red led on the card flashes.

Best Regards,
Volkan

Bir Cevap Yazın

Please log in using one of these methods to post your comment:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Google fotoğrafı

Google hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Connecting to %s