EMLIB to Peripheral HAL Migration Guide: Architectural Differences#
Core Philosophy#
EMLIB (Legacy Library)#
EMLIB was designed as a comprehensive, all-in-one solution that:
Combines multiple operations in single function calls
Handles clock management automatically within peripheral drivers
Includes initialization and enable in the
init()functionsProvides
deinit()functions for resource cleanupUses boolean enable parameters in init structures
Manages peripheral state implicitly
Design Principle: "Do everything you need in one function call - convenient but less flexible"
Example Pattern:
// EMLIB: Everything in one call
TIMER_Init_TypeDef timerInit = TIMER_INIT_DEFAULT;
timerInit.enable = true;
TIMER_Init(TIMER0, &timerInit); // Init AND enable AND startPeripheral HAL (Modern Library)#
Peripheral HAL follows a different philosophy:
Separates concerns into distinct, explicit operations
Delegates clock management to Clock Manager
Splits initialization and enable into separate functions
No
deinit()functions - use explicit resetExplicit operation control instead of boolean flags
Design Principle: "Each function does one thing well - explicit control over every aspect"
Example Pattern:
// Peripheral HAL: Explicit steps
sl_hal_timer_init_t init = SL_HAL_TIMER_INIT_DEFAULT;
sl_hal_timer_init(TIMER0, &init); // Initialize only
sl_hal_timer_enable(TIMER0); // Explicit enable
sl_hal_timer_start(TIMER0); // Explicit startMajor Architectural Changes#
Synchronous vs. Asynchronous API#
EMLIB Approach (Synchronous): EMLIB functions perform multiple operations in a tightly coupled, synchronous manner:
Operations are bundled together and must be done back-to-back
No ability to decouple steps or perform custom activities between them
init()functions automatically configure, enable, and start operationsClock management, peripheral enable, and operation start happen together
Example:
// EMLIB: All operations happen synchronously in one call
TIMER_Init_TypeDef timerInit = TIMER_INIT_DEFAULT;
timerInit.enable = true;
TIMER_Init(TIMER0, &timerInit); // Configure, enable, and start - all coupledPeripheral HAL Approach (Asynchronous): Each operation is decoupled, allowing for asynchronous sequencing:
Operations can be separated with custom code in between
Provides flexibility to perform activities between driver calls
init()configures but doesn't enableenable()enables peripheral module (can be called later)start()or specific operation functions begin operations (independent step)
Example:
// Peripheral HAL: Operations are decoupled - asynchronous approach
sl_hal_timer_init(TIMER0, &init); // Step 1: Configure
// Additionnal configuration in WSTATIC registers is possible
sl_hal_timer_enable(TIMER0); // Step 2: Enable (decoupled from init)
// More custom activities possible
sl_hal_timer_start(TIMER0); // Step 3: Start (decoupled from enable)Migration Impact:
Must call
sl_hal_*_enable()after theinit()function
No Clock Management in Drivers#
EMLIB:
// EMLIB handles clock automatically
LDMA_Init(&init); // CMU clock enabled internallyPeripheral HAL:
// Must enable clock explicitly first
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_LDMA0);
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_LDMAXBAR0);
sl_hal_ldma_init(LDMA0, &init);Rationale:
Decouples clock management from peripheral drivers
Allows centralized clock control
Makes clock requirements explicit
Clock management was inconsistent in EMLIB. Not all peripheral was managing the bus clock automatically
Migration Impact:
Must call
sl_clock_manager_enable_bus_clock()explicitly before theinit()function
No Deinit() Functions#
EMLIB:
LDMA_Init(&init); // Initialize
// ... use ldma ...
LDMA_DeInit(); // Cleanup/resetPeripheral HAL:
sl_hal_ldma_init(LDMA0, &init); // Initialize
// ... use ldma ...
sl_hal_ldma_reset(LDMA0); // Explicit reset of the hardware moduleRationale:
Deinitialization is not necessary for a low-level driver with no internal state
EMLIB had inconsistent naming
DeInit()andReset()