Porting Guideยถ

Comprehensive guide for porting the Nexus Embedded Platform to new hardware platforms.

Overviewยถ

Porting Nexus to a new platform involves:

  • HAL Implementation: Hardware abstraction layer for the target

  • OSAL Integration: Operating system abstraction layer

  • Platform Configuration: Build system and Kconfig setup

  • Testing: Validation of the port

  • Documentation: Platform-specific documentation

This guide walks through the complete porting process.

Prerequisitesยถ

Before Startingยถ

Hardware Requirements

  • Target development board

  • Debug probe (J-Link, ST-Link, etc.)

  • Serial console connection

  • Power supply

Software Requirements

  • Cross-compiler toolchain

  • Debugger (GDB, OpenOCD, etc.)

  • Flash programming tools

  • Terminal emulator

Knowledge Requirements

  • Target MCU architecture

  • Peripheral specifications

  • Memory map

  • Clock configuration

  • Interrupt system

Platform Architectureยถ

Nexus Platform Layersยถ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚        Applications                 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚        Framework                    โ”‚
โ”‚  (Log, Shell, Config, etc.)         โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚        OSAL (FreeRTOS/Native)       โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚        HAL (Platform-Specific)      โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚        Hardware                     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

HAL Layer

Platform-specific hardware abstraction:

  • GPIO, UART, SPI, I2C, ADC, etc.

  • Clock configuration

  • Interrupt management

  • DMA support

  • Power management

OSAL Layer

Operating system abstraction:

  • Task management

  • Synchronization primitives

  • Timers

  • Memory management

  • Message queues

Porting Processยถ

Step 1: Create Platform Directoryยถ

Create directory structure for new platform:

# Create platform directory
mkdir -p platforms/myplatform

# Create subdirectories
mkdir -p platforms/myplatform/hal
mkdir -p platforms/myplatform/startup
mkdir -p platforms/myplatform/linker
mkdir -p platforms/myplatform/config

Directory structure:

platforms/myplatform/
โ”œโ”€โ”€ hal/                    # HAL implementation
โ”‚   โ”œโ”€โ”€ hal_gpio.c
โ”‚   โ”œโ”€โ”€ hal_uart.c
โ”‚   โ”œโ”€โ”€ hal_spi.c
โ”‚   โ””โ”€โ”€ ...
โ”œโ”€โ”€ startup/                # Startup code
โ”‚   โ”œโ”€โ”€ startup.c
โ”‚   โ””โ”€โ”€ system_init.c
โ”œโ”€โ”€ linker/                 # Linker scripts
โ”‚   โ””โ”€โ”€ myplatform.ld
โ”œโ”€โ”€ config/                 # Configuration
โ”‚   โ””โ”€โ”€ platform_config.h
โ”œโ”€โ”€ CMakeLists.txt          # Build configuration
โ””โ”€โ”€ Kconfig                 # Kconfig options

Step 2: Implement HALยถ

GPIO Implementation

Create platforms/myplatform/hal/hal_gpio.c:

/**
 * \file            hal_gpio.c
 * \brief           GPIO HAL implementation for MyPlatform
 * \author          Nexus Team
 */

#include "hal/hal_gpio.h"
#include "myplatform_gpio.h"  /* Platform-specific header */

/*---------------------------------------------------------------------------*/
/* Private Functions                                                         */
/*---------------------------------------------------------------------------*/

/**
 * \brief           Validate GPIO parameters
 */
static hal_status_t gpio_validate_params(hal_gpio_port_t port, uint8_t pin) {
    if (port >= HAL_GPIO_PORT_MAX) {
        return HAL_ERROR_PARAM;
    }
    if (pin >= HAL_GPIO_PIN_MAX) {
        return HAL_ERROR_PARAM;
    }
    return HAL_OK;
}

/*---------------------------------------------------------------------------*/
/* Public Functions                                                          */
/*---------------------------------------------------------------------------*/

/**
 * \brief           Initialize GPIO pin
 */
