# Proxy MCAL: Universal Abstraction Layer for Microcontrollers
Proxy MCAL solves the problem of tying the application to a specific vendor's HAL. When migrating firmware to a new microcontroller, the standard HAL requires a complete rewrite of GPIO, SPI, UART, and other peripheral drivers. Proxy MCAL provides a single API implemented through binding functions for each MCU family. This preserves code portability without rewriting the application logic.
Developers face migration due to chip obsolescence, supply shortages, sanctions, or new requirements like Bluetooth 5.3. Proxy MCAL ensures modularity compliant with ISO-26262: abstract architecture, configurability, testability.
Requirements for Proxy MCAL
Proxy MCAL must meet strict criteria for middle/senior-level developers:
- Completeness: getters/setters for all peripherals (CLOCK, GPIO, I2C, SPI, UART, ADC, DMA). Unused functions are weak, so the linker discards them.
- Acceptance: common API agreed upon by the team.
- Simplicity: 45–55 lines of prototypes, intuitive interface, documentation via grep on module tests.
- Scalability: multiple instances of components.
- Versatility: support for ASIC drivers, protocols, RTOS.
- Portability: builds on PC with empty weak stubs.
- CLI Access: function verification via UART at runtime.
- Testability: module tests as documentation.
- Configurability: separate configs as arrays of structures.
Binding Function Examples
Single API gpio_logic_level_set(Pad_t pad, GpioLogicLevel_t logic_level) implemented differently:
For STM32:
bool gpio_logic_level_set(Pad_t pad, GpioLogicLevel_t logic_level) {
HAL_GPIO_WritePin(Port2PortPtr(pad.port), 1 << pad.pin, (GPIO_PinState)logic_level);
return true;
}
For NRF5340:
bool gpio_logic_level_set(Pad_t Pad, GpioLogicLevel_t logic_level) {
bool res = false;
res = gpio_is_valid_pad(Pad);
if(res) {
nrf_gpio_pin_write((uint32_t)Pad.byte, (uint32_t)logic_level);
}
return res;
}
For Artery AT32 (ISR-safe):
bool gpio_logic_level_set(Pad_t Pad, GpioLogicLevel_t logic_level) {
Pad_t pad = {0};
(void)pad;
pad.byte = pad_num;
gpio_type* GPIOx = Port2PortPtr(Pad.port);
if(GPIOx) {
switch((uint8_t)logic_level) {
case GPIO_LVL_HI: {
GPIOx->scr = 1 << Pad.pin;
} break;
case GPIO_LVL_LOW: {
GPIOx->clr = 1 << Pad.pin;
} break;
}
}
return true;
}
Prototypes are fixed, bodies adapted to vendor HAL or registers.
Benefits of Implementation
- Portability: Proxy MCAL application compiles for any MCU via bindings.
- Testing: unified module tests verify any HAL.
- CLI Interface: centralized peripheral management.
- ASIC Drivers: universal for SPI/I2C devices across all platforms.
Drawbacks and Mitigations
Overhead — 10–20 cycles per call. Solution: inline functions. Risk of spaghetti code minimized by API simplicity and loose coupling.
Key Points
- Proxy MCAL separates the application from vendor HAL, simplifying migration to new MCUs.
- Single API with bindings ensures completeness and portability.
- Compliant with ISO-26262: modularity, testability, configurability.
- Supports CLI and module tests for runtime verification.
- Scales to 16+ MCU families without rewriting the application.
— Editorial Team
No comments yet.