System Porting

1. Introduction
2. Port Creating
3. Configuration Script
4. Description of Port Interface Functions

1. Introduction

To use the dnx RTOS on a new microcontroller the specified port is required. The port is a part of software that is directly connected with a hardware. Usually the port is a chunk of software that contains: the system files, CPU hooks file (CPU exceptions handling), interrupt vector table, startup code, and linker scripts. Each of listed files creates the microcontroller port. Note that the kernel must have specified port to handle particular CPU (Official FreeRTOS Ports). Do not forget that the new port requires a new implementation of modules to handle the devices of microcontroller.

2. Port Creating

This manual shows only the steps that the user should achieve to create a new port. Those steps not shows the implementation of the port. To create a new port, follow:

  1. Go to the ./src/system/portable folder, and creates a new port folder, e.g. my_port,
  2. Go to the created folder. Creates the cpuctl.c and cpuctl.h files. Those files are required by the system to provide few interface functions. Add the specified content into the cpuctl.h file:
    #ifndef _CPUCTL_H_
    #define _CPUCTL_H_
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    #include <sys/types.h>
    #include "config.h"
    
    #define _CPUCTL_PLATFORM_NAME "New Platform Name"
    #define _CPUCTL_VENDOR_NAME   "Microcontroller Vendor"
    
    extern void  _cpuctl_init(void);
    extern void  _cpuctl_restart_system(void);
    extern void  _cpuctl_sleep(void);
    extern void  _cpuctl_update_system_clocks(void);
    
    #if (CONFIG_MONITOR_CPU_LOAD > 0)
    extern void  _cpuctl_init_CPU_load_counter(void);
    extern void  _cpuctl_reset_CPU_load_counter(void);
    extern u32_t _cpuctl_get_CPU_load_counter_value(void);
    #endif
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif /* _CPUCTL_H_ */
        

    Of course, in this file can be another definitions that are required by the new port,

  3. Save and close the cpuctl.h file. Opens the cpuctl.c file, and add the specified content:
    #include "config.h"
    #include "my_port/cpuctl.h"
    #include "kernel/kwrapper.h"
    
    void _cpuctl_init(void)
    {
    }
    
    void _cpuctl_restart_system(void)
    {
    }
    
    void _cpuctl_sleep(void)
    {
    }
    
    void _cpuctl_update_system_clocks(void)
    {
    }
    
    #if (CONFIG_MONITOR_CPU_LOAD > 0)
    void _cpuctl_init_CPU_load_counter(void)
    {
    }
    #endif
    
    #if (CONFIG_MONITOR_CPU_LOAD > 0)
    void _cpuctl_reset_CPU_load_counter(void)
    {
    }
    #endif
    
    #if (CONFIG_MONITOR_CPU_LOAD > 0)
    u32_t _cpuctl_get_CPU_load_counter_value(void)
    {
    }
    #endif
        

    This file is used to implement the functions used by the system. To learn more about those functions, please read the Description of Port Interface Functions section,

  4. Save and close this file. Open the ./src/system/include/portable/cpuctl.h file and add a new architecture conditional include:
    #if defined(ARCH_my_port)
    #       include "my_port/cpuctl.h"
    #endif
        
  5. Save and close this file. Creates the vectors.c file and add to it the specified for this microcontroller vector functions. Make sure that vectors are enclosed in the vectors array (this array will be used in the linker script to set its position in the ROM),
  6. Creates the cpuhooks.c file if needed. It is needed only when microcontroller supports the exceptions,
  7. Creates the startup.c or startup.s file, that will be used to initialize RAM at microcontroller startup,
  8. Creates the my_port.ld linker file, that describe memories,
  9. Opens the ./src/system/portable/Makefile file, and add created files to it:
    ifeq ($(TARGET), my_port)
    ASRC_ARCH   += portable/my_port/startup.s
    CSRC_ARCH   += portable/my_port/cpuctl.c
    CSRC_ARCH   += portable/my_port/cpuhooks.c
    HDRLOC_ARCH += portable/my_port
    endif
        

    This file pass to the compiler the files that must be compiled,

  10. Save and close this file. Opens the ./src/system/kernel/Makefile file, and add specified content:
    ifeq ($(TARGET), my_port)
    CSRC_ARCH += kernel/FreeRTOS/Source/portable/GCC/<my_port_CPU>/port.c
    endif
        
  11. To register the port in the system, open the ./config/project/flags.h file, and add your port to the supported architectures section:
    #define my_port 4 // a next free number
        
  12. Next, in the include specific CPU architecture files section add the specified content:
    // [...]
    #elif (__CPU_ARCH__ == my_port)
    #include "my_port/cpu.h"
    #endif
        
  13. Save and close this file. Create a new folder my_port in the ./config folder,
  14. Open the created folder and create cpu.h and Makefile files,
  15. Open the cpu.h file and add the specified content:
    #define __CPU_START_FREQUENCY__ (8000000UL)  // base frequency
    #define __CPU_HEAP_ALIGN__      (4)          // 4 for a 32-bit CPU
    #define ARCH_my_port
        

    An additional CPU definitions can be added in this file,

  16. Save and close this file. Open the Makefile file and add the specified lines:
    # Makefile for GNU make
    CPUCONFIG_CPUNAME=...
    CPUCONFIG_AFLAGS=...
    CPUCONFIG_CFLAGS=...
    CPUCONFIG_CXXFLAGS=...
    CPUCONFIG_LDFLAGS=...
    CPUCONFIG_LD=src/system/portable/my_port/$(CPUCONFIG_CPUNAME).ld
        

    Those variables must be filled by a valid compiler flags for the selected microcontroller.