hal_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin,
                          const hal_gpio_config_t* config) {
    hal_status_t status;

    /* Validate parameters */
    status = gpio_validate_params(port, pin);
    if (status != HAL_OK) {
        return status;
    }

    if (config == NULL) {
        return HAL_ERROR_PARAM;
    }

    /* Enable GPIO clock */
    platform_gpio_enable_clock(port);

    /* Configure GPIO mode */
    platform_gpio_set_mode(port, pin, config->mode);

    /* Configure pull-up/down */
    platform_gpio_set_pull(port, pin, config->pull);

    /* Configure speed */
    platform_gpio_set_speed(port, pin, config->speed);

    /* Set initial level */
    if (config->mode == HAL_GPIO_MODE_OUTPUT_PP ||
        config->mode == HAL_GPIO_MODE_OUTPUT_OD) {
        platform_gpio_write(port, pin, config->init_level);
    }

    return HAL_OK;
}

/**
 * \brief           Write to GPIO pin
 */
hal_status_t hal_gpio_write(hal_gpio_port_t port, uint8_t pin,
                            hal_gpio_level_t level) {
    hal_status_t status;

    /* Validate parameters */
    status = gpio_validate_params(port, pin);
    if (status != HAL_OK) {
        return status;
    }

    /* Write to GPIO */
    platform_gpio_write(port, pin, level);

    return HAL_OK;
}

/**
 * \brief           Read from GPIO pin
 */
hal_status_t hal_gpio_read(hal_gpio_port_t port, uint8_t pin,
                          hal_gpio_level_t* level) {
    hal_status_t status;

    /* Validate parameters */
    status = gpio_validate_params(port, pin);
    if (status != HAL_OK) {
        return status;
    }

    if (level == NULL) {
        return HAL_ERROR_PARAM;
    }

    /* Read from GPIO */
    *level = platform_gpio_read(port, pin);

    return HAL_OK;
}

UART Implementation

Create platforms/myplatform/hal/hal_uart.c:

/**
 * \file            hal_uart.c
 * \brief           UART HAL implementation for MyPlatform
 * \author          Nexus Team
 */

#include "hal/hal_uart.h"
#include "myplatform_uart.h"

/*---------------------------------------------------------------------------*/
/* Private Data                                                              */
/*---------------------------------------------------------------------------*/

static struct {
    bool initialized;
    hal_uart_callback_t callback;
    void* user_data;
} uart_state[HAL_UART_MAX];

/*---------------------------------------------------------------------------*/
/* Public Functions                                                          */
/*---------------------------------------------------------------------------*/

/**
 * \brief           Initialize UART
 */
hal_status_t hal_uart_init(hal_uart_id_t id,
                          const hal_uart_config_t* config) {
    if (id >= HAL_UART_MAX) {
        return HAL_ERROR_PARAM;
    }

    if (config == NULL) {
        return HAL_ERROR_PARAM;
    }

    /* Enable UART clock */
    platform_uart_enable_clock(id);

    /* Configure UART */
    platform_uart_set_baudrate(id, config->baudrate);
    platform_uart_set_wordlen(id, config->wordlen);
    platform_uart_set_stopbits(id, config->stopbits);
    platform_uart_set_parity(id, config->parity);

    /* Enable UART */
    platform_uart_enable(id);

    uart_state[id].initialized = true;

    return HAL_OK;
}

/**
 * \brief           Send data via UART
 */
hal_status_t hal_uart_send(hal_uart_id_t id, const uint8_t* data,
                          size_t length, uint32_t timeout) {
    if (id >= HAL_UART_MAX) {
        return HAL_ERROR_PARAM;
    }

    if (!uart_state[id].initialized) {
        return HAL_ERROR_STATE;
    }

    if (data == NULL || length == 0) {
        return HAL_ERROR_PARAM;
    }

    /* Send data */
    for (size_t i = 0; i < length; i++) {
        if (!platform_uart_send_byte(id, data[i], timeout)) {
            return HAL_ERROR_TIMEOUT;
        }
    }

    return HAL_OK;
}

Step 3: Startup Codeยถ

Create platforms/myplatform/startup/startup.c:

