Hardware Abstraction Layer (HAL)ΒΆ

OverviewΒΆ

The Nexus HAL provides a unified, object-oriented interface for hardware peripherals across different MCU platforms. It uses a factory pattern to create device instances and interface-based design for operations.

Key features:

  • Factory pattern for device creation and lifecycle management

  • Interface-based design with consistent API across peripherals

  • Reference counting for safe resource management

  • Support for both synchronous and asynchronous operations

  • Power management and diagnostic interfaces

ArchitectureΒΆ

The HAL is organized into several layers:

+------------------+
|   Application    |
+------------------+
       |
+------------------+
|   nx_factory     |  Device creation and management
+------------------+
       |
+------------------+
|   Interfaces     |  nx_gpio_t, nx_uart_t, nx_spi_t, etc.
+------------------+
       |
+------------------+
|   Platform HAL   |  STM32F4, Native, etc.
+------------------+

Supported PeripheralsΒΆ

Module

Interface

Description

GPIO

nx_gpio_t

General I/O

UART

nx_uart_t

Serial comm

SPI

nx_spi_t

SPI bus

I2C

nx_i2c_t

I2C bus

Timer

nx_timer_t

Hardware timers

ADC

nx_adc_t

Analog input

Getting StartedΒΆ

Include the main header:

#include "hal/nx_hal.h"

Initialize and use:

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

    /* Get a GPIO device */
    nx_gpio_t* led = nx_factory_gpio(0, 5);  /* Port A, Pin 5 */
    if (led) {
        led->write(led, 1);  /* Turn on */
        nx_factory_gpio_release(led);
    }

    /* Cleanup */
    nx_hal_deinit();
    return 0;
}

GPIO ModuleΒΆ

Get GPIO with default configuration:

nx_gpio_t* gpio = nx_factory_gpio(port, pin);

Get GPIO with custom configuration:

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

nx_gpio_t* led = nx_factory_gpio_with_config(0, 5, &cfg);

Operations:

/* Write */
led->write(led, 1);  /* High */
led->write(led, 0);  /* Low */

/* Read */
uint8_t state = led->read(led);

/* Toggle */
led->toggle(led);

/* Runtime configuration */
led->set_mode(led, NX_GPIO_MODE_INPUT);
led->set_pull(led, NX_GPIO_PULL_UP);

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

External interrupt:

void button_callback(void* ctx)
{
    /* Handle button press */
}

nx_gpio_t* btn = nx_factory_gpio(0, 0);
btn->set_mode(btn, NX_GPIO_MODE_INPUT);
btn->set_exti(btn, NX_GPIO_EXTI_FALLING, button_callback, NULL);

UART ModuleΒΆ

Get UART with default configuration:

nx_uart_t* uart = nx_factory_uart(0);

Get UART with custom configuration:

nx_uart_config_t cfg = {
    .baudrate     = 115200,
    .word_length  = 8,
    .stop_bits    = 1,
    .parity       = 0,  /* None */
    .flow_control = 0,  /* None */
};

nx_uart_t* uart = nx_factory_uart_with_config(0, &cfg);

Synchronous operations:

nx_tx_sync_t* tx = uart->get_tx_sync(uart);
nx_rx_sync_t* rx = uart->get_rx_sync(uart);

/* Transmit with timeout */
const char* msg = "Hello, Nexus!";
tx->send(tx, (uint8_t*)msg, strlen(msg), 1000);

/* Receive with timeout */
uint8_t buf[64];
rx->receive(rx, buf, sizeof(buf), 1000);

Asynchronous operations:

nx_tx_async_t* tx = uart->get_tx_async(uart);
nx_rx_async_t* rx = uart->get_rx_async(uart);

/* Non-blocking send */
tx->send(tx, data, len);

/* Check available data */
size_t avail = rx->available(rx);
if (avail > 0) {
    size_t read = rx->read(rx, buf, avail);
}

/* Set receive callback */
rx->set_callback(rx, my_rx_callback, NULL);

Release when done:

nx_factory_uart_release(uart);

SPI ModuleΒΆ

Get SPI device:

nx_spi_t* spi = nx_factory_spi(0);

/* Or with configuration */
nx_spi_config_t cfg = {
    .clock_hz   = 1000000,
    .mode       = 0,
    .bit_order  = NX_SPI_MSB_FIRST,
};
nx_spi_t* spi = nx_factory_spi_with_config(0, &cfg);

/* Use SPI... */

nx_factory_spi_release(spi);

I2C ModuleΒΆ

Get I2C device:

nx_i2c_t* i2c = nx_factory_i2c(0);

/* Or with configuration */
nx_i2c_config_t cfg = {
    .clock_hz = 100000,  /* 100 kHz */
};
nx_i2c_t* i2c = nx_factory_i2c_with_config(0, &cfg);

/* Use I2C... */

nx_factory_i2c_release(i2c);

Error HandlingΒΆ

All factory functions return NULL on failure. Interface methods return nx_status_t:

nx_gpio_t* gpio = nx_factory_gpio(port, pin);
if (!gpio) {
    /* Handle error: device not available */
    return -1;
}

nx_status_t status = gpio->set_mode(gpio, NX_GPIO_MODE_OUTPUT_PP);
if (status != NX_OK) {
    /* Handle error */
}

Common status codes:

  • NX_OK - Success

  • NX_ERR_PARAM - Invalid parameter

  • NX_ERR_STATE - Invalid state

  • NX_ERR_TIMEOUT - Operation timeout

  • NX_ERR_BUSY - Resource busy

  • NX_ERR_NO_MEM - Out of memory

Lifecycle ManagementΒΆ

Devices support lifecycle operations through the nx_lifecycle_t interface:

nx_gpio_t* gpio = nx_factory_gpio(0, 5);
nx_lifecycle_t* lc = gpio->get_lifecycle(gpio);

/* Suspend device */
lc->suspend(lc);

/* Resume device */
lc->resume(lc);

Power ManagementΒΆ

Devices support power management through the nx_power_t interface:

nx_uart_t* uart = nx_factory_uart(0);
nx_power_t* pwr = uart->get_power(uart);

/* Enter low power mode */
pwr->set_mode(pwr, NX_POWER_MODE_SLEEP);

/* Wake up */
pwr->set_mode(pwr, NX_POWER_MODE_NORMAL);

API ReferenceΒΆ

See HAL API Reference for complete API documentation.