23 极物科技 | DALI协议栈 - EEPROM持久化机制

极物科技 | DALI协议栈 - EEPROM持久化机制

前言

在智能控制领域,"协议壁垒"与"系统稳定性"始终是绕不开的难题。极物科技(Zeewo)以 "重构空间交互体验" 为使命,通过自研的 极物 OS,实现了 KNX、DALI、CAN、RS485 等多种总线协议在单一主机上的深度融合。

我们认为,一个真正优秀的智能系统,不仅要实现灯光、遮阳、温控、音乐、安防等全生态设备的无界融合 ,更要确保本地运行、断网可用 ,并具备WEB 远程调试OTA 固件升级的能力。基于此底层架构,我们推出了诸如带双路 DALI 的 KNX 主机、HomeKit 网桥等核心硬件,并将极物 OS 成功接入了 Apple HomeKit、小度、纯血鸿蒙及 HomeAssistant 等主流生态系统。

一句话概述:本文深入解析极物 DALI 协议栈 EEPROM 持久化机制,展示配置数据从 RAM 到 EEPROM 的完整保存与加载流程。

本文聚焦于 DALI 设备配置数据的持久化存储,涵盖数据加载、差异写入、更新标志管理(VAR_UPDATE/BANK0_UPDATE/BANK1_UPDATE)、数据校验、断电恢复等核心内容。通过源码级剖析,帮助读者理解 DALI 从设备如何实现可靠的非易失性数据存储。


1. EEPROM持久化概述

在DALI智能照明系统中,设备断电后需要保留关键配置信息(如短地址、分组、场景值、色温参数等),EEPROM(Electrically Erasable Programmable Read-Only Memory)是实现数据持久化的核心组件。

1.1 需要持久化的数据

根据DALI标准,以下数据必须保存到非易失性存储器:

数据类型 字段 说明
设备地址 short_address 0-63短地址或0xFF未寻址
分组信息 group_0_7, group_8_15 16个分组归属
场景值 scene[0-15] 16个场景亮度值
系统参数 power_on_level 上电亮度
系统参数 system_failure_level 故障亮度
系统参数 minimum_level 最小亮度
系统参数 maximum_level 最大亮度
渐变参数 fade_rate 渐变率
渐变参数 fade_time 渐变时间
DT8参数 tc_scene[0-15] 16个场景色温值
DT8参数 tc_powon_level 上电色温
DT8参数 tc_config_maxcold_level 配置最冷色温
DT8参数 tc_config_maxwarn_level 配置最暖色温

1.2 EEPROM模块接口

c 复制代码
// dali_eeprom.h - EEPROM模块接口
bool dali_load_from_eeprom(void);           // 从EEPROM加载数据
void dali_update_to_eeprom(void);           // 更新数据到EEPROM
void dali_eeprom_update_tick(void);         // 触发更新
void dali_eeprom_init(void);                // EEPROM初始化

二、数据加载机制

2.1 dali_load_from_eeprom

系统启动时从EEPROM加载持久化数据到RAM:

c 复制代码
// dali_eeprom.c - 从EEPROM加载数据
bool dali_load_from_eeprom()
{
    int i;
    uint8_t flag[2];
    uint8_t errom_data;

    // 1. 获取DALI数据区大小和地址
    g_dali_data_size = dali_get_data_size_from_stack();
    g_dali_data_P = dali_get_data_addr_from_stack();

    // 2. 检查EEPROM数据状态
    if (eeprom_get_data_status() != 1) {
        // printf("get eprom data error \r\n");
        return false;
    }

    // 3. 从EEPROM读取数据到RAM
    // 跳过DALI_DATA_NO_SAVE_INDEX+1之前的字节(不保存的数据)
    for (i = DALI_DATA_NO_SAVE_INDEX + 1; i < g_dali_data_size; i++) {
        *(g_dali_data_P + i) = eeprom_read_cache(i);
        // printf("i %hx data %bx \r\n", i, *(g_dali_data_P + i));
    }

    return true;
}

2.2 数据区结构

c 复制代码
// dali_top.h - 更新标志位定义
#define VAR_UPDATE   (1 << 0)  // DALI变量更新
#define BANK0_UPDATE (1 << 1)  // Bank0更新
#define BANK1_UPDATE (1 << 2)  // Bank1更新

数据区布局