/**
 * \file            startup.c
 * \brief           Startup code for MyPlatform
 * \author          Nexus Team
 */

#include <stdint.h>

/*---------------------------------------------------------------------------*/
/* External Symbols                                                          */
/*---------------------------------------------------------------------------*/

extern uint32_t _estack;
extern uint32_t _sdata;
extern uint32_t _edata;
extern uint32_t _sidata;
extern uint32_t _sbss;
extern uint32_t _ebss;

extern int main(void);

/*---------------------------------------------------------------------------*/
/* Function Prototypes                                                       */
/*---------------------------------------------------------------------------*/

void Reset_Handler(void);
void Default_Handler(void);

/*---------------------------------------------------------------------------*/
/* Vector Table                                                              */
/*---------------------------------------------------------------------------*/

__attribute__((section(".isr_vector")))
const void* vector_table[] = {
    &_estack,                   /* Initial stack pointer */
    Reset_Handler,              /* Reset handler */
    /* Add other interrupt handlers */
};

/*---------------------------------------------------------------------------*/
/* Reset Handler                                                             */
/*---------------------------------------------------------------------------*/

/**
 * \brief           Reset handler
 */
void Reset_Handler(void) {
    uint32_t* src;
    uint32_t* dst;

    /* Copy data section from flash to RAM */
    src = &_sidata;
    dst = &_sdata;
    while (dst < &_edata) {
        *dst++ = *src++;
    }

    /* Zero-initialize BSS section */
    dst = &_sbss;
    while (dst < &_ebss) {
        *dst++ = 0;
    }

    /* Call system initialization */
    SystemInit();

    /* Call main */
    main();

    /* Infinite loop if main returns */
    while (1);
}

/**
 * \brief           Default interrupt handler
 */
void Default_Handler(void) {
    while (1);
}

Step 4: Linker Scriptยถ

Create platforms/myplatform/linker/myplatform.ld:

/* Memory layout */
MEMORY
{
    FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 512K
    RAM (rwx)   : ORIGIN = 0x20000000, LENGTH = 128K
}

/* Stack size */
_stack_size = 0x2000;

/* Entry point */
ENTRY(Reset_Handler)

SECTIONS
{
    /* Vector table */
    .isr_vector :
    {
        . = ALIGN(4);
        KEEP(*(.isr_vector))
        . = ALIGN(4);
    } >FLASH

    /* Code section */
    .text :
    {
        . = ALIGN(4);
        *(.text)
        *(.text*)
        *(.rodata)
        *(.rodata*)
        . = ALIGN(4);
    } >FLASH

    /* Data section */
    .data :
    {
        . = ALIGN(4);
        _sdata = .;
        *(.data)
        *(.data*)
        . = ALIGN(4);
        _edata = .;
    } >RAM AT>FLASH

    _sidata = LOADADDR(.data);

    /* BSS section */
    .bss :
    {
        . = ALIGN(4);
        _sbss = .;
        *(.bss)
        *(.bss*)
        *(COMMON)
        . = ALIGN(4);
        _ebss = .;
    } >RAM

    /* Stack */
    .stack :
    {
        . = ALIGN(8);
        . = . + _stack_size;
        . = ALIGN(8);
        _estack = .;
    } >RAM
}

Step 5: CMake Configurationยถ

Create platforms/myplatform/CMakeLists.txt:

# Platform: MyPlatform

# Set platform name
set(PLATFORM_NAME "myplatform")

# Toolchain
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)

# Compiler
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)

# Compiler flags
set(PLATFORM_C_FLAGS
    -mcpu=cortex-m4
    -mthumb
    -mfloat-abi=hard
    -mfpu=fpv4-sp-d16
)

# Linker flags
set(PLATFORM_LINKER_FLAGS
    -T${CMAKE_CURRENT_SOURCE_DIR}/linker/myplatform.ld
    -Wl,--gc-sections
    -Wl,-Map=${CMAKE_BINARY_DIR}/${PROJECT_NAME}.map
)

