Core Conceptsยถ

This guide explains the fundamental concepts and design principles of the Nexus platform.

Architecture Overviewยถ

Layered Designยถ

Nexus follows a strict layered architecture:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚        Application Layer            โ”‚  Your code
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚        Framework Layer              โ”‚  Log, Shell, Config, Init
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚    OS Abstraction Layer (OSAL)      โ”‚  Tasks, Mutex, Queue, Timer
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  Hardware Abstraction Layer (HAL)   โ”‚  GPIO, UART, SPI, I2C, ADC
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚        Platform Layer               โ”‚  STM32F4, STM32H7, Native
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Key Principles:

  1. Separation of Concerns: Each layer has a specific responsibility

  2. Abstraction: Hide implementation details behind clean interfaces

  3. Portability: Minimize platform-specific code in applications

  4. Dependency Rule: Upper layers depend on lower layers, never reverse

Design Patternsยถ

Factory Pattern

HAL uses factory functions to create device instances:

/* Create GPIO device */
nx_gpio_write_t* led = nx_factory_gpio_write('A', 5);

/* Use device */
led->toggle(led);

/* Release device */
nx_factory_gpio_release((nx_gpio_t*)led);

Interface Pattern

Devices expose interfaces with function pointers:

typedef struct {
    void (*write)(nx_gpio_write_t* self, uint8_t value);
    void (*toggle)(nx_gpio_write_t* self);
    uint8_t (*read)(nx_gpio_write_t* self);
} nx_gpio_write_t;

Adapter Pattern

OSAL adapts different RTOS backends to a common interface:

/* Same API works with FreeRTOS, bare-metal, etc. */
osal_task_create(task_func, "task", 512, NULL, 1, NULL);

Hardware Abstraction Layer (HAL)ยถ

Purposeยถ

HAL provides unified APIs for hardware peripherals, hiding platform differences.

Benefits:

  • Write once, run on multiple platforms

  • Consistent API across different MCUs

  • Easy to test with native simulation

  • Simplified driver development

Key Conceptsยถ

Device Instances

Each peripheral is represented as a device instance:

/* GPIO device */
nx_gpio_write_t* led;

/* UART device */
nx_uart_t* uart;

/* SPI device */
nx_spi_t* spi;

Configuration Structures

Devices are configured using structures:

nx_gpio_config_t gpio_cfg = {
    .mode  = NX_GPIO_MODE_OUTPUT_PP,
    .pull  = NX_GPIO_PULL_NONE,
    .speed = NX_GPIO_SPEED_LOW,
};

nx_uart_config_t uart_cfg = {
    .baudrate    = 115200,
    .word_length = 8,
    .stop_bits   = 1,
    .parity      = 0,
};

Factory Functions

Create devices using factory functions:

/* Simple creation */
nx_gpio_write_t* led = nx_factory_gpio_write('A', 5);

/* Creation with configuration */
nx_gpio_t* gpio = nx_factory_gpio_with_config('A', 5, &gpio_cfg);

/* Release when done */
nx_factory_gpio_release(gpio);

Interface Methods

Access device functionality through interface methods:

/* GPIO operations */
led->write(led, 1);
led->toggle(led);
uint8_t state = led->read(led);

/* UART operations */
nx_tx_sync_t* tx = uart->get_tx_sync(uart);
tx->send(tx, data, len, timeout);

Peripheral Typesยถ

GPIO - General Purpose I/O

  • Digital input/output

  • Interrupt support

  • Pull-up/pull-down configuration

UART - Serial Communication

  • Asynchronous serial

  • Configurable baud rate

  • TX/RX with timeouts

SPI - Serial Peripheral Interface

  • Master/slave modes

  • Full-duplex communication

  • Configurable clock polarity/phase

I2C - Inter-Integrated Circuit

  • Master/slave modes

  • 7-bit/10-bit addressing

  • Clock stretching support

ADC - Analog-to-Digital Converter

  • Single/continuous conversion

  • Multiple channels

  • DMA support

Timer - Hardware Timers

  • PWM generation

  • Input capture

  • Output compare

See Hardware Abstraction Layer (HAL) for detailed HAL documentation.

OS Abstraction Layer (OSAL)ยถ

Purposeยถ

OSAL provides portable RTOS primitives, allowing applications to work with different operating systems.

Supported Backends:

  • Bare-metal (cooperative scheduling)

  • FreeRTOS

  • RT-Thread

  • Zephyr

Key Conceptsยถ

Tasks/Threads

Create and manage concurrent execution:

/* Task function */
void my_task(void* arg) {
    while (1) {
        /* Task work */
        osal_task_delay(1000);
    }
}

/* Create task */
osal_task_handle_t task;
osal_task_create(my_task, "my_task", 512, NULL, 1, &task);

Mutexes

Mutual exclusion for shared resources:

