数字可寻址照明接口(DALI)总线驱动
DALI 组件提供了基于 ESP-IDF 的 DALI(IEC 62386)主站驱动。 该驱动使用 ESP 的 RMT 外设实现 前向帧 发送与 后向帧 解码,便于应用直接控制和查询 DALI 控制设备。
功能特性
支持目标
组件元数据当前支持以下 ESP32 系列芯片:
ESP32
ESP32-S2
ESP32-S3
ESP32-C3
ESP32-C6
ESP32-P4
ESP32-H2
快速开始
包含头文件:
#include "dali.h" #include "dali_command.h"
初始化驱动:
dali_master_handle_t dali; dali_master_config_t cfg = { .rx_gpio = GPIO_NUM_4, .tx_gpio = GPIO_NUM_5, .invert_tx = false, .invert_rx = false, }; dali_master_rmt_config_t rmt_cfg = { .mem_block_symbols = 64, }; ESP_ERROR_CHECK(dali_new_master_rmt(&cfg, &rmt_cfg, &dali));
发送命令(不期望后向帧):
/* 驱动在每次事务后自动插入最小帧间隔 (> 22 Te),无需手动延时 */ dali_master_transaction_config_t tx_cfg = { .addr_type = DALI_ADDR_SHORT, .addr = 0, .is_cmd = true, .command = DALI_CMD_RECALL_MAX_LEVEL, .send_twice = false, .tx_timeout_ms = DALI_TX_TIMEOUT_MS, }; ESP_ERROR_CHECK(dali_master_do_transaction(dali, &tx_cfg, NULL));
发送查询(期望后向帧):
int reply = DALI_RESULT_NO_REPLY; dali_master_transaction_config_t tx_cfg = { .addr_type = DALI_ADDR_SHORT, .addr = 0, .is_cmd = true, .command = DALI_CMD_QUERY_STATUS, .send_twice = false, .tx_timeout_ms = DALI_TX_TIMEOUT_MS, }; ESP_ERROR_CHECK(dali_master_do_transaction(dali, &tx_cfg, &reply)); if (DALI_RESULT_IS_VALID(reply)) { ESP_LOGI("dali", "QUERY_STATUS = 0x%02X", (unsigned)reply); }
配置项
DALI 驱动的全部配置均通过两个结构体在运行时完成,无需 Kconfig 选项:
dali_master_config_t— GPIO 引脚分配(rx_gpio、tx_gpio)和信号极性反相(invert_tx、invert_rx)。dali_master_rmt_config_t— RMT 后端专用设置,如内存块大小。
dali_master_config_t cfg = {
.rx_gpio = GPIO_NUM_4,
.tx_gpio = GPIO_NUM_5,
.invert_tx = false, /* 默认不启用 TX 硬件链路奇数次反相 */
.invert_rx = false, /* 默认不启用 RX 硬件链路奇数次反相 */
};
dali_master_rmt_config_t rmt_cfg = {
.mem_block_symbols = 0, /* 0 = 根据 SOC 能力自动检测 */
};
ESP_ERROR_CHECK(dali_new_master_rmt(&cfg, &rmt_cfg, &dali));
命令模型
统一通过 dali_master_do_transaction() 完成不同类型事务。
通过 dali_master_transaction_config_t 描述事务参数:
DAPC 直控:
config.is_cmd = false,config.command为亮度值。普通命令/查询:
config.is_cmd = true,config.command来自dali_command.h。需要双发的命令:设置
config.send_twice = true。查询命令:传入
result != NULL,并用DALI_RESULT_IS_VALID(*result)判断是否收到有效回复。dali_master_do_transaction()每次调用后自动插入所需帧间隔 (> 22 Te), 无需在连续调用间手动延时。
时序说明
DALI 对帧间隔与后向帧响应窗口有严格约束。
驱动在每次
dali_master_do_transaction()调用后自动插入最小帧间隔 (> 22 Te), 满足 IEC 62386 时序要求。dali_master_do_transaction()为阻塞调用 — 请勿在 ISR 或对实时性要求极高的任务中调用。
示例与测试
示例工程:lighting/dali_basic
组件测试:
components/dali/test_apps/main/dali_test.c
示例覆盖内容包括:
DAPC 调光序列
普通命令发送
查询命令与回复解析
send-twice 配置命令流程
API 参考
Header File
Functions
-
esp_err_t dali_new_master_rmt(const dali_master_config_t *config, const dali_master_rmt_config_t *rmt_config, dali_master_handle_t *handle)
Create and initialize a new DALI driver instance backed by RMT.
Allocates a driver context, configures the RMT TX channel on
config->tx_gpioand the RMT RX channel onconfig->rx_gpio, and returns an opaque handle. Multiple independent instances can be created on different GPIO pairs.The naming convention follows the pattern
dali_new_bus_<backend>so that future backends (e.g.dali_new_bus_uart) can coexist without naming conflicts.- 参数
config – [in] Pointer to bus configuration (GPIO numbers).
rmt_config – [in] Pointer to RMT-specific configuration. Pass NULL to use built-in defaults (mem_block_symbols=64).
handle – [out] Pointer to store the created handle on success.
- 返回
ESP_OK on success;
*handleis validESP_ERR_INVALID_ARG if
configorhandleis NULL, or GPIO numbers are invalidESP_ERR_NO_MEM if heap allocation fails
Other ESP_ERR codes propagated from RMT driver
-
esp_err_t dali_del_master(dali_master_handle_t handle)
De-initialize a DALI driver instance and release all resources.
Disables and deletes the RMT channels, encoder, and RX queue associated with
handle, then frees the context memory. The handle is invalid after this call.Safe to call even if dali_new_master_rmt only partially succeeded (e.g. during error recovery).
- 参数
handle – [in] Handle returned by dali_new_master_rmt.
- 返回
ESP_OK always.
-
esp_err_t dali_master_do_transaction(dali_master_handle_t handle, const dali_master_transaction_config_t *config, int *result)
Execute a DALI transaction (forward frame, optional backward frame).
Transmits a 16-bit DALI forward frame composed of an address byte and a command/data byte, then optionally listens for an 8-bit backward frame. After the transaction completes the driver automatically inserts the minimum inter-frame gap required by IEC 62386 (> 22 Te ≈ 9.2 ms), so callers do not need to add an explicit delay between consecutive calls.
Address byte construction:
config->addr_type
First byte format
DALI_ADDR_SHORT
0AAAAAAS(A = 0–63)DALI_ADDR_GROUP
100AAAAS(A = 0–15)DALI_ADDR_BROADCAST
1111111SDALI_ADDR_SPECIAL
config->addr passed through
The S (selector) bit is set to 1 when config->is_cmd is
true(indirect command), or 0 whenfalse(direct arc-power control, DAPC).Send-twice commands: Certain configuration commands (e.g., RESET, STORE_ACTUAL_LEVEL) only take effect when sent twice within 100 ms. Set config->send_twice to
trueand the driver will automatically re-transmit the frame after a 40 ms delay.Result semantics:
Pass
NULLforresultif no backward frame is expected. The driver will wait one backward-frame window before returning.Pass a pointer for
resultto enable RX. On return:*result >= 0: valid 8-bit backward-frame value (0x00–0xFF)*result == DALI_RESULT_NO_REPLY: timeout — no reply received
备注
This function is blocking. It occupies the calling task for the duration of the TX transmission plus the backward-frame reception window (up to config->tx_timeout_ms + 50 ms). Do not call this function from an ISR or from a high-priority real-time task where blocking is not acceptable.
- 参数
handle – [in] Handle returned by dali_new_master_rmt.
config – [in] Pointer to transaction configuration.
result – [out] Pointer to store the backward-frame result, or
NULLif no reply is expected.
- 返回
ESP_OK on success (including DALI_RESULT_NO_REPLY case)
ESP_ERR_INVALID_ARG if
handleorconfigis NULL, or address is out of rangeOther ESP_ERR codes propagated from RMT driver
Structures
-
struct dali_master_config_t
Configuration structure for creating a DALI driver instance.
Contains bus-agnostic parameters shared across all backend implementations (RMT, UART, etc.). Backend-specific parameters are passed separately via the corresponding config struct (e.g. dali_master_rmt_config_t).
Public Members
-
gpio_num_t rx_gpio
GPIO number for the DALI bus receive line
-
gpio_num_t tx_gpio
GPIO number for the DALI bus transmit line
-
bool invert_tx
Invert TX signal polarity. Enable when the hardware path between the MCU TX GPIO and the DALI bus performs an odd number of signal inversions.
-
bool invert_rx
Invert RX input signal polarity. Enable when the hardware path between the DALI bus and the MCU RX GPIO performs an odd number of signal inversions.
-
gpio_num_t rx_gpio
-
struct dali_master_rmt_config_t
RMT-backend specific configuration for a DALI master driver instance.
Pass a pointer to this struct as the
rmt_configargument of dali_new_master_rmt. Initialize with designated initializers to override the built-in defaults:dali_master_rmt_config_t rmt_cfg = { .mem_block_symbols = 48, }; dali_new_master_rmt(&cfg, &rmt_cfg, &handle);
Public Members
-
uint32_t mem_block_symbols
RMT memory block size in symbols for both TX and RX channels. Set to 0 to let the driver auto-detect the optimal value based on SOC_RMT_MEM_WORDS_PER_CHANNEL (48 on ESP32-C3/S3, 64 on ESP32/S2).
-
uint32_t mem_block_symbols
-
struct dali_master_transaction_config_t
Transaction configuration for dali_master_do_transaction().
Bundles all parameters that describe a single DALI transaction (forward frame addressing, command/data byte, and transmission options).
Public Members
-
dali_addr_type_t addr_type
Address type (dali_addr_type_t)
-
uint8_t addr
Device address (0–63 for short, 0–15 for group, ignored for broadcast, raw byte for special)
-
bool is_cmd
true → indirect command (S-bit = 1) false → direct DAPC value (S-bit = 0)
-
uint8_t command
Command code or arc-power value (second byte)
-
bool send_twice
true to repeat the frame within 100 ms
-
int tx_timeout_ms
Timeout in ms for the RMT TX completion wait
-
dali_addr_type_t addr_type
Macros
-
DALI_TX_TIMEOUT_MS
Default TX transmission timeout in milliseconds.
-
DALI_RESULT_NO_REPLY
Sentinel value returned in *result when no backward frame was received.
A genuine DALI backward frame carries an 8-bit value (0x00–0xFF). This negative sentinel is outside that range and is safe to use as a “no reply” indicator.
-
DALI_RESULT_IS_VALID(r)
Test whether a query result contains a valid backward-frame byte.
Usage:
int reply; dali_master_do_transaction(handle, &config, &reply); if (DALI_RESULT_IS_VALID(reply)) { ... }
Type Definitions
-
typedef struct dali_master_t *dali_master_handle_t
Opaque handle for a DALI driver instance.
Obtained from dali_new_master_rmt and passed to all subsequent API calls. Multiple independent instances can coexist on different GPIO pairs.
Enumerations
-
enum dali_addr_type_t
DALI address types.
Selects the addressing mode used when constructing the first byte of a forward frame.
Values:
-
enumerator DALI_ADDR_SHORT
Short address (0–63, format: 0AAAAAAS)
-
enumerator DALI_ADDR_GROUP
Group address (0–15, format: 100AAAAS)
-
enumerator DALI_ADDR_BROADCAST
Broadcast (format: 1111111S)
-
enumerator DALI_ADDR_SPECIAL
Special command byte passed through as-is
-
enumerator DALI_ADDR_SHORT
术语表
- Te
DALI 半周期单位,标称值为 416.67 µs(IEC 62386 允许 ±10% 容差)。 所有 DALI 时序均以 Te 的整数倍表示。
- 前向帧(FF,Forward Frame)
由 DALI 主站发送给控制设备的 16 位帧,由 1 个起始位 + 16 个数据位 + 2 个停止位组成,共 38 Te。第一字节为地址字节,第二字节为命令或亮度值。
- 后向帧(BF,Backward Frame)
DALI 从设备响应查询命令时发送的 8 位回复帧,由 1 个起始位 + 8 个数据位 + 2 个停止位组成,共 22 Te。从设备须在前向帧结束后 7 Te~22 Te 内回复。
- 短地址(Short Address)
分配给单个 DALI 控制设备的唯一地址,范围 0–63。 在前向帧中编码为 ``0AAAAAAS``(A 为地址位,S 为选择位)。
- 组地址(Group Address)
最多 16 个控制设备共享的地址,范围 0–15。 编码为
100AAAAS,可同时控制多个灯具而无需逐一寻址。