# HAL sources
set(PLATFORM_HAL_SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/hal/hal_gpio.c
    ${CMAKE_CURRENT_SOURCE_DIR}/hal/hal_uart.c
    ${CMAKE_CURRENT_SOURCE_DIR}/hal/hal_spi.c
    ${CMAKE_CURRENT_SOURCE_DIR}/hal/hal_i2c.c
)

# Startup sources
set(PLATFORM_STARTUP_SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/startup/startup.c
    ${CMAKE_CURRENT_SOURCE_DIR}/startup/system_init.c
)

# Include directories
set(PLATFORM_INCLUDE_DIRS
    ${CMAKE_CURRENT_SOURCE_DIR}/config
)

# Create platform library
add_library(platform_hal STATIC
    ${PLATFORM_HAL_SOURCES}
    ${PLATFORM_STARTUP_SOURCES}
)

target_include_directories(platform_hal PUBLIC
    ${PLATFORM_INCLUDE_DIRS}
)

target_compile_options(platform_hal PRIVATE
    ${PLATFORM_C_FLAGS}
)

Step 6: Kconfig Configurationยถ

Create platforms/myplatform/Kconfig:

# MyPlatform Configuration

config PLATFORM_MYPLATFORM
    bool "MyPlatform Support"
    default n
    help
      Enable support for MyPlatform

if PLATFORM_MYPLATFORM

config MYPLATFORM_CPU_FREQ
    int "CPU Frequency (Hz)"
    default 168000000
    help
      CPU frequency in Hz

config MYPLATFORM_GPIO_PORTS
    int "Number of GPIO Ports"
    default 11
    help
      Number of GPIO ports available

config MYPLATFORM_UART_COUNT
    int "Number of UART Instances"
    default 6
    help
      Number of UART instances available

endif # PLATFORM_MYPLATFORM

Step 7: Testingยถ

Unit Tests

Create platform-specific tests:

/* tests/platform/myplatform/test_gpio.c */

#include "gtest/gtest.h"
#include "hal/hal_gpio.h"

TEST(MyPlatform_GPIO, Init) {
    hal_gpio_config_t config = {
        .mode = HAL_GPIO_MODE_OUTPUT_PP,
        .pull = HAL_GPIO_PULL_NONE,
        .speed = HAL_GPIO_SPEED_LOW,
        .init_level = HAL_GPIO_LEVEL_LOW
    };

    EXPECT_EQ(HAL_OK, hal_gpio_init(HAL_GPIO_PORT_A, 5, &config));
}

TEST(MyPlatform_GPIO, Write) {
    EXPECT_EQ(HAL_OK, hal_gpio_write(HAL_GPIO_PORT_A, 5, HAL_GPIO_LEVEL_HIGH));
}

Hardware Tests

Create hardware validation tests:

/* tests/hardware/myplatform/test_gpio_hw.c */

void test_gpio_loopback(void) {
    /* Configure PA5 as output */
    hal_gpio_config_t out_config = {
        .mode = HAL_GPIO_MODE_OUTPUT_PP,
        .pull = HAL_GPIO_PULL_NONE,
        .speed = HAL_GPIO_SPEED_LOW,
        .init_level = HAL_GPIO_LEVEL_LOW
    };
    hal_gpio_init(HAL_GPIO_PORT_A, 5, &out_config);

    /* Configure PA6 as input */
    hal_gpio_config_t in_config = {
        .mode = HAL_GPIO_MODE_INPUT,
        .pull = HAL_GPIO_PULL_NONE,
    };
    hal_gpio_init(HAL_GPIO_PORT_A, 6, &in_config);

    /* Test loopback (PA5 -> PA6) */
    hal_gpio_write(HAL_GPIO_PORT_A, 5, HAL_GPIO_LEVEL_HIGH);
    hal_gpio_level_t level;
    hal_gpio_read(HAL_GPIO_PORT_A, 6, &level);
    assert(level == HAL_GPIO_LEVEL_HIGH);
}

Platform-Specific Featuresยถ

Clock Configurationยถ

/**
 * \brief           Initialize system clocks
 */
