Implementing Real-Time Clock Interfaces in HarmonyOS Hardware Drivers

Core Functionality

The Real-Time Clock (RTC) module serves as the temporal backbone for embedded operating systems. It maintains accurate system time and supports scheduled alarm events. Leveraging an external backup power source, the RTC preserves timekeeping operations during system shutdowns. Upon power restoration, it synchronizes the OS clock, guaranteeing temporal continuity across reboot cycles.

Architectural Model within the HDF Framework

Within the Hardware Driver Foundation (HDF), RTC peripherals operate under a standalone service paradigm. Unlike aggregated service models, each hardware instance independently registers its own service endpoint. The device manager routes incoming API calls by parsing request parameters and dispatching them to the corresponding hardware abstraction methods. While this approach requires individual device node configurations and may increase memory overhead for mass-deployed peripherals, its highly efficient for RTC implementations, as typical embedded platforms host only a single timekeeping controller.

Configuring this mode requires drivers to implement the Bind hook inside HdfDriverEntry. Additionally, the policy attribute in device_info.hcs must be set to either 1 or 2, as value 0 disables standalone registration.

The driver architecture is stratified into three primary layers:

  • Interface Layer: Exposes functions for device initialization, time synchronization, alarm configuration, interrupt masking, crystal frequency management, register I/O, and termination.
  • Core Layer: Manages controller lifecycle operations and facilitates cross-layer communication via callback hooks.
  • Adaptation Layer: Translates abstract hook definitions into hardware-specific register operations and platform-dependent logic.

API Specification & Integration Workflow

The framework exposes a standardized set of functions located in //drivers/hdf_core/framework/include/platform/rtc_if.h. Below is a summary of the primary operations:

Function Signature Purpose
DevHandle RtcOpen(void) Retrieves an active controller handle for the RTC peripheral.
void RtcClose(DevHandle handle) Releases system resources associated with the controller handle.
int32_t RtcReadTime(DevHandle handle, struct RtcTime *time) Fetches the current timestamp maintained by the hardware.
int32_t RtcWriteTime(DevHandle handle, const struct RtcTime *time) Programs the hardware clock with new date and time values (year through milliseconds).
int32_t RtcReadAlarm(DevHandle handle, enum RtcAlarmIndex alarmIndex, struct RtcTime *time) Queries the configured threshold for a specific alarm channel.
int32_t RtcWriteAlarm(DevHandle handle, enum RtcAlarmIndex alarmIndex, const struct RtcTime *time) Sets the trigger threshold for a designated alarm channel.
int32_t RtcRegisterAlarmCallback(DevHandle handle, enum RtcAlarmIndex alarmIndex, RtcAlarmCallback cb) Binds an asynchronous handler to execute upon alarm expiration.
int32_t RtcAlarmInterruptEnable(DevHandle handle, enum RtcAlarmIndex alarmIndex, uint8_t enable) Toggles the interrupt line for a specific alarm channel.
int32_t RtcGetFreq(DevHandle handle, uint32_t *freq) Reads the current oscillator frequency configuration.
int32_t RtcSetFreq(DevHandle handle, uint32_t freq) Updates the external crystal oscillator frequency parameters.
int32_t RtcReset(DevHandle handle) Performs a hardware-level reset of the RTC subsystem.
int32_t RtcReadReg(DevHandle handle, uint8_t usrDefIndex, uint8_t *value) Reads raw data from a vendor-specific register.
int32_t RtcWriteReg(DevHandle handle, uint8_t usrDefIndex, uint8_t value) Writes raw data to a vendor-specific register.

Acquiring the Controller Instance

Once the driver stack initializes, applications or kernel modules can request a communication handle using the framework's discovery mechanism. Note that the current platform iteration restricts RTC support to a single active peripheral. The following snippet demonstrates proper handle acquisition and error handling:

DevHandle rtc_ctrl = NULL;

// Initialize driver context by requesting the service
rtc_ctrl = RtcOpen();
if (!rtc_ctrl) {
    HDF_LOGE("Failed to acquire RTC controller instance");
    return HDF_FAILURE;
}

Configuring Alarm Interrupts & Callbacks

To react to scheduled timeouts, developers must bind a handler function to a specific alarm channel. This function executes asynchronously when the hardware timer expires. The registration process requires passing the device handle, the target channel identifier, and a function pointer matching the callback signature.

The following example demonstrates a robust callback implementation that safely routes execution based on the trigger source:

static int32_t ProcessRtcTimeoutNotification(enum RtcAlarmIndex trigger_source)
{
    if (trigger_source == RTC_ALARM_INDEX_A) {
        HDF_LOGI("Alarm channel A triggered. Executing timeout routine.");
        // Insert hardware-specific handling logic here
    } else if (trigger_source == RTC_ALARM_INDEX_B) {
        HDF_LOGI("Alarm channel B triggered. Processing secondary alert.");
    } else {
        HDF_LOGW("Unexpected alarm index received: %d", trigger_source);
        return HDF_ERR_INVALID_PARAM;
    }
    return HDF_SUCCESS;
}

// Registration routine
int32_t InitializeAlarmHandler(DevHandle device_ptr)
{
    int32_t status = RtcRegisterAlarmCallback(device_ptr, RTC_ALARM_INDEX_A, ProcessRtcTimeoutNotification);
    if (status != HDF_SUCCESS) {
        HDF_LOGE("Callback registration failed with code: %d", status);
        return status;
    }
    
    // Enable the corresponding interrupt line
    status = RtcAlarmInterruptEnable(device_ptr, RTC_ALARM_INDEX_A, 1);
    return status;
}

Tags: HarmonyOS HDF Real-Time Clock device driver Embedded Systems

Posted on Sun, 20 Sep 2026 16:06:53 +0000 by jevman