πŸ”§ HardFOC Internal Interface Layer:

Multi-MCU Peripherals Interface

C++ License CI Docs

🎯 Universal Hardware Interface for Multi-MCU Development

A professional hardware abstraction layer enabling seamless MCU portability through unified peripheral APIs - designed for the HardFOC board ecosystem


πŸ“š Table of Contents


🎯 Overview

πŸ“– πŸ“šπŸŒ Live Complete Documentation - Interactive guides, examples, and step-by-step tutorials

This Internal Interface Wrap (IID) provides a unified interface for common MCU peripherals, enabling seamless portability between different microcontroller platforms. Originally designed for the HardFOC board which needs to support multiple MCU types, this abstraction layer allows developers to write hardware-agnostic code while maintaining optimal performance.

πŸ† Core Benefits

  • πŸ”„ MCU Portability - Write once, run on multiple MCU platforms
  • 🎯 Unified APIs - Consistent interface across all peripheral types
  • ⚑ Performance - Zero-cost abstractions with compile-time optimization
  • πŸ›‘οΈ Type Safety - Strong typing with project-specific type system
  • πŸ“ˆ Extensible - Easy to add new MCUs and peripheral drivers
  • πŸ”Œ Complete Coverage - 14+ peripheral interfaces for comprehensive hardware control

🎨 Design Philosophy

1
2
3
4
5
6
// Write hardware-agnostic code
BaseGpio* led = GpioFactory::Create(GPIO_PIN_2, GPIO_OUTPUT);
led->SetHigh();

// Same code works on ESP32, STM32, or any supported MCU
// The factory handles MCU-specific implementation selection

πŸ—οΈ Architecture

Two-Layer Design

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
πŸ“¦ Hardware Abstraction Layer
β”œβ”€β”€ 🎯 Base Layer (inc/base/)           # Abstract interfaces
β”‚   β”œβ”€β”€ BaseGpio.h                      # GPIO operations
β”‚   β”œβ”€β”€ BaseAdc.h                       # Analog-to-digital conversion
β”‚   β”œβ”€β”€ BasePwm.h                       # Pulse width modulation
β”‚   β”œβ”€β”€ BaseUart.h                      # Serial communication
β”‚   β”œβ”€β”€ BaseI2c.h                       # I2C bus operations
β”‚   β”œβ”€β”€ BaseSpi.h                       # SPI bus operations
β”‚   β”œβ”€β”€ BaseCan.h                       # CAN bus communication
β”‚   β”œβ”€β”€ BaseWifi.h                      # WiFi networking
β”‚   β”œβ”€β”€ BaseBluetooth.h                 # Bluetooth connectivity
β”‚   β”œβ”€β”€ BaseNvs.h                       # Non-volatile storage
β”‚   β”œβ”€β”€ BaseLogger.h                    # Unified logging system
β”‚   β”œβ”€β”€ BaseTemperature.h               # Temperature sensing
β”‚   β”œβ”€β”€ BasePeriodicTimer.h             # Timer operations
β”‚   └── BasePio.h                       # Programmable I/O (advanced GPIO)
β”‚
└── πŸ”§ MCU Layer (inc/mcu/ & src/mcu/)  # Platform implementations
    β”œβ”€β”€ esp32/                          # ESP32 family support
    β”‚   β”œβ”€β”€ EspGpio.h/.cpp             # ESP32 GPIO implementation
    β”‚   β”œβ”€β”€ EspAdc.h/.cpp              # ESP32 ADC implementation
    β”‚   β”œβ”€β”€ EspPwm.h/.cpp              # ESP32 PWM implementation
    β”‚   └── ...                        # All other ESP32 peripherals
    β”‚
    β”œβ”€β”€ stm32/                          # STM32 family (future)
    β”‚   └── ...                        # STM32 implementations
    β”‚
    └── nrf/                            # Nordic nRF (future)
        └── ...                        # nRF implementations

Abstraction Benefits

