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() functions

  • Provides deinit() functions for resource cleanup

  • Uses 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 start

Peripheral 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 reset

  • Explicit 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 start

Major 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 operations

  • Clock 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 coupled

Peripheral 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 enable

  • enable() 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 the init() function

No Clock Management in Drivers#

EMLIB:

// EMLIB handles clock automatically
LDMA_Init(&init);  // CMU clock enabled internally

Peripheral 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 the init() function

No Deinit() Functions#

EMLIB:

LDMA_Init(&init);    // Initialize
// ... use ldma ...
LDMA_DeInit();       // Cleanup/reset

Peripheral HAL:

sl_hal_ldma_init(LDMA0, &init);   // Initialize
// ... use ldma ...
sl_hal_ldma_reset(LDMA0);         // Explicit reset of the hardware module

Rationale:

  • Deinitialization is not necessary for a low-level driver with no internal state

  • EMLIB had inconsistent naming DeInit() and Reset()