void platform_clock_init(void) {
    /* Enable HSE (external oscillator) */
    RCC->CR |= RCC_CR_HSEON;
    while (!(RCC->CR & RCC_CR_HSERDY));

    /* Configure PLL */
    RCC->PLLCFGR = (
        RCC_PLLCFGR_PLLSRC_HSE |
        (8 << RCC_PLLCFGR_PLLM_Pos) |
        (336 << RCC_PLLCFGR_PLLN_Pos) |
        (0 << RCC_PLLCFGR_PLLP_Pos) |
        (7 << RCC_PLLCFGR_PLLQ_Pos)
    );

    /* Enable PLL */
    RCC->CR |= RCC_CR_PLLON;
    while (!(RCC->CR & RCC_CR_PLLRDY));

    /* Configure flash latency */
    FLASH->ACR = FLASH_ACR_LATENCY_5WS;

    /* Switch to PLL */
    RCC->CFGR |= RCC_CFGR_SW_PLL;
    while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
}

Interrupt Managementยถ

/**
 * \brief           Enable interrupt
 */
void platform_irq_enable(IRQn_Type irq) {
    NVIC_EnableIRQ(irq);
}

/**
 * \brief           Disable interrupt
 */
void platform_irq_disable(IRQn_Type irq) {
    NVIC_DisableIRQ(irq);
}

/**
 * \brief           Set interrupt priority
 */
void platform_irq_set_priority(IRQn_Type irq, uint32_t priority) {
    NVIC_SetPriority(irq, priority);
}

DMA Supportยถ

/**
 * \brief           Configure DMA for UART TX
 */
void platform_uart_dma_tx_init(hal_uart_id_t id, const uint8_t* data,
                               size_t length) {
    DMA_Stream_TypeDef* stream = get_uart_tx_stream(id);

    /* Disable stream */
    stream->CR &= ~DMA_SxCR_EN;
    while (stream->CR & DMA_SxCR_EN);

    /* Configure stream */
    stream->PAR = (uint32_t)&UART_INSTANCES[id]->DR;
    stream->M0AR = (uint32_t)data;
    stream->NDTR = length;
    stream->CR = (
        DMA_SxCR_CHSEL_4 |
        DMA_SxCR_MINC |
        DMA_SxCR_DIR_0 |
        DMA_SxCR_TCIE
    );

    /* Enable stream */
    stream->CR |= DMA_SxCR_EN;
}

Best Practicesยถ

Code Organizationยถ

  • Keep platform-specific code isolated

  • Use consistent naming conventions

  • Document hardware dependencies

  • Provide clear error messages

  • Handle all error conditions

Performance Optimizationยถ

  • Use DMA for bulk transfers

  • Optimize interrupt handlers

  • Minimize critical sections

  • Use hardware features efficiently

  • Profile and measure performance

Testing Strategyยถ

  • Unit test all HAL functions

  • Property-based testing for HAL

  • Hardware validation tests

  • Stress testing

  • Power consumption testing

Documentationยถ

  • Document hardware requirements

  • Provide pin mapping tables

  • Document clock configuration

  • List known limitations

  • Provide usage examples

Common Issuesยถ

Clock Configurationยถ

Issue: System doesnโ€™t start

Solutions: * Verify oscillator frequency * Check PLL configuration * Verify flash wait states * Check power supply voltage

Memory Layoutยถ

Issue: Hard fault on startup

Solutions: * Verify linker script * Check stack size * Verify memory regions * Check vector table alignment

Interrupt Prioritiesยถ

Issue: Interrupt not firing

Solutions: * Enable interrupt in NVIC * Set appropriate priority * Clear pending flags * Verify interrupt handler name

See Alsoยถ

Summaryยถ

Porting Nexus to a new platform involves:

  1. Create platform directory structure

  2. Implement HAL for all peripherals

  3. Create startup code and linker script

  4. Configure CMake build system

  5. Add Kconfig options

  6. Write comprehensive tests

  7. Document platform-specific features

Following this guide ensures a complete, tested, and maintainable platform port.