1. MCU Independence

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Application code remains the same across MCUs
class MotorController {
    BaseGpio* enable_pin;
    BasePwm* speed_control;
    BaseAdc* current_sensor;
    
public:
    void Initialize() {
        enable_pin = GpioFactory::Create(MOTOR_ENABLE_PIN, GPIO_OUTPUT);
        speed_control = PwmFactory::Create(PWM_CHANNEL_1, 1000); // 1kHz
        current_sensor = AdcFactory::Create(ADC_CHANNEL_1);
    }
    
    void SetSpeed(hf_u16_t speed_percent) {
        speed_control->SetDutyCycle(speed_percent);
    }
};

2. External Driver Support

The base classes can be extended for external chips:

1
2
3
4
5
6
7
8
9
10
11
// External motor driver chip
class DRV8302_Driver : public BasePwm {
    BaseI2c* i2c_bus;
    BaseSpi* spi_bus;
    
public:
    // Implement BasePwm interface using external chip
    void SetDutyCycle(hf_u16_t duty) override {
        // Send PWM command to DRV8302 via SPI/I2C
    }
};

πŸ”Œ Peripheral Interfaces

πŸ“– πŸ“šπŸŒ Live Complete Documentation - Interactive guides, examples, and step-by-step tutorials

Core Peripherals

Interface Purpose Key Features

|β€”β€”β€”β€”β€”|β€”β€”β€”β€”-|β€”β€”β€”β€”β€”β€”|

BaseGpio Digital I/O control Input/output, interrupts, pull-up/down
BaseAdc Analog measurement Multi-channel, calibration, DMA support
BasePwm Motor/servo control Frequency control, duty cycle, phase alignment
BaseUart Serial communication Async I/O, flow control, custom baud rates

Communication Buses

Interface Purpose Key Features

|β€”β€”β€”β€”β€”|β€”β€”β€”β€”-|β€”β€”β€”β€”β€”β€”|

BaseI2c Sensor communication Master/slave, clock stretching, error recovery
BaseSpi High-speed data Full/half duplex, DMA, chip select management
BaseCan Automotive/industrial Message filtering, error handling, bus monitoring

Wireless Connectivity

Interface Purpose Key Features

|β€”β€”β€”β€”β€”|β€”β€”β€”β€”-|β€”β€”β€”β€”β€”β€”|

BaseWifi Network connectivity STA/AP modes, WPA3 security, power management
BaseBluetooth Short-range wireless Classic/BLE, pairing, service discovery

System Services

Interface Purpose Key Features

|β€”β€”β€”β€”β€”|β€”β€”β€”β€”-|β€”β€”β€”β€”β€”β€”|

BaseNvs Configuration storage Key-value pairs, encryption, wear leveling
BaseLogger Debug/monitoring Multiple levels, async logging, filtering
BaseTemperature Thermal monitoring Internal/external sensors, calibration
BasePeriodicTimer Task scheduling Precise timing, ISR-safe callbacks
BasePio Advanced GPIO State machines, DMA, complex protocols

πŸ–₯️ MCU Support

Currently Supported

ESP32 Family βœ…

  • ESP32 - Original dual-core WiFi/BT
  • ESP32-C6 - RISC-V with WiFi 6 + Zigbee
  • ESP32-S3 - Dual-core with AI acceleration
  • ESP32-C3 - Single-core RISC-V WiFi/BT

Implementation Status: All 14 peripheral interfaces fully implemented

Planned Support

STM32 Family 🚧

  • STM32F4 - High-performance ARM Cortex-M4
  • STM32H7 - Dual-core ARM Cortex-M7
  • STM32G4 - Motor control optimized

Nordic nRF 🚧

  • nRF52840 - Bluetooth 5.0 + Thread/Zigbee
  • nRF5340 - Dual-core Bluetooth 5.2

Adding New MCUs

  1. Create MCU directory: inc/mcu/your_mcu/ and src/mcu/your_mcu/
  2. Implement base interfaces: Inherit from base classes
  3. Add factory support: Register your implementations
  4. Update build system: Add MCU-specific compilation flags
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Example: Adding STM32 GPIO support
class Stm32Gpio : public BaseGpio {
    GPIO_TypeDef* gpio_port;
    hf_u16_t gpio_pin;
    
public:
    void SetHigh() override {
        HAL_GPIO_WritePin(gpio_port, gpio_pin, GPIO_PIN_SET);
    }
    