复制代码
+------------------+------------------+------------------+
| 不保存的数据区   |  Bank0数据区     |  Bank1数据区     |
| (target_level等) | (场景/分组等)    | (设备类型等)     |
+------------------+------------------+------------------+
  DALI_DATA_NO_SAVE_INDEX+1之前        需要持久化的数据

2.3 不保存的数据

部分运行时数据不需要保存到EEPROM:

c 复制代码
// dali_cmd.h - 不保存数据索引
#define DALI_DATA_NO_SAVE_INDEX 1

struct var {
    /* 以下数据不需要保存 */
    uint8_t target_level;      // 目标亮度(运行时)
    uint8_t tc_target_level;   // 目标色温(运行时)
    uint8_t data_check_1;      // 校验位
    
    /* 以下数据需要保存 */
    uint8_t power_on_level;    // 上电亮度
    uint8_t system_failure_level;  // 故障亮度
    // ... 其他持久化数据
};

三、数据更新机制

3.1 dali_update_to_eeprom

将RAM中的变更数据写回EEPROM:

c 复制代码
// dali_eeprom.c - 更新数据到EEPROM
void dali_update_to_eeprom()
{
    uint8_t i = 0;
    uint8_t errom_data;
    uint8_t count = 0;

    // 1. 检查是否有更新标志
    if (update_flag == 0) {
        return;  // 无更新,直接返回
    }

    printf("update_flag \r\n");
    
    // 2. 逐字节比对并写入变更数据
    for (i = DALI_DATA_NO_SAVE_INDEX + 1; i < g_dali_data_size; i++) {
        // 头两个字节不保存
        errom_data = eeprom_read_cache(i);
        if (*(g_dali_data_P + i) != errom_data) {
            eeprom_write_cache(i, *(g_dali_data_P + i));
        }
    }
    
    // 3. 标记写入成功
    eeprom_data_is_write_sucess();
    
    // 4. 清除更新标志
    update_flag = 0;
    return;
}

3.2 更新触发时机

以下操作会设置update_flag触发EEPROM写入:

操作 设置的标志 说明
设置短地址 BANK0_UPDATE 地址分配完成
设置分组 BANK0_UPDATE 分组配置变更
设置场景 BANK0_UPDATE 场景值变更
RESET命令 `BANK0_UPDATE BANK1_UPDATE`
配置参数变更 VAR_UPDATE 亮度/色温等参数变更

示例

c 复制代码
// dali_cmd.c - SET SHORT ADDRESS命令
case PROGRAM_SHORT_ADDRESS:
    if (repeat_flag == false) {
        return RECEIVE_FIRST;
    }
    dali_ram.variable.short_address = dtr0;
    update_flag |= BANK0_UPDATE;  // 触发EEPROM更新
    break;

// dali_cmd.c - SET SCENE命令
case STORE_DTR0_AS_SCENE0:
    // ...
    dali_ram.variable.scene[scene_index] = dtr0;
    update_flag |= BANK0_UPDATE;  // 触发EEPROM更新
    break;

3.3 dali_eeprom_update_tick

立即触发EEPROM更新的接口:

c 复制代码
// dali_eeprom.c - 触发EEPROM更新
void dali_eeprom_update_tick(void)
{
    dali_update_to_eeprom();
    return;
}

调用场景

c 复制代码
// dali_hal.c - HAL层保存持久化变量
void dali_hal_save_persistent_variables(void)
{
    /* Execute update immediately */
    dali_eeprom_update_tick();
}

四、EEPROM初始化

4.1 初始化标志

c 复制代码
// dali_eeprom.h - EEPROM初始化成功标志
#define EEROM_DATA_INIT_SUCESS_DATA_1 0X55
#define EEROM_DATA_INIT_SUCESS_DATA_2 0XAA

4.2 初始化流程

c 复制代码
// dali_eeprom.c - EEPROM初始化
void dali_eeprom_init()
{
    // 1. 检查EEPROM是否已初始化
    if (eeprom_get_data_status() != 1) {
        // 2. 未初始化,执行初始化
        eeprom_init();
        
        // 3. 写入初始化成功标志
        eeprom_write_cache(0, EEROM_DATA_INIT_SUCESS_DATA_1);
        eeprom_write_cache(1, EEROM_DATA_INIT_SUCESS_DATA_2);
        
        // 4. 标记写入成功
        eeprom_data_is_write_sucess();
    }
}

五、目标亮度特殊处理

5.1 读取目标亮度

c 复制代码
// dali_eeprom.c - 从EEPROM读取目标亮度
uint8_t dali_read_target_level_from_eeprom(void)
{
    // printf("\n");
    return 1;
}

5.2 写入目标亮度

c 复制代码
// dali_eeprom.c - 写入目标亮度到EEPROM
void dali_write_target_level_to_eeprom(uint8_t level)
{
    // printf("\n");
    return;
}

说明:这两个函数当前为占位实现,实际项目中可根据需求扩展。


六、数据校验机制

6.1 启动时校验

系统启动时检查EEPROM数据有效性:

c 复制代码
// dali_eeprom.c - 加载数据时校验
bool dali_load_from_eeprom()
{
    // 检查EEPROM数据状态
    if (eeprom_get_data_status() != 1) {
        return false;
    }
    
    // 加载数据...
    return true;
}

6.2 写入时校验

写入完成后验证数据正确性:

c 复制代码
// dali_eeprom.c - 更新数据后校验
void dali_update_to_eeprom()
{
    // 写入数据...
    
    // 标记写入成功(内部包含校验逻辑)
    eeprom_data_is_write_sucess();
    
    update_flag = 0;
}

七、EEPROM写入优化

7.1 差异写入

只写入变更的字节,减少EEPROM写入次数:

c 复制代码
// dali_eeprom.c - 差异写入
for (i = DALI_DATA_NO_SAVE_INDEX + 1; i < g_dali_data_size; i++) {
    errom_data = eeprom_read_cache(i);
    if (*(g_dali_data_P + i) != errom_data) {
        eeprom_write_cache(i, *(g_dali_data_P + i));
    }
}

优势

  • 减少EEPROM写入次数,延长寿命
  • 提高写入效率
  • 降低功耗

7.2 批量写入

多个更新标志合并为一次写入:

c 复制代码
// 多个操作触发更新
update_flag |= VAR_UPDATE;      // 参数变更
update_flag |= BANK0_UPDATE;    // Bank0变更

// 统一触发一次写入
dali_eeprom_update_tick();

八、数据持久化流程

8.1 完整流程图

复制代码
系统启动
  ↓
EEPROM初始化检查
  ↓
dali_load_from_eeprom()
  ↓
检查EEPROM数据状态
  ↓
读取数据到RAM(跳过不保存区)
  ↓
数据校验
  ↓
dali_cmd_init() 初始化命令状态
  ↓
dali_cmd_init_check() 校验配置参数
  ↓
系统正常运行
  ↓
配置变更触发update_flag
  ↓
dali_eeprom_update_tick()
  ↓
dali_update_to_eeprom()
  ↓
差异比对,只写入变更字节
  ↓
eeprom_data_is_write_sucess()
  ↓
清除update_flag

8.2 断电恢复流程

复制代码
设备上电
  ↓
EEPROM初始化
  ↓
dali_load_from_eeprom()
  ↓
恢复short_address
  ↓
恢复group_0_7, group_8_15
  ↓
恢复scene[0-15]
  ↓
恢复tc_scene[0-15]
  ↓
恢复power_on_level
  ↓
恢复system_failure_level
  ↓
恢复fade_rate, fade_time
  ↓
设备恢复到断电前状态

九、关键设计亮点

9.1 分层数据管理

复制代码
+------------------+
|  运行时数据区    |  ← 不保存到EEPROM
| (target_level)   |
+------------------+
|  Bank0数据区     |  ← 保存到EEPROM
| (场景/分组/地址) |
+------------------+
|  Bank1数据区     |  ← 保存到EEPROM
| (设备类型/版本)  |
+------------------+

9.2 标志位驱动更新

c 复制代码
// 更新标志位
#define VAR_UPDATE   (1 << 0)  // 变量更新
#define BANK0_UPDATE (1 << 1)  // Bank0更新
#define BANK1_UPDATE (1 << 2)  // Bank1更新

// 设置更新标志
update_flag |= VAR_UPDATE;

// 检查并执行更新
if (update_flag != 0) {
    dali_update_to_eeprom();
}

9.3 差异写入优化

c 复制代码
// 只写入变更的字节
if (*(g_dali_data_P + i) != errom_data) {
    eeprom_write_cache(i, *(g_dali_data_P + i));
}

9.4 立即更新接口

c 复制代码
// HAL层提供立即更新接口
void dali_hal_save_persistent_variables(void)
{
    dali_eeprom_update_tick();
}

十、应用场景

10.1 设备地址持久化

设备通过DALI总线分配短地址后,必须保存到EEPROM:

c 复制代码
case PROGRAM_SHORT_ADDRESS:
    if (repeat_flag == false) {
        return RECEIVE_FIRST;
    }
    dali_ram.variable.short_address = dtr0;
    update_flag |= BANK0_UPDATE;  // 触发EEPROM更新
    break;

10.2 场景值持久化

用户配置的场景值需要断电保存:

c 复制代码
case STORE_DTR0_AS_SCENE0:
    dali_ram.variable.scene[0] = dtr0;
    update_flag |= BANK0_UPDATE;  // 触发EEPROM更新
    break;

10.3 DT8色温参数持久化

双色温设备的色温范围配置需要保存:

c 复制代码
case SET_TC_MAX_COLD:
    dali_ram.variable.tc_config_maxcold_level = dtr0;
    update_flag |= VAR_UPDATE;  // 触发EEPROM更新
    break;

11. 总结

本文详细解析了DALI协议栈中EEPROM持久化机制的实现,涵盖:

  • 数据加载机制:系统启动时从EEPROM加载数据到RAM
  • 数据更新机制:运行时变更数据写回EEPROM
  • 差异写入优化:只写入变更字节,延长EEPROM寿命
  • 标志位驱动:VAR_UPDATE/BANK0_UPDATE/BANK1_UPDATE分层管理
  • 数据校验:确保数据完整性和正确性
  • 立即更新接口:HAL层提供dali_eeprom_update_tick()

通过本文的解析,读者可以深入理解DALI设备数据持久化的完整实现,为智能照明系统的开发提供技术参考。


关于极物科技(ZEEWO)

极物科技(Zeewo)致力于为用户提供智能控制系统及硬件产品。我们以总线系统为技术底座,以**"稳定、可靠、快速响应"**为产品底线,是国内少有的拥有 KNX、DALI 全套软硬件自主研发能力的厂商之一。

我们的核心能力:

  • 系统架构:自研极物 OS,支持多协议无界融合(KNX/DALI/CAN/RS485/IP)。
  • 核心硬件:带双路 DALI 的 KNX 主机、超薄全金属定制面板、各类智选传感器及网关。
  • 生态互联:深度融入 Apple HomeKit、Matter、小度、HomeAssistant 及纯血鸿蒙生态。
  • 调试交付:独家支持 ETS 导出 XML 直接导入进行 APP 免编程调试,支持远程 WEB 运维。

我们的市场覆盖:

服务网点已覆盖全国核心城市(含长三角、珠三角、成渝等),并以高品质的方案深耕家居生活、酒店民宿、企业办公、疗愈康养、餐馆会所等多个细分领域。

(如果您在开发或落地中遇到技术问题,欢迎通过官网或后台私信与我交流探讨)

相关推荐
阿钱真强道1 天前
20 极物科技 | DALI协议栈 - 配置命令详解
智能照明·极物·极物智能·极物科技·iec 62386·dali协议栈·场景配置
阿钱真强道1 天前
22 极物科技 | DALI协议栈 - 特殊命令与设备发现机制
极物·极物智能·极物科技·iec 62386·设备发现·dali协议栈·智慧照明
阿钱真强道2 天前
19 极物科技 | DALI协议栈 - 标准命令集解析
极物·极物智能·极物科技·iec 62386·调光控制·dali协议栈·标准命令
阿钱真强道2 天前
17 极物科技 | DALI协议栈 - 物理层位编解码详解
曼彻斯特编码·极物·极物智能·极物科技·iec 62386·dali协议栈
阿钱真强道3 天前
16 极物科技 | DALI协议栈 - 架构总览与模块设计
智能家居·照明·极物·极物智能·极物科技·iec 62386·dali协议栈
阿钱真强道5 天前
11 极物科技 | DALI调光灯 - 功能接口与调试指南
智能照明·极物·极物智能·极物科技·dali调光灯·调光控制·调试指南
阿钱真强道5 天前
12 极物科技 | DALI调光灯 - 设备发现与地址分配机制
智能照明·极物·极物智能·极物科技·dali调光灯·设备发现·地址分配
阿钱真强道6 天前
09 极物科技 | DALI调光灯 - IEC 62386 底层协议解析
智能照明·总线协议·极物·极物智能·极物科技·dali调光灯·iec 62386
阿钱真强道7 天前
07 极物科技 | DALI调光灯 - 快速接入指南
智能照明·极物·极物智能·极物科技·dali调光灯·iec 62386·调光控制