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:
Separation of Concerns: Each layer has a specific responsibility
Abstraction: Hide implementation details behind clean interfaces
Portability: Minimize platform-specific code in applications
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ยถ
Separate concerns: One file per module
Use headers: Public API in headers, implementation in source
Minimize dependencies: Reduce coupling between modules
Document interfaces: Use Doxygen comments
Error Handlingยถ
Check all return values: Never ignore errors
Log errors: Use logging framework
Fail gracefully: Implement recovery strategies
Use assertions: For programming errors
Resource Managementยถ
Initialize before use: Always initialize resources
Clean up: Release resources when done
Avoid leaks: Match allocations with deallocations
Use RAII pattern: Acquire resources in initialization
Concurrencyยถ
Protect shared data: Use mutexes
Avoid deadlocks: Acquire locks in consistent order
Minimize critical sections: Hold locks briefly
Use queues: For inter-task communication
Testingยถ
Write unit tests: Test individual components
Test error paths: Donโt just test happy path
Use mocks: Isolate dependencies
Automate tests: Run tests in CI/CD
Next Stepsยถ
Now that you understand core concepts:
Configuration - Master Kconfig configuration
Examples Tour - Explore complex examples
Architecture - Deep dive into architecture
Tutorials - Follow step-by-step tutorials
See Alsoยถ
Hardware Abstraction Layer (HAL) - HAL API reference
OS Abstraction Layer (OSAL) - OSAL API reference
Log Framework - Logging framework
Coding Standards - Coding standards