The best way to create a new port is taking a pattern from existing port implementations.

3. Configuration Script

To enable the CPU port from the configuration wizard, the user should create (update) configuration scripts. Follow:

  1. Open the ./tools/wizard/modules/db.lua file and the arch.list variable add your port name,
  2. And, create the specified variables:
    arch.my_port             = {}
    arch.my_port.description = "An example port"
    arch.my_port.mcu         = {}
    arch.my_port.mcu.list    = {}
        

    Add a supported microcontrollers to the arch.my_port.mcu.list variable.

At this point the new port will be visible in the configuration wizard. To use modules in this port, the configuration script for each module must be implemented (the module scrips should be updated).

4. Description of Port Interface Functions

The system requires from the port that the API functions must be implemented. Those functions are used to provide few important actions that are used by the system in the run phases. The API functions used in the cpuctl.c port files:

  • _cpuctl_init() – the function is used by the system at startup to configure the microcontroller (e.g.: configuration of address of vector table, interrupts priority group, external memory, etc). The function prototype:
    void _cpuctl_init(void)
  • _cpuctl_restart_system() – the function is used to perform the reset of the microcontroller from the software. The function prototype:
    void _cpuctl_restart_system(void)
  • _cpuctl_sleep() – the function is used to sleep the microcontroller to next event or interrupt. It is called from the idle task when sleep on idle flag is set. The function prototype:
    void _cpuctl_sleep(void)
  • _cpuctl_update_system_clocks() – the function is called when the clocks of the microcontroller was changed, e.g. by the PLL module. This function will updates the system timer (systick) that is used to context switch (if it is used). The function prototype:
    void _cpuctl_update_system_clocks(void)
  • _cpuctl_init_CPU_load_counter() – the function initializes a selected counter that provides the time reference used by the system monitor to calculate CPU load values. The function prototype:
    void _cpuctl_init_CPU_load_counter(void)
  • _cpuctl_reset_CPU_load_counter() – the function resets a value of CPU load counter. The function prototype:
    void _cpuctl_reset_CPU_load_counter(void)
  • _cpuctl_get_CPU_load_counter_value() – the function returns a value of CPU load counter. The function prototype:
    u32_t _cpuctl_get_CPU_load_counter_value(void)