    void SetLow() override {
        HAL_GPIO_WritePin(gpio_port, gpio_pin, GPIO_PIN_RESET);
    }
};

πŸš€ Quick Start

1. Clone Repository

1
2
git clone <repository-url>
cd hf-internal-interface-wrap

2. Setup Development Environment

1
2
3
## For ESP32 development
cd examples/esp32
./scripts/setup_repo.sh

3. Build Example

1
2
## Build GPIO test for ESP32
./scripts/build_app.sh gpio_test Release esp32

4. Flash and Monitor

1
2
3
4
5
## Flash to connected ESP32
./scripts/flash_app.sh gpio_test Release flash

## Monitor serial output
./scripts/flash_app.sh gpio_test Release monitor

5. Basic Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "base/BaseGpio.h"
#include "mcu/esp32/EspGpio.h"

void setup() {
    // Create GPIO instance for built-in LED
    BaseGpio* led = new EspGpio(GPIO_NUM_2, GPIO_MODE_OUTPUT);
    
    // Blink LED
    while(true) {
        led->SetHigh();
        vTaskDelay(pdMS_TO_TICKS(500));
        led->SetLow();
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

πŸ“– API Documentation

Generated Documentation

Key Concepts

Type System

1
2
3
4
5
6
7
8
9
10
// Project uses consistent type definitions
typedef uint8_t  hf_u8_t;
typedef uint16_t hf_u16_t;
typedef uint32_t hf_u32_t;

// Enums use snake_case with *t suffix
enum class hf_gpio_state_t {
    LOW = 0,
    HIGH = 1
};

Error Handling

1
2
3
4
5
6
7
8
9
10
11
12
// All operations return status codes
enum class hf_gpio_err_t {
    SUCCESS = 0,
    INVALID_PIN,
    ALREADY_CONFIGURED,
    HARDWARE_ERROR
};

hf_gpio_err_t result = gpio->Configure(GPIO_MODE_OUTPUT);
if (result != hf_gpio_err_t::SUCCESS) {
    Logger::GetInstance().LogError("GPIO configuration failed");
}

Factory Pattern

The factory pattern enables completely MCU-agnostic code by automatically selecting the correct implementation at compile time. Factories support both dynamic allocation (heap-based) and static allocation (stack-based) patterns:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// inc/utils/GpioFactory.h - MCU-agnostic factory interface
class GpioFactory {
public:
    static BaseGpio* Create(hf_u8_t pin, gpio_mode_t mode);
    static BaseGpio* CreateWithInterrupt(hf_u8_t pin, gpio_isr_t callback);
    static void Destroy(BaseGpio* gpio);
};

// src/utils/GpioFactory.cpp - Automatic MCU selection
BaseGpio* GpioFactory::Create(hf_u8_t pin, gpio_mode_t mode) {
#ifdef MCU_ESP32
    return new EspGpio(static_cast<gpio_num_t>(pin), mode);
#elif defined(MCU_STM32)
    return new Stm32Gpio(pin, mode);
#elif defined(MCU_NRF)
    return new NrfGpio(pin, mode);
#else
    #error "Unsupported MCU platform"
#endif
}

// Application code - same across all MCUs
BaseGpio* led = GpioFactory::Create(GPIO_PIN_2, GPIO_OUTPUT);
BaseGpio* button = GpioFactory::CreateWithInterrupt(GPIO_PIN_0, button_callback);

Static Allocation Alternative:

For systems requiring deterministic memory usage or avoiding heap allocation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// inc/utils/StaticGpioFactory.h - Stack-based allocation (C++23 compatible)
template<size_t MAX_GPIOS = 16>
class StaticGpioFactory {
private:
    // Modern C++23 approach: alignas + std::byte array instead of deprecated std::aligned_storage
    static std::array<alignas(BaseGpio) std::byte[sizeof(EspGpio)], MAX_GPIOS> gpio_storage;
    static std::array<bool, MAX_GPIOS> gpio_used;
    static size_t next_index;
    
public:
    static BaseGpio* Create(hf_u8_t pin, gpio_mode_t mode) {
        if (next_index >= MAX_GPIOS) return nullptr;
        
        // Construct in-place in pre-allocated storage using placement new
        void* storage = &gpio_storage[next_index];
        BaseGpio* gpio = nullptr;
        
#ifdef MCU_ESP32
        gpio = new(storage) EspGpio(static_cast<gpio_num_t>(pin), mode);
#elif defined(MCU_STM32)
        gpio = new(storage) Stm32Gpio(pin, mode);
#elif defined(MCU_NRF)
        gpio = new(storage) NrfGpio(pin, mode);
#endif
        
        gpio_used[next_index] = true;
        next_index++;
        return gpio;
    }
    
    static void DestroyAll() {
        for (size_t i = 0; i < next_index; ++i) {
            if (gpio_used[i]) {
                // Use std::launder for safe pointer conversion (C++17+)
                BaseGpio* gpio = std::launder(reinterpret_cast<BaseGpio*>(&gpio_storage[i]));
                gpio->~BaseGpio();  // Call destructor explicitly
                gpio_used[i] = false;
            }
        }
        next_index = 0;
    }
};

// Pre-allocated object pool for known hardware configuration
class HardwarePool {
private:
    // Modern C++23 approach: alignas + std::byte arrays instead of deprecated std::aligned_storage
    alignas(BaseGpio) std::byte motor_enable_storage[sizeof(EspGpio)];
    alignas(BaseGpio) std::byte fault_pin_storage[sizeof(EspGpio)];
    alignas(BasePwm) std::byte motor_pwm_storage[sizeof(EspPwm)];
    alignas(BaseAdc) std::byte current_adc_storage[sizeof(EspAdc)];
    
public:
    BaseGpio* motor_enable;
    BaseGpio* fault_pin;
    BasePwm* motor_pwm;
    BaseAdc* current_adc;
    
    // Constructor creates all objects in pre-allocated storage
    HardwarePool() {
#ifdef MCU_ESP32
        motor_enable = new(&motor_enable_storage) EspGpio(GPIO_NUM_5, GPIO_MODE_OUTPUT);
        fault_pin = new(&fault_pin_storage) EspGpio(GPIO_NUM_4, GPIO_MODE_INPUT);
        motor_pwm = new(&motor_pwm_storage) EspPwm(LEDC_CHANNEL_0, 20000, 12, GPIO_NUM_18);
        current_adc = new(&current_adc_storage) EspAdc(ADC1_CHANNEL_0);
#elif defined(MCU_STM32)
        motor_enable = new(&motor_enable_storage) Stm32Gpio(5, GPIO_MODE_OUTPUT);
        fault_pin = new(&fault_pin_storage) Stm32Gpio(4, GPIO_MODE_INPUT);
        motor_pwm = new(&motor_pwm_storage) Stm32Pwm(TIM1, 20000, 5);
        current_adc = new(&current_adc_storage) Stm32Adc(ADC1, 0);
#endif
    }
    
    // Destructor calls destructors explicitly
    ~HardwarePool() {
        if (motor_enable) motor_enable->~BaseGpio();
        if (fault_pin) fault_pin->~BaseGpio();
        if (motor_pwm) motor_pwm->~BasePwm();
        if (current_adc) current_adc->~BaseAdc();
    }
};

Usage Comparison:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// Dynamic allocation (heap-based)
class DynamicController {
    BaseGpio* motor_enable;
    BasePwm* motor_speed;
    
public:
    void Initialize() {
        motor_enable = GpioFactory::Create(GPIO_PIN_5, GPIO_OUTPUT);
        motor_speed = PwmFactory::CreateMotorControl(PWM_CH_0, GPIO_PIN_18);
    }
    
    ~DynamicController() {
        GpioFactory::Destroy(motor_enable);
        PwmFactory::Destroy(motor_speed);
    }
};

// Static allocation (stack-based, deterministic memory)
class StaticController {
    HardwarePool hardware;  // All objects created in constructor
    
public:
    void Initialize() {
        // Objects already created in hardware pool constructor
        // Just configure them
        hardware.motor_enable->SetHigh();
        hardware.motor_pwm->SetDutyCycle(0);
    }
    
    void RunMotor(hf_u16_t speed) {
        hardware.motor_pwm->SetDutyCycle(speed);
        hf_u16_t current = hardware.current_adc->ReadRaw();
        Logger::GetInstance().LogInfo("Motor speed: %d%%, Current: %d", speed, current);
    }
    
    // Destructor automatically called, no manual cleanup needed
};

// Real-time system with pre-allocated pool
void RealTimeTask() {
    static StaticGpioFactory<8> gpio_pool;  // Max 8 GPIOs, stack allocated
    
    BaseGpio* led1 = gpio_pool.Create(GPIO_PIN_2, GPIO_OUTPUT);
    BaseGpio* led2 = gpio_pool.Create(GPIO_PIN_3, GPIO_OUTPUT);
    BaseGpio* button = gpio_pool.Create(GPIO_PIN_0, GPIO_INPUT);
    
    // No heap allocation, deterministic timing
    while(true) {
        if (button->Read() == GPIO_HIGH) {
            led1->SetHigh();
            led2->SetLow();
        } else {
            led1->SetLow();
            led2->SetHigh();
        }
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

Memory Allocation Benefits:

Allocation Type Use Case Benefits Trade-offs

|β€”β€”β€”β€”β€”β€”β€”|————–|————–|β€”β€”β€”β€”β€”-|

| Dynamic (Heap) | Flexible systems | Easy to use, unlimited objects | Runtime allocation, fragmentation |

| Static Pool | Known hardware count | Deterministic memory, no fragmentation | Fixed object count, more setup |

| Pre-allocated | Real-time systems | Constructor-based, automatic cleanup | Compile-time definition |

When to Use Each:

  • Dynamic: Prototyping, flexible configurations, plenty of RAM
  • Static Pool: Real-time systems, safety-critical applications
  • Pre-allocated: Known hardware layout, maximum determinism

C++23 Compatibility Note: The examples above use modern C++23 syntax with alignas() and std::byte arrays instead of the deprecated std::aligned_storage. As noted in P1413R3, std::aligned_storage is deprecated due to API issues and potential undefined behavior. The replacement pattern alignas(T) std::byte[sizeof(T)] provides the same functionality with better type safety and constexpr compatibility.

Advanced Factory Examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// PWM Factory with motor control optimization
class PwmFactory {
public:
    static BasePwm* CreateMotorControl(hf_u8_t channel, hf_u8_t gpio_pin) {
        // Automatically configures optimal settings for motor control
        // ESP32: 20kHz, 12-bit resolution
        // STM32: 20kHz, 16-bit resolution  
        // nRF: 20kHz, 10-bit resolution
    }
    
    static BasePwm* CreateServoControl(hf_u8_t channel, hf_u8_t gpio_pin) {
        // Automatically configures for servo control (50Hz, precise timing)
    }
};

// Communication Factory with bus management
class CommFactory {
public:
    static BaseI2c* CreateSensorBus(hf_u8_t bus_num) {
        // Optimized I2C settings for sensor communication
        // Handles MCU-specific pin assignments automatically
    }
    
    static BaseUart* CreateDebugPort() {
        // Creates standard debug UART on each MCU's debug pins
        // ESP32: UART0 on GPIO1/3
        // STM32: USART2 on PA2/PA3
        // nRF: UART0 on P0.06/P0.08
    }
};

πŸ”§ Building

Build System Features

  • Multi-MCU Support - Single build system for all platforms
  • Automated Testing - Comprehensive test suites
  • CI/CD Integration - Automated builds and validation

Build Commands

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
## Build specific application
./scripts/build_app.sh <app_name> <build_type> <target>

## Examples:
./scripts/build_app.sh gpio_test Debug esp32
./scripts/build_app.sh pwm_test Release esp32c6
./scripts/build_app.sh uart_test Debug esp32s3
```yaml

### **Configuration**
Applications are configured in `examples/esp32/app_config.yml`:
```yaml
applications:
  gpio_test:
    source_file: "GpioComprehensiveTest.cpp"
    description: "GPIO interface testing"
    enabled: true
    
  pwm_test:
    source_file: "PwmComprehensiveTest.cpp" 
    description: "PWM interface testing"
    enabled: true

πŸ“Š Examples

Available Test Applications

Application Tests Purpose

|—————–|———–|β€”β€”β€”β€”-|

gpio_test Digital I/O, interrupts GPIO interface validation
adc_test Multi-channel sampling ADC accuracy and performance
pwm_test Frequency/duty control Motor control applications
uart_test Serial communication Data transmission testing
i2c_test Sensor communication I2C bus operations
spi_test High-speed data SPI protocol testing
wifi_test Network connectivity WiFi stack validation
bluetooth_test Wireless pairing Bluetooth functionality

Factory Usage Examples

Basic Factory Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Simple GPIO control - works on any MCU
void BlinkLED() {
    BaseGpio* led = GpioFactory::Create(GPIO_PIN_2, GPIO_OUTPUT);
    
    while(true) {
        led->SetHigh();
        vTaskDelay(pdMS_TO_TICKS(500));
        led->SetLow(); 
        vTaskDelay(pdMS_TO_TICKS(500));
    }
    
    GpioFactory::Destroy(led);
}

// PWM motor control - MCU-optimized automatically
void ControlMotor() {
    BasePwm* motor = PwmFactory::CreateMotorControl(PWM_CH_0, GPIO_PIN_5);
    BaseAdc* current = AdcFactory::Create(ADC_CHANNEL_1);
    
    motor->SetDutyCycle(75);  // 75% speed
    hf_u16_t current_ma = current->ReadMillivolts() / 10;  // Convert to mA
    
    Logger::GetInstance().LogInfo("Motor current: %d mA", current_ma);
}

Multi-Peripheral Application

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
class HardFOCController {
    // Hardware interfaces - MCU agnostic
    BaseGpio* motor_enable;
    BaseGpio* fault_pin;
    BasePwm* motor_speed;
    BaseAdc* current_sensor;
    BaseAdc* voltage_sensor;
    BaseUart* debug_port;
    BaseI2c* sensor_bus;
    BaseWifi* telemetry;
    
public:
    hf_gpio_err_t Initialize() {
        // Factory creates MCU-specific implementations automatically
        motor_enable = GpioFactory::Create(MOTOR_EN_PIN, GPIO_OUTPUT);
        fault_pin = GpioFactory::CreateWithInterrupt(FAULT_PIN, fault_callback);
        motor_speed = PwmFactory::CreateMotorControl(PWM_CH_0, MOTOR_PWM_PIN);
        current_sensor = AdcFactory::Create(CURRENT_ADC_CH);
        voltage_sensor = AdcFactory::Create(VOLTAGE_ADC_CH);
        debug_port = CommFactory::CreateDebugPort();
        sensor_bus = CommFactory::CreateSensorBus(I2C_BUS_0);
        telemetry = WifiFactory::Create();
        
        // Validate all interfaces created successfully
        if (!motor_enable || !motor_speed || !current_sensor) {
            return hf_gpio_err_t::HARDWARE_ERROR;
        }
        
        debug_port->Printf("HardFOC Controller initialized on %s\n", MCU_NAME);
        return hf_gpio_err_t::SUCCESS;
    }
    
    void RunMotor(hf_u16_t speed_percent) {
        // Enable motor driver
        motor_enable->SetHigh();
        
        // Set motor speed
        motor_speed->SetDutyCycle(speed_percent);
        
        // Read diagnostics
        hf_u16_t current_ma = current_sensor->ReadMillivolts() / 10;
        hf_u16_t voltage_mv = voltage_sensor->ReadMillivolts();
        
        // Log locally
        debug_port->Printf("Speed: %d%%, Current: %dmA, Voltage: %dmV\n", 
                          speed_percent, current_ma, voltage_mv);
        
        // Send telemetry if connected
        if (telemetry && telemetry->IsConnected()) {
            telemetry->SendData("motor_speed", speed_percent);
            telemetry->SendData("motor_current", current_ma);
            telemetry->SendData("bus_voltage", voltage_mv);
        }
    }
    
    void EmergencyStop() {
        motor_enable->SetLow();
        motor_speed->SetDutyCycle(0);
        debug_port->Printf("EMERGENCY STOP - Motor disabled\n");
    }
    
    ~HardFOCController() {
        // Clean up all resources
        EmergencyStop();
        GpioFactory::Destroy(motor_enable);
        GpioFactory::Destroy(fault_pin);
        PwmFactory::Destroy(motor_speed);
        AdcFactory::Destroy(current_sensor);
        AdcFactory::Destroy(voltage_sensor);
        CommFactory::DestroyComm(debug_port);
        CommFactory::DestroyComm(sensor_bus);
        WifiFactory::Destroy(telemetry);
    }
};

// Same code compiles and runs on ESP32, STM32, nRF!
HardFOCController controller;
controller.Initialize();
controller.RunMotor(50);  // 50% speed

External Sensor Integration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Factories can create drivers for external chips too
class EnvironmentalMonitor {
    BaseTemperature* internal_temp;    // MCU internal sensor
    BaseTemperature* external_temp;    // DS18B20 external sensor
    BaseAdc* external_adc;             // MCP3208 external ADC
    
public:
    void Initialize() {
        // Internal MCU sensors
        internal_temp = SensorFactory::CreateInternalTemp();
        
        // External sensors using base interfaces
        BaseGpio* ds18b20_pin = GpioFactory::Create(GPIO_PIN_4, GPIO_INPUT_OUTPUT);
        external_temp = SensorFactory::CreateDS18B20(ds18b20_pin);
        
        BaseSpi* spi_bus = CommFactory::CreateSpi(SPI_BUS_1, 1000000);
        BaseGpio* cs_pin = GpioFactory::Create(GPIO_PIN_10, GPIO_OUTPUT);
        external_adc = SensorFactory::CreateMCP3208(spi_bus, cs_pin);
    }
    
    void ReadAllSensors() {
        float internal_celsius = internal_temp->ReadCelsius();
        float external_celsius = external_temp->ReadCelsius();
        hf_u16_t external_raw = external_adc->ReadRaw();
        
        Logger::GetInstance().LogInfo("Temps: Internal=%.1fΒ°C, External=%.1fΒ°C, ADC=%d", 
                                     internal_celsius, external_celsius, external_raw);
    }
};

🀝 Contributing

Development Workflow

  1. Fork the repository
  2. Create feature branch (feature/new-mcu-support)
  3. Implement following coding standards
  4. Test with existing applications
  5. Document your changes
  6. Submit pull request

Adding New Peripherals

  1. Create base interface in inc/base/BaseYourPeripheral.h
  2. Implement for ESP32 in inc/mcu/esp32/EspYourPeripheral.h
  3. Add comprehensive tests in examples/esp32/main/
  4. Update documentation

Coding Standards

  • Functions: CamelCase (SetDutyCycle, ReadValue)
  • Types: snake_case with *t suffix (hf_gpio_state_t)
  • Enums: snake_case enum class (hf_adc_err_t)
  • Logging: Use Logger::GetInstance() for all output

πŸ“„ License

This project is licensed under the GNU General Public License v3.0.

See LICENSE for full details.


Documentation

Development

  • πŸš€ Examples - Test applications and usage examples
  • πŸ§ͺ Test Documentation - Comprehensive test documentation
  • πŸ”§ Scripts - Build, flash, and development tools
  • πŸ“Š Configuration - Application and build settings

Community

  • 🀝 Contributing - Please refer to the HardFOC community for contribution guidelines

Built for the HardFOC ecosystem - Enabling seamless MCU portability

Hardware abstraction that just worksβ„’


πŸ“‹ Table of Contents