/* Create mutex */
osal_mutex_handle_t mutex;
osal_mutex_create(&mutex);

/* Lock */
osal_mutex_lock(mutex, OSAL_WAIT_FOREVER);

/* Critical section */
shared_resource++;

/* Unlock */
osal_mutex_unlock(mutex);

Semaphores

Signaling and resource counting:

/* Create binary semaphore */
osal_sem_handle_t sem;
osal_sem_create(&sem, 0, 1);

/* Wait for signal */
osal_sem_wait(sem, OSAL_WAIT_FOREVER);

/* Signal */
osal_sem_give(sem);

Message Queues

Inter-task communication:

/* Create queue */
osal_queue_handle_t queue;
osal_queue_create(&queue, 10, sizeof(message_t));

/* Send message */
message_t msg = {.id = 1, .data = 42};
osal_queue_send(queue, &msg, OSAL_WAIT_FOREVER);

/* Receive message */
message_t received;
osal_queue_receive(queue, &received, OSAL_WAIT_FOREVER);

Software Timers

Periodic or one-shot timers:

/* Timer callback */
void timer_callback(void* arg) {
    /* Timer expired */
}

/* Create timer */
osal_timer_handle_t timer;
osal_timer_create(&timer, "timer", 1000, true, NULL, timer_callback);

/* Start timer */
osal_timer_start(timer);

Synchronization Patternsยถ

Producer-Consumer

/* Producer task */
void producer_task(void* arg) {
    while (1) {
        data_t data = produce_data();
        osal_queue_send(queue, &data, OSAL_WAIT_FOREVER);
    }
}

/* Consumer task */
void consumer_task(void* arg) {
    while (1) {
        data_t data;
        osal_queue_receive(queue, &data, OSAL_WAIT_FOREVER);
        consume_data(&data);
    }
}

Resource Protection

/* Shared resource with mutex */
static int shared_counter = 0;
static osal_mutex_handle_t counter_mutex;

void increment_counter(void) {
    osal_mutex_lock(counter_mutex, OSAL_WAIT_FOREVER);
    shared_counter++;
    osal_mutex_unlock(counter_mutex);
}

See OS Abstraction Layer (OSAL) for detailed OSAL documentation.

Framework Layerยถ

Logging Frameworkยถ

Flexible logging with multiple backends and log levels.

Log Levels:

LOG_ERROR("Critical error: %d", error_code);
LOG_WARN("Warning: %s", warning_msg);
LOG_INFO("Information: %d", value);
LOG_DEBUG("Debug: %s", debug_info);

Module Filtering:

/* Define module */
#define LOG_MODULE "MyModule"

/* Log with module tag */
LOG_INFO("Module-specific log");

Backends:

  • Console (stdout)

  • UART

  • File

  • Custom backends

See Log Framework for detailed logging documentation.

Shell Frameworkยถ

Interactive command-line interface for debugging and control.

Command Registration:

static int cmd_handler(int argc, char* argv[]) {
    shell_printf("Command executed\n");
    return 0;
}

static const shell_command_t cmd_def = {
    .name = "mycommand",
    .handler = cmd_handler,
    .help = "My custom command",
    .usage = "mycommand [args]",
    .completion = NULL
};

shell_register_command(&cmd_def);

Features:

  • Command history

  • Tab completion

  • Built-in commands (help, clear, reboot)

  • Custom command registration

See Shell Framework for detailed shell documentation.

Configuration Frameworkยถ

Key-value configuration storage with persistence.

Basic Usage:

/* Store values */
config_set_i32("app.timeout", 5000);
config_set_str("device.name", "MyDevice");
config_set_bool("feature.enabled", true);

/* Retrieve values */
int32_t timeout;
config_get_i32("app.timeout", &timeout, 0);

Namespaces:

/* Open namespace */
config_ns_handle_t wifi_ns;
config_open_namespace("wifi", &wifi_ns);

/* Store in namespace */
config_ns_set_str(wifi_ns, "ssid", "MyNetwork");

/* Close namespace */
config_close_namespace(wifi_ns);

Import/Export:

/* Export to JSON */
char buffer[1024];
size_t size;
config_export(CONFIG_FORMAT_JSON, 0, buffer, sizeof(buffer), &size);

/* Import from JSON */
config_import(CONFIG_FORMAT_JSON, 0, buffer, size);

See Config Manager for detailed configuration documentation.

Configuration System (Kconfig)ยถ

Purposeยถ

Kconfig provides compile-time configuration for:

  • Platform selection

  • Peripheral enablement

  • Feature selection

  • Resource allocation

Key Conceptsยถ

Configuration Options

Define what features to include:

config HAL_GPIO
    bool "Enable GPIO support"
    default y
    help
      Enable GPIO peripheral support

Dependencies

Express relationships between options:

config HAL_SPI
    bool "Enable SPI support"
    depends on HAL_GPIO
    help
      Enable SPI peripheral support

Defaults

Provide sensible defaults:

config HAL_UART_BAUDRATE
    int "Default UART baud rate"
    default 115200
    range 9600 921600

Generated Header

Kconfig generates nexus_config.h:

#define CONFIG_HAL_GPIO 1
#define CONFIG_HAL_UART 1
#define CONFIG_HAL_UART_BAUDRATE 115200

Usage in Codeยถ

#include "nexus_config.h"

#ifdef CONFIG_HAL_GPIO
/* GPIO code */
#endif

#ifdef CONFIG_HAL_UART
/* UART code */
#endif

See Configuration for detailed Kconfig usage.

Memory Managementยถ

Static Allocationยถ

All memory allocated at compile time:

Advantages:

  • Deterministic behavior

  • No fragmentation

  • Suitable for safety-critical systems

Disadvantages:

  • Less flexible

  • May waste memory

Example:

#define MAX_DEVICES 10
static device_t devices[MAX_DEVICES];

Dynamic Allocationยถ

Runtime memory allocation:

Advantages:

  • Flexible

  • Efficient memory usage

Disadvantages:

  • Fragmentation risk

  • Non-deterministic

Example:

device_t* device = malloc(sizeof(device_t));
/* Use device */
free(device);

Pool Allocationยถ

Fixed-size memory pools:

Advantages:

  • Fast allocation

  • No fragmentation

  • Predictable behavior

Disadvantages:

  • Fixed block size

  • May waste memory

Example:

/* Create pool */
osal_pool_handle_t pool;
osal_pool_create(&pool, 10, sizeof(device_t));

/* Allocate from pool */
device_t* device = osal_pool_alloc(pool);

/* Return to pool */
osal_pool_free(pool, device);

Error Handlingยถ

Status Codesยถ

All APIs return status codes:

typedef enum {
    HAL_OK = 0,
    HAL_ERR_FAIL,
    HAL_ERR_PARAM,
    HAL_ERR_STATE,
    HAL_ERR_TIMEOUT,
    HAL_ERR_NO_MEMORY,
} hal_status_t;

Error Checkingยถ

Always check return values:

hal_status_t status = hal_gpio_init(port, pin, &config);
if (status != HAL_OK) {
    LOG_ERROR("GPIO init failed: %d", status);
    return status;
}

Error Recoveryยถ

Implement appropriate recovery strategies:

/* Retry on timeout */
int retries = 3;
while (retries--) {
    status = hal_uart_send(uart, data, len, timeout);
    if (status == HAL_OK) {
        break;
    }
    if (status == HAL_ERR_TIMEOUT) {
        continue;  /* Retry */
    }
    return status;  /* Other errors */
}

Resource Managementยถ

Initializationยถ

Proper initialization order:

int main(void) {
    /* 1. Initialize HAL */
    nx_hal_init();

    /* 2. Initialize OSAL */
    osal_init();

    /* 3. Initialize frameworks */
    log_init(NULL);
    shell_init(&shell_config);

    /* 4. Initialize application */
    app_init();

    /* 5. Start scheduler (if using RTOS) */
    osal_start_scheduler();

    return 0;
}

Cleanupยถ

Proper resource cleanup:

void app_cleanup(void) {
    /* Release devices */
    nx_factory_gpio_release(led);
    nx_factory_uart_release(uart);

    /* Deinitialize frameworks */
    shell_deinit();
    log_deinit();

    /* Deinitialize HAL */
    nx_hal_deinit();
}

Best Practicesยถ

Code Organizationยถ

  1. Separate concerns: One file per module

  2. Use headers: Public API in headers, implementation in source

  3. Minimize dependencies: Reduce coupling between modules

  4. Document interfaces: Use Doxygen comments

Error Handlingยถ

  1. Check all return values: Never ignore errors

  2. Log errors: Use logging framework

  3. Fail gracefully: Implement recovery strategies

  4. Use assertions: For programming errors

Resource Managementยถ

  1. Initialize before use: Always initialize resources

  2. Clean up: Release resources when done

  3. Avoid leaks: Match allocations with deallocations

  4. Use RAII pattern: Acquire resources in initialization

Concurrencyยถ

  1. Protect shared data: Use mutexes

  2. Avoid deadlocks: Acquire locks in consistent order

  3. Minimize critical sections: Hold locks briefly

  4. Use queues: For inter-task communication

Testingยถ

  1. Write unit tests: Test individual components

  2. Test error paths: Donโ€™t just test happy path

  3. Use mocks: Isolate dependencies

  4. Automate tests: Run tests in CI/CD

Next Stepsยถ

Now that you understand core concepts:

  1. Configuration - Master Kconfig configuration

  2. Examples Tour - Explore complex examples

  3. Architecture - Deep dive into architecture

  4. Tutorials - Follow step-by-step tutorials

See Alsoยถ