目录
ESP-ADF外设子系统深度解析:esp_peripherals组件架构与核心设计(显示输出类外设之AW2013)
版本信息: ESP-ADF v2.7-65-gcf908721
简介
本文档详细分析ESP-ADF中的显示/输出类外设实现机制,包括LCD、LED、WS2812、IS31FL3216和AW2013等外设的设计模式、接口规范、初始化流程和事件处理机制。ESP-ADF显示/输出类外设基于统一的外设框架设计,通过事件驱动模型实现显示和指示功能,为音频应用提供了丰富的视觉反馈能力和用户界面支持。
模块概述
功能定义
ESP-ADF显示/输出类外设主要负责提供视觉反馈和用户界面显示功能,将应用程序的状态和数据以可视化方式呈现给用户。主要功能包括:
- 状态指示(LED指示灯、状态灯等)
- 用户界面显示(LCD屏幕显示文本、图形等)
- 视觉效果(WS2812彩色灯带、IS31FL3216和AW2013 LED矩阵等)
- 音频可视化(音频频谱显示、节奏灯光效果等)
架构位置
显示/输出类外设是ESP-ADF外设子系统的重要组成部分,位于硬件驱动层和应用层之间:
核心特性
- 多种显示设备支持:支持LCD、LED、WS2812、IS31FL3216和AW2013等多种显示和指示设备
- 统一控制接口:所有显示/输出外设使用统一的初始化和控制接口
- 丰富的显示效果:支持开关控制、亮度调节、颜色变化、动画效果等多种显示功能
- 与音频处理集成:可与音频处理模块协同工作,实现音频可视化效果
- 低功耗设计:支持设备休眠和唤醒管理,优化功耗表现
- 事件驱动模型:通过事件机制实现显示状态变化的通知和处理
AW2013外设分析
AW2013外设概述
AW2013是一款3通道RGB LED驱动芯片,通过I2C总线控制,支持多种LED效果,包括常亮、呼吸灯和自动闪烁等模式。在ESP-ADF框架中,AW2013外设被封装为三个层次:
-
外设层:负责将AW2013集成到ESP-ADF外设系统中,处理事件分发和生命周期管理。
- 头文件:
components/esp_peripherals/include/periph_aw2013.h
- 实现文件:
components/esp_peripherals/periph_aw2013.c
- 头文件:
-
底层驱动层:提供底层AW2013驱动,负责I2C通信、寄存器配置和LED控制。
- 头文件:
components/esp_peripherals/lib/aw2013/aw2013.h
- 实现文件:
components/esp_peripherals/lib/aw2013/aw2013.c
- 头文件:
-
总线层:底层驱动通过I2C总线层与硬件通信,提供统一的总线访问接口。
- 头文件:
components/esp_peripherals/driver/i2c_bus/i2c_bus.h
- 实现文件:
components/esp_peripherals/driver/i2c_bus/i2c_bus.c
(ESP-IDF 5.3.0- 实现) - 实现文件:
components/esp_peripherals/driver/i2c_bus/i2c_bus_v2.c
(ESP-IDF 5.3.0+ 实现)
- 头文件:
AW2013芯片具有以下主要特性:
- 3通道RGB LED驱动
- 每通道最大电流可达15mA
- 支持常亮、呼吸灯和自动闪烁模式
- 可配置的闪烁周期和亮度
- 通过I2C总线控制
AW2013外设层次架构图
API与数据结构
外设层API
源文件:components/esp_peripherals/include/periph_aw2013.h
和components/esp_peripherals/periph_aw2013.c
公共API
// AW2013工作模式枚举
typedef enum {
AW2013_MODE_LED, // 常亮模式
AW2013_MODE_FADE, // 呼吸灯模式
AW2013_MODE_AUTO // 自动闪烁模式
} periph_aw2013_mode_t;
// AW2013配置结构体
typedef struct {
periph_aw2013_mode_t mode; // 工作模式
aw2013_brightness_t bright; // 亮度设置
uint32_t rgb_value; // RGB颜色值
} periph_aw2013_cfg_t;
// 初始化AW2013外设
esp_periph_handle_t periph_aw2013_init(periph_aw2013_cfg_t *aw2013_cfg);
// 设置亮度
esp_err_t periph_aw2013_set_brightless(esp_periph_handle_t periph, aw2013_brightness_t bright);
// 设置时间周期
esp_err_t periph_aw2013_set_time(esp_periph_handle_t periph, aw2013_time_t time, aw2013_time_level_t level);
// 设置工作模式
esp_err_t periph_aw2013_set_mode(esp_periph_handle_t periph, periph_aw2013_mode_t mode);
// 设置RGB颜色值
esp_err_t periph_aw2013_set_rgb_value(esp_periph_handle_t periph, uint32_t value);
// 设置重复次数
esp_err_t periph_aw2013_set_repeat_time(esp_periph_handle_t periph, uint8_t cnt);
内部数据结构
// AW2013外设内部结构体
typedef struct {
aw2013_time_level_t time[5]; // 5个时间段的设置
aw2013_brightness_t bright; // 亮度设置
periph_aw2013_mode_t mode; // 工作模式
uint32_t rgb_value; // RGB颜色值
uint8_t rpt_time; // 重复次数
} periph_aw2013_t;
底层驱动API
源文件:components/esp_peripherals/lib/aw2013/aw2013.h
和components/esp_peripherals/lib/aw2013/aw2013.c
公共API
// 亮度级别枚举
typedef enum {
AW2013_BRIGHT_0, // 关闭LED,电流为0mA
AW2013_BRIGHT_1, // 5mA
AW2013_BRIGHT_2, // 10mA
AW2013_BRIGHT_3, // 15mA
} aw2013_brightness_t;
// 自动闪烁周期的时间段
/*-------------------------------------------*\
| __________ |
| /| |\ |
| / | | \ |
| / | | \ |
| ________/ | | \__________ |
| | | | | | | |
| |<--t0->|t1 |<--t2-->|t3 |<--t4-->| |
\*-------------------------------------------*/
typedef enum {
AW2013_TIME_0, // T0
AW2013_TIME_1, // T1
AW2013_TIME_2, // T2
AW2013_TIME_3, // T3
AW2013_TIME_4 // T4
} aw2013_time_t;
// 时间级别枚举
typedef enum { // T1-T4 T0
AW2013_TIME_LEVEL_0, // 0.13s (T0 0s)
AW2013_TIME_LEVEL_1, // 0.26s (T0 0.13s)
AW2013_TIME_LEVEL_2, // 0.52s (T0 0.26s)
AW2013_TIME_LEVEL_3, // 1.04s (T0 0.52s)
AW2013_TIME_LEVEL_4, // 2.08s (T0 1.04s)
AW2013_TIME_LEVEL_5, // 4.16s (T0 2.08s)
AW2013_TIME_LEVEL_6, // 8.32s (T0 4.16s)
AW2013_TIME_LEVEL_7, // 16.64s (T0 8.32s)
AW2013_TIME_LEVEL_8, // (T0 16.64s)
} aw2013_time_level_t;
// 初始化AW2013芯片
esp_err_t aw2013_init(void);
// 重置AW2013芯片
esp_err_t aw2013_reset(void);
// 设置RGB值
esp_err_t aw2013_set_pwm_value(uint32_t value);
// 设置自动闪烁的重复次数
esp_err_t aw2013_set_repeat_time(uint8_t cnt);
// 设置各时间段的时长
esp_err_t aw2013_set_time(aw2013_time_t time, aw2013_time_level_t level);
// 设置亮度
esp_err_t aw2013_set_brightness(aw2013_brightness_t bright);
// 启用/禁用自动闪烁功能
esp_err_t aw2013_enable_auto_flash(bool en);
// 启用/禁用呼吸灯功能
esp_err_t aw2013_enable_fade_mode(bool en);
// 释放AW2013芯片资源
esp_err_t aw2013_deinit(void);
内部宏定义
#define AW2013_ADDR 0x8a // AW2013芯片地址
#define AW2013_MAX_LED_NUM 3 // 最大LED数量
#define AW2013_MAX_REPEAT_TIME 15 // 最大重复次数
AW2013 外设初始化流程
AW2013 外设的初始化流程涉及两个层次:外设层(Peripheral Layer)和底层驱动层(Driver Layer)。下面分别介绍这两个层次的初始化过程。
外设层初始化过程(periph_aw2013.c)
外设层初始化主要通过 periph_aw2013_init
函数(位于 periph_aw2013.c
)完成,主要包括以下步骤:
- 创建外设句柄:调用
esp_periph_create
函数创建外设句柄。 - 分配内部数据结构:分配
periph_aw2013_t
结构体内存,用于存储 AW2013 配置参数。 - 设置配置参数:根据传入的配置结构体
aw2013_cfg
设置工作模式、亮度和 RGB 值。 - 注册回调函数:设置初始化和销毁回调函数
_aw2013_init
和_aw2013_destroy
。
// 文件:components/esp_peripherals/periph_aw2013.c
// 初始化 AW2013 外设,返回外设句柄以供后续操作
esp_periph_handle_t periph_aw2013_init(periph_aw2013_cfg_t *aw2013_cfg)
{
// 1. 创建外设句柄,指定外设 ID 和名称
esp_periph_handle_t periph = esp_periph_create(PERIPH_ID_AW2013, "periph_aw2013");
AUDIO_MEM_CHECK(TAG, periph, return NULL); // 内存检查,确保句柄创建成功
// 2. 分配内部数据结构,用于存储 AW2013 配置和状态
periph_aw2013_t *aw2013 = audio_calloc(1, sizeof(periph_aw2013_t));
AUDIO_MEM_CHECK(TAG, aw2013, {
audio_free(periph);
return NULL;
});
// 3. 设置配置参数,从传入的配置结构体中获取
aw2013->mode = aw2013_cfg->mode; // 设置工作模式
aw2013->bright = aw2013_cfg->bright; // 设置亮度级别
aw2013->rgb_value = aw2013_cfg->rgb_value; // 设置 RGB 颜色值
// 设置默认时间段值,用于自动闪烁模式
aw2013->time[AW2013_TIME_0] = AW2013_TIME_LEVEL_1;
aw2013->time[AW2013_TIME_1] = AW2013_TIME_LEVEL_2;
aw2013->time[AW2013_TIME_2] = AW2013_TIME_LEVEL_2;
aw2013->time[AW2013_TIME_3] = AW2013_TIME_LEVEL_2;
aw2013->time[AW2013_TIME_4] = AW2013_TIME_LEVEL_2;
aw2013->rpt_time = 0; // 默认重复次数为 0
// 4. 注册回调函数,设置初始化和销毁函数
esp_periph_set_data(periph, aw2013); // 关联数据到句柄
esp_periph_set_function(periph, _aw2013_init, NULL, _aw2013_destroy); // 设置回调
return periph; // 返回外设句柄
}
当外设被添加到外设集合并启动时,会调用 _aw2013_init
函数(位于 periph_aw2013.c
),该函数负责调用底层驱动初始化函数并设置 AW2013 参数:
// 文件:components/esp_peripherals/periph_aw2013.c
// 外设初始化回调函数,在外设启动时调用
static esp_err_t _aw2013_init(esp_periph_handle_t self)
{
esp_err_t ret = ESP_OK;
periph_aw2013_t *aw2013 = esp_periph_get_data(self); // 获取外设数据
ret |= aw2013_init(); // 调用底层驱动初始化函数,初始化 I2C 和芯片
for (int i = 0; i <= AW2013_TIME_4; i++) {
ret |= aw2013_set_time(i, aw2013->time[i]); // 设置每个时间段的时长
}
ret |= aw2013_set_repeat_time(aw2013->rpt_time); // 设置自动闪烁重复次数
ret |= aw2013_set_brightness(aw2013->bright); // 设置亮度级别
ret |= _aw2013_set_mode(aw2013->mode); // 设置工作模式(常亮、呼吸灯、自动闪烁)
ret |= aw2013_set_pwm_value(aw2013->rgb_value); // 设置 RGB 颜色值
return ret; // 返回操作结果
}
在 _aw2013_init
函数中,调用了以下底层驱动函数来完成 AW2013 的配置:
- aw2013_set_time:设置自动闪烁周期中各个时间段(T0~T4)的时长。参数
time
指定时间段,level
指定时长级别。 - aw2013_set_repeat_time:设置自动闪烁的重复次数。参数
cnt
指定重复次数,需小于最大值AW2013_MAX_REPEAT_TIME
。 - aw2013_set_brightness:设置 LED 亮度级别。参数
bright
指定亮度级别枚举值。 - aw2013_set_pwm_value:设置 RGB 颜色值,通过 PWM 控制 LED 输出。参数
value
是一个 32 位值,每个字节分别表示 R、G、B 通道的 PWM 值。 - _aw2013_set_mode:内部辅助函数,根据指定的工作模式启用或禁用自动闪烁和呼吸灯功能。参数
mode
指定工作模式枚举值。
底层驱动初始化过程(aw2013.c)
底层驱动初始化通过 aw2013_init
函数(位于 aw2013.c
)完成,主要包括以下步骤:
- I2C 配置:将 I2C 配置设置为主机模式,时钟速度为 100000 Hz。
- 获取 I2C 引脚:调用
get_i2c_pins
函数为指定端口配置 I2C 引脚。 - 创建 I2C 总线:使用指定的端口和配置创建 I2C 总线。
- 复位 AW2013:调用
aw2013_reset
函数将 AW2013 芯片复位到默认状态。 - 错误处理:如果上述任何步骤失败,则使用
ESP_LOGE
记录错误消息。 - 返回结果:函数返回初始化过程的结果。
// 文件:components/esp_peripherals/lib/aw2013/aw2013.c
// 初始化 AW2013 芯片,配置 I2C 总线并启用芯片
esp_err_t aw2013_init(void)
{
esp_err_t ret = ESP_OK;
i2c_config_t config = {
.mode = I2C_MODE_MASTER, // 设置 I2C 为主机模式
.master.clk_speed = 100000 // 设置时钟速度为 100kHz
};
ret |= get_i2c_pins(AW2013_I2C_PORT, &config); // 获取 I2C 引脚配置
i2c_handle = i2c_bus_create(AW2013_I2C_PORT, &config); // 创建 I2C 总线
ret |= aw2013_reset(); // 复位 AW2013 芯片
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Fail to init aw2013"); // 如果初始化失败,记录错误日志
}
return ret; // 返回初始化结果
}
在 aw2013_init
函数中,调用了以下辅助函数:
- aw2013_reset:复位 AW2013 芯片,将所有寄存器恢复到默认值,确保芯片处于已知状态。
辅助函数详解
初始化过程中涉及以下辅助函数,用于支持 AW2013 外设的配置和操作。下面是这些函数的详细说明和代码片段:
aw2013_reset
// 文件:components/esp_peripherals/lib/aw2013/aw2013.c
// 复位 AW2013 芯片,将所有寄存器恢复到默认值
esp_err_t aw2013_reset(void)
{
esp_err_t ret = ESP_OK;
uint8_t reg_val = 0;
uint8_t reg_addr = 0x0;
AUDIO_NULL_CHECK(TAG, i2c_handle, return ESP_FAIL); // 检查 I2C 句柄是否有效
reg_addr = AW2013_REG_RESET; // 复位寄存器地址
reg_addr = AW2013_RESET_VALUE; // 设置复位值
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1); // 写入复位命令
reg_addr = AW2013_REG_GCR; // 全局控制寄存器地址
reg_val = 0x01; // 启用芯片
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1); // 写入寄存器
reg_addr = AW2013_REG_LCTR; // LED 控制寄存器地址
reg_val = 0x07; // 启用所有 LED 通道
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1); // 写入寄存器
ret |= aw2013_set_brightness(1); // 设置默认亮度
return ret; // 返回操作结果
}
该函数用于复位 AW2013 芯片,通过向复位寄存器 AW2013_REG_RESET
写入特定值 AW2013_RESET_VALUE
来触发复位操作。复位后,函数还会配置全局控制寄存器启用芯片,设置 LED 控制寄存器启用所有 LED 通道,并设置默认亮度,确保芯片处于已知且可用的状态。
以下是 aw2013_reset
函数的执行时序图:
这个时序图展示了 aw2013_reset
函数的执行流程,包括检查 I2C 句柄、复位芯片、配置全局控制寄存器、设置 LED 控制寄存器以及设置默认亮度等步骤,以及与 I2C 总线和 AW2013 芯片的交互过程。
aw2013_set_time
// 文件:components/esp_peripherals/lib/aw2013/aw2013.c
// 设置自动闪烁周期中各个时间段的时长
esp_err_t aw2013_set_time(aw2013_time_t time, aw2013_time_level_t level)
{
if (level > AW2013_TIME_LEVEL_8 || time > AW2013_TIME_4) {
ESP_LOGE(TAG, "Invalid parameters, time: %d, level: %d", time, level);
return ESP_FAIL;
}
uint8_t reg_val = 0;
uint8_t reg_addr = 0x0;
esp_err_t ret = ESP_OK;
AUDIO_NULL_CHECK(TAG, i2c_handle, return ESP_FAIL); // 检查 I2C 句柄是否有效
for (int i = 0; i < AW2013_MAX_LED_NUM; i++) { // 为所有 LED 通道设置时间
switch (time) {
case AW2013_TIME_0: {
reg_addr = AW2013_REG_LED0T0CNT + AW2013_MAX_LED_NUM * i;
ret |= i2c_bus_read_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
reg_val &= 0x0f;
reg_val |= (level << 4);
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
break;
}
case AW2013_TIME_1: {
if (level > AW2013_TIME_LEVEL_7) {
level = AW2013_TIME_LEVEL_7; // 限制级别最大值
}
reg_addr = AW2013_REG_LED0T1T2 + AW2013_MAX_LED_NUM * i;
ret |= i2c_bus_read_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
reg_val &= 0x8f;
reg_val |= (level << 4);
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
break;
}
case AW2013_TIME_2: {
if (level > AW2013_TIME_LEVEL_5) {
level = AW2013_TIME_LEVEL_5; // 限制级别最大值
}
reg_addr = AW2013_REG_LED0T1T2 + AW2013_MAX_LED_NUM * i;
ret |= i2c_bus_read_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
reg_val &= 0xf8;
reg_val |= level;
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
break;
}
case AW2013_TIME_3: {
if (level > 7) {
level = 7; // 限制级别最大值
}
reg_addr = AW2013_REG_LED0T3T4 + AW2013_MAX_LED_NUM * i;
ret |= i2c_bus_read_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
reg_val &= 0x8f;
reg_val |= (level << 4);
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
break;
}
case AW2013_TIME_4: {
if (level > 7) {
level = 7; // 限制级别最大值
}
reg_addr = AW2013_REG_LED0T3T4 + AW2013_MAX_LED_NUM * i;
ret |= i2c_bus_read_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
reg_val &= 0xf8;
reg_val |= level;
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
break;
}
default: {
return ESP_FAIL;
}
}
}
return ret; // 返回操作结果
}
该函数用于设置自动闪烁周期中各个时间段(T0~T4)的时长。参数 time
指定时间段,level
指定时长级别。函数会验证参数的有效性,并为所有 LED 通道配置相应的时间寄存器。根据不同的时间段,函数会操作不同的寄存器并应用适当的位掩码,确保正确配置每个时间段的持续时间。每个时间段还有其特定的级别限制,函数会确保不超过这些限制。
以下是 aw2013_set_time
函数的执行时序图:
这个时序图展示了 aw2013_set_time
函数的执行流程,包括参数验证、对不同时间段的处理逻辑以及与 I2C 总线和 AW2013 芯片的交互过程。根据不同的时间段参数,函数会操作不同的寄存器并应用适当的位掩码,确保正确配置每个时间段的持续时间。
aw2013_set_repeat_time
// 文件:components/esp_peripherals/lib/aw2013/aw2013.c
// 设置自动闪烁的重复次数
esp_err_t aw2013_set_repeat_time(uint8_t cnt)
{
esp_err_t ret = ESP_OK;
AUDIO_NULL_CHECK(TAG, i2c_handle, return ESP_FAIL); // 检查 I2C 句柄是否有效
uint8_t reg_val = 0;
uint8_t reg_addr = 0x0;
cnt %= AW2013_MAX_REPEAT_TIME; // 确保重复次数不超过最大值
for (int i = 0; i < AW2013_MAX_LED_NUM; i++) { // 为所有 LED 通道设置重复次数
reg_addr = AW2013_REG_LED0T0CNT + AW2013_MAX_LED_NUM * i;
ret |= i2c_bus_read_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
reg_val &= 0xf0;
reg_val |= cnt;
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
}
return ret; // 返回操作结果
}
该函数用于设置自动闪烁模式的重复次数。参数 cnt
指定重复次数,函数会确保其不超过最大值 AW2013_MAX_REPEAT_TIME
。函数为所有 LED 通道配置重复次数,通过读取当前寄存器值,修改相应位,然后写回寄存器。
aw2013_set_brightness
// 文件:components/esp_peripherals/lib/aw2013/aw2013.c
// 设置 LED 亮度级别
esp_err_t aw2013_set_brightness(aw2013_brightness_t bright)
{
esp_err_t ret = ESP_OK;
uint8_t reg_val = 0;
uint8_t reg_addr = 0x0;
AUDIO_NULL_CHECK(TAG, i2c_handle, return ESP_FAIL); // 检查 I2C 句柄是否有效
if (bright > AW2013_BRIGHT_3) {
bright = AW2013_BRIGHT_3; // 限制亮度级别最大值
}
for (int i = 0; i < AW2013_MAX_LED_NUM; i++) { // 为所有 LED 通道设置亮度
reg_addr = AW2013_REG_LCFG0 + i;
ret |= i2c_bus_read_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
reg_val &= 0xfc;
reg_val |= bright;
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
}
return ret; // 返回操作结果
}
该函数用于设置 LED 的亮度级别。参数 bright
指定亮度级别枚举值。函数会确保亮度级别不超过最大值,并为所有 LED 通道配置亮度。通过读取当前寄存器值,修改相应位,然后写回寄存器。
aw2013_set_pwm_value
// 文件:components/esp_peripherals/lib/aw2013/aw2013.c
// 设置 RGB 颜色值,通过 PWM 控制 LED 输出
esp_err_t aw2013_set_pwm_value(uint32_t value)
{
esp_err_t ret = ESP_OK;
uint8_t reg_val = 0;
uint8_t reg_addr = 0x0;
AUDIO_NULL_CHECK(TAG, i2c_handle, return ESP_FAIL); // 检查 I2C 句柄是否有效
reg_addr = AW2013_REG_PWM0;
reg_val = (value >> 16) & 0xff; // 提取 R 通道 PWM 值
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
reg_addr = AW2013_REG_PWM1;
reg_val = (value >> 8) & 0xff; // 提取 G 通道 PWM 值
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
reg_addr = AW2013_REG_PWM2;
reg_val = value & 0xff; // 提取 B 通道 PWM 值
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
return ret; // 返回操作结果
}
该函数用于设置 RGB 颜色值,通过 PWM 控制 LED 的输出。参数 value
是一个 32 位值,其中每个字节分别表示 R、G、B 通道的 PWM 值。函数分别将这些值写入对应的 PWM 寄存器以控制 LED 颜色。
aw2013_enable_auto_flash
// 文件:components/esp_peripherals/lib/aw2013/aw2013.c
// 启用或禁用自动闪烁功能
esp_err_t aw2013_enable_auto_flash(bool en)
{
esp_err_t ret = ESP_OK;
uint8_t reg_val = 0;
uint8_t reg_addr = 0x0;
AUDIO_NULL_CHECK(TAG, i2c_handle, return ESP_FAIL); // 检查 I2C 句柄是否有效
if (en) { // 启用自动闪烁
for (int i = 0; i < AW2013_MAX_LED_NUM; i++) {
reg_addr = AW2013_REG_LCFG0 + i;
ret |= i2c_bus_read_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
reg_val |= (0x01 << 4); // 设置自动闪烁位
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
}
} else { // 禁用自动闪烁
for (int i = 0; i < AW2013_MAX_LED_NUM; i++) {
reg_addr = AW2013_REG_LCFG0 + i;
ret |= i2c_bus_read_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
reg_val &= ~(0x01 << 4); // 清除自动闪烁位
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
}
}
return ret; // 返回操作结果
}
该函数用于启用或禁用自动闪烁功能。参数 en
为布尔值,决定是否启用该功能。函数为所有 LED 通道配置自动闪烁功能,通过读取当前寄存器值,设置或清除相应位,然后写回寄存器。
aw2013_enable_fade_mode
// 文件:components/esp_peripherals/lib/aw2013/aw2013.c
// 启用或禁用呼吸灯模式
esp_err_t aw2013_enable_fade_mode(bool en)
{
esp_err_t ret = ESP_OK;
uint8_t reg_val = 0;
uint8_t reg_addr = 0x0;
AUDIO_NULL_CHECK(TAG, i2c_handle, return ESP_FAIL); // 检查 I2C 句柄是否有效
if (en) { // 启用呼吸灯模式
for (int i = 0; i < AW2013_MAX_LED_NUM; i++) {
reg_addr = AW2013_REG_LCFG0 + i;
ret |= i2c_bus_read_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
reg_val &= ~(0x01 << 4); // 清除自动闪烁位
reg_val |= (0x03 << 5); // 设置呼吸灯模式位
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
}
} else { // 禁用呼吸灯模式
for (int i = 0; i < AW2013_MAX_LED_NUM; i++) {
reg_addr = AW2013_REG_LCFG0 + i;
ret |= i2c_bus_read_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
reg_val &= ~(0x03 << 5); // 清除呼吸灯模式位
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1);
}
}
return ret; // 返回操作结果
}
该函数用于启用或禁用呼吸灯模式。参数 en
为布尔值,决定是否启用该功能。函数为所有 LED 通道配置呼吸灯模式,通过读取当前寄存器值,设置或清除相应位,然后写回寄存器。启用呼吸灯模式时,会同时禁用自动闪烁功能。
_aw2013_set_mode
// 文件:components/esp_peripherals/periph_aw2013.c
// 设置 AW2013 工作模式(常亮、呼吸灯、自动闪烁)
static esp_err_t _aw2013_set_mode(periph_aw2013_mode_t mode)
{
esp_err_t ret = ESP_OK;
switch (mode) {
case PERIPH_AW2013_MODE_NORMAL: // 常亮模式
ret |= aw2013_enable_auto_flash(false); // 禁用自动闪烁
ret |= aw2013_enable_fade_mode(false); // 禁用呼吸灯
break;
case PERIPH_AW2013_MODE_FADE: // 呼吸灯模式
ret |= aw2013_enable_auto_flash(false); // 禁用自动闪烁
ret |= aw2013_enable_fade_mode(true); // 启用呼吸灯
break;
case PERIPH_AW2013_MODE_AUTO_FLASH: // 自动闪烁模式
ret |= aw2013_enable_auto_flash(true); // 启用自动闪烁
ret |= aw2013_enable_fade_mode(false); // 禁用呼吸灯
break;
default:
ESP_LOGE(TAG, "Unsupported mode: %d", mode); // 不支持的模式
ret = ESP_FAIL;
break;
}
return ret; // 返回操作结果
}
该函数是一个内部辅助函数,用于设置 AW2013 的工作模式。根据指定的模式枚举值,函数会调用相应的函数来启用或禁用自动闪烁和呼吸灯功能,从而实现常亮、呼吸灯或自动闪烁模式。
AW2013 外设完整初始化时序图
下图展示了 AW2013 外设从应用程序调用到底层驱动完成初始化的完整流程:
总结
AW2013 外设的初始化过程涉及多个层次的组件交互,包括外设层和底层驱动层。初始化完成后,AW2013 外设可以通过不同的工作模式实现 LED 的常亮、呼吸灯和自动闪烁效果。整个初始化流程设计合理,各组件职责明确,便于维护和扩展。
AW2013 外设销毁流程
AW2013 外设的销毁流程同样涉及外设层(Peripheral Layer)和底层驱动层(Driver Layer)两个层次。销毁过程主要负责释放资源和清理内存。下面分别介绍这两个层次的销毁过程。
外设层销毁过程(periph_aw2013.c)
外设层销毁主要通过 _aw2013_destroy
函数(位于 periph_aw2013.c
)完成,这个函数在外设被移除或者被停止时由 ESP 外设框架调用。根据实际源码,该函数主要包括以下步骤:
- 获取外设数据:从外设句柄中获取之前存储的
periph_aw2013_t
结构体。 - 调用底层驱动销毁:调用
aw2013_deinit
函数释放底层资源。 - 释放内存:释放
periph_aw2013_t
结构体占用的内存。
// 文件:components/esp_peripherals/periph_aw2013.c
// 销毁 AW2013 外设,释放资源
static esp_err_t _aw2013_destroy(esp_periph_handle_t self)
{
esp_err_t ret = ESP_OK;
periph_aw2013_t *aw2013 = esp_periph_get_data(self); // 获取外设数据
ret |= aw2013_deinit(); // 调用底层驱动销毁函数,释放底层资源
audio_free(aw2013); // 释放 aw2013 结构体内存
return ret; // 返回操作结果
}
该函数首先通过 esp_periph_get_data
获取之前在初始化阶段存储的外设数据结构。然后直接调用底层驱动的 aw2013_deinit
函数进行硬件资源的释放。最后,释放分配给 periph_aw2013_t
结构体的内存空间。这简化的销毁过程依赖于 aw2013_deinit
函数来正确地清理芯片和总线资源。
底层驱动销毁过程(aw2013.c)
底层驱动销毁通过 aw2013_deinit
函数(位于 aw2013.c
)完成,主要包括以下步骤:
- 复位芯片:向 AW2013 芯片的复位寄存器写入复位值,使其回到默认状态。
- 释放 I2C 总线:调用
i2c_bus_delete
函数删除 I2C 总线实例,释放相关资源。
// 文件:components/esp_peripherals/lib/aw2013/aw2013.c
// 反初始化 AW2013 芯片,释放资源
esp_err_t aw2013_deinit(void)
{
esp_err_t ret = ESP_OK;
uint8_t reg_addr = AW2013_REG_RESET;
uint8_t reg_val = AW2013_RESET_VALUE;
AUDIO_NULL_CHECK(TAG, i2c_handle, return ESP_FAIL); // 检查 I2C 句柄是否有效
ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, ®_addr, 1, ®_val, 1); // 复位芯片
ret |= i2c_bus_delete(i2c_handle); // 删除 I2C 总线实例
return ret; // 返回操作结果
}
该函数首先检查 I2C 句柄是否有效,然后通过 I2C 总线向 AW2013 芯片的复位寄存器(AW2013_REG_RESET
)写入复位值(AW2013_RESET_VALUE
),使芯片恢复到初始状态。接着调用 i2c_bus_delete
函数删除之前创建的 I2C 总线实例,释放相关资源。这样可以确保 AW2013 外设完全释放所有占用的硬件和软件资源。
AW2013 外设完整销毁时序图
下图展示了 AW2013 外设从停止到完全释放资源的销毁流程:
这个时序图展示了 AW2013 外设销毁的完整流程,从外设框架调用 _aw2013_destroy
开始,到最终释放所有资源结束。该流程反映了实际源码中的简洁设计,直接调用 aw2013_deinit
函数复位芯片并释放 I2C 总线资源,然后释放外设数据结构内存。
总结
AW2013 外设的销毁流程设计简洁且合理,能够有效释放所有占用的资源,包括硬件资源(I2C 总线和 AW2013 芯片)和软件资源(内存空间)。销毁流程采用了最小化设计,直接复位芯片并释放 I2C 总线和内存资源,遵循了资源管理的最佳实践,确保系统运行稳定且无资源泄漏。
AW2013 外设事件处理
AW2013 外设是一款 LED 驱动芯片,主要用于控制 RGB LED 灯的亮度、闪烁和呼吸效果等。与其他一些需要处理用户输入的外设不同,AW2013 主要是一个输出型外设,它本身不会产生需要由应用程序处理的事件。
在 ESP-ADF 的外设框架中,AW2013 外设没有特定的事件处理函数(如 _aw2013_event_handler
),这是因为它不需要响应或处理来自硬件的事件通知。应用程序通过调用 AW2013 外设提供的 API 函数来控制 LED 的显示效果,而不是通过事件机制与 AW2013 外设交互。
虽然 AW2013 外设没有专门的事件处理,但它仍然遵循 ESP-ADF 外设框架的生命周期管理,包括初始化和销毁过程。应用程序可以通过框架提供的通用接口(如 esp_periph_start
、esp_periph_stop
等)来管理 AW2013 外设的生命周期。
AW2013 外设控制接口
虽然没有事件处理机制,但 AW2013 外设提供了丰富的控制接口,允许应用程序灵活地控制 LED 显示效果:
-
设置 RGB 值:通过
periph_aw2013_set_rgb_value
函数设置 LED 的颜色。esp_err_t periph_aw2013_set_rgb_value(esp_periph_handle_t periph, uint32_t value);
-
设置工作模式:通过
periph_aw2013_set_mode
函数设置 LED 的工作模式(常亮、呼吸或闪烁)。esp_err_t periph_aw2013_set_mode(esp_periph_handle_t periph, periph_aw2013_mode_t mode);
-
设置亮度:通过
periph_aw2013_set_brightless
函数设置 LED 的亮度级别。esp_err_t periph_aw2013_set_brightless(esp_periph_handle_t periph, aw2013_brightness_t bright);
-
设置时间参数:通过
periph_aw2013_set_time
函数设置呼吸灯或闪烁效果的时间参数。esp_err_t periph_aw2013_set_time(esp_periph_handle_t periph, aw2013_time_t time, aw2013_time_level_t level);
-
设置重复次数:通过
periph_aw2013_set_repeat_time
函数设置闪烁效果的重复次数。esp_err_t periph_aw2013_set_repeat_time(esp_periph_handle_t periph, uint8_t cnt);
这些接口提供了全面的 LED 控制能力,使应用程序可以根据需要实现各种视觉效果。
AW2013 外设典型使用示例
以下是 AW2013 外设的典型使用示例,展示了如何在实际应用中控制 RGB LED。
#include "esp_peripherals.h"
#include "periph_aw2013.h"
#include "board.h"
void app_main()
{
// 初始化外设管理器
esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
esp_periph_set_handle_t set = esp_periph_set_init(&periph_cfg);
// 配置 AW2013 外设 - 设置为呼吸灯模式
periph_aw2013_cfg_t aw2013_cfg = {
.mode = PERIPH_AW2013_MODE_BREATHE, // 呼吸灯模式
.rgb_value = 0x0000FF, // 蓝色
.bright = AW2013_BRIGHTNESS_025, // 亮度级别
};
// 初始化并启动 AW2013 外设
esp_periph_handle_t aw2013_handle = periph_aw2013_init(&aw2013_cfg);
esp_periph_start(set, aw2013_handle);
// 配置呼吸灯参数
periph_aw2013_set_time(aw2013_handle, AW2013_TIME_FADE_IN, AW2013_TIME_1S3_1S9);
periph_aw2013_set_time(aw2013_handle, AW2013_TIME_FADE_OUT, AW2013_TIME_1S3_1S9);
// 切换到其他模式示例
// periph_aw2013_set_mode(aw2013_handle, PERIPH_AW2013_MODE_ALWAYS_ON); // 常亮模式
// periph_aw2013_set_rgb_value(aw2013_handle, 0x00FF00); // 改变颜色为绿色
// 与事件系统结合的示例
// esp_periph_set_callback(set, event_handler, aw2013_handle); // 注册事件回调
// 主循环
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
// 事件回调函数示例 - 与其他外设(如按键、Wi-Fi等)交互
static esp_err_t event_handler(esp_periph_handle_t self, esp_periph_event_t *event, void *ctx)
{
esp_periph_handle_t aw2013 = (esp_periph_handle_t)ctx;
// 根据不同事件设置不同LED效果
switch(event->type) {
case PERIPH_WIFI_CONNECTED: // Wi-Fi连接成功
periph_aw2013_set_rgb_value(aw2013, 0x00FF00); // 绿色
periph_aw2013_set_mode(aw2013, PERIPH_AW2013_MODE_ALWAYS_ON); // 常亮
break;
case PERIPH_WIFI_DISCONNECTED: // Wi-Fi断开连接
periph_aw2013_set_rgb_value(aw2013, 0xFF0000); // 红色
periph_aw2013_set_mode(aw2013, PERIPH_AW2013_MODE_AUTO_FLASH); // 闪烁
break;
}
return ESP_OK;
}
总结
AW2013 外设提供了丰富的 API 来控制 RGB LED 的显示效果,可以实现常亮、呼吸灯和闪烁等多种模式。通过这些 API,开发者可以根据应用程序需求和系统状态,动态调整 LED 的显示效果,提供直观的视觉反馈。
虽然 AW2013 外设本身不产生事件,但它可以与其他产生事件的外设(如 Wi-Fi、按键等)结合使用,根据这些事件动态改变 LED 显示,从而提升用户体验。AW2013 外设的简单易用性和灵活性使其成为 ESP-ADF 应用中实现视觉反馈的理想选择。