ESP-ADF外设子系统深度解析:esp_peripherals组件架构与核心设计(显示输出类外设之AW2013)

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外设子系统的重要组成部分,位于硬件驱动层和应用层之间:

应用程序
ESP外设子系统
显示/输出类外设
LCD外设
LED外设
WS2812外设
IS31FL3216外设
AW2013外设
SPI/I2C驱动
GPIO驱动
RMT驱动
I2C驱动
I2C驱动

核心特性

  • 多种显示设备支持:支持LCD、LED、WS2812、IS31FL3216和AW2013等多种显示和指示设备
  • 统一控制接口:所有显示/输出外设使用统一的初始化和控制接口
  • 丰富的显示效果:支持开关控制、亮度调节、颜色变化、动画效果等多种显示功能
  • 与音频处理集成:可与音频处理模块协同工作,实现音频可视化效果
  • 低功耗设计:支持设备休眠和唤醒管理,优化功耗表现
  • 事件驱动模型:通过事件机制实现显示状态变化的通知和处理

AW2013外设分析

AW2013外设概述

AW2013是一款3通道RGB LED驱动芯片,通过I2C总线控制,支持多种LED效果,包括常亮、呼吸灯和自动闪烁等模式。在ESP-ADF框架中,AW2013外设被封装为三个层次:

  1. 外设层:负责将AW2013集成到ESP-ADF外设系统中,处理事件分发和生命周期管理。

    • 头文件:components/esp_peripherals/include/periph_aw2013.h
    • 实现文件:components/esp_peripherals/periph_aw2013.c
  2. 底层驱动层:提供底层AW2013驱动,负责I2C通信、寄存器配置和LED控制。

    • 头文件:components/esp_peripherals/lib/aw2013/aw2013.h
    • 实现文件:components/esp_peripherals/lib/aw2013/aw2013.c
  3. 总线层:底层驱动通过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外设层次架构图
底层驱动层 aw2013.c
外设层 periph_aw2013.c
调用
调用
设置
设置
调用
调用
调用
调用
调用
初始化
设置
设置
设置
调用
调用
调用
调用
初始化
写入
写入
写入
访问
访问
寄存器配置
aw2013_init
时间寄存器
aw2013_set_time
亮度寄存器
aw2013_set_brightness
PWM寄存器
aw2013_set_pwm_value
i2c_bus_create
i2c_bus_write_bytes
i2c_bus_write_bytes
i2c_bus_write_bytes
_aw2013_init
periph_aw2013_init
_aw2013_destroy
ESP-ADF应用
esp_periph_create
aw2013_deinit
I2C总线初始化
I2C总线传输
ESP32 I2C硬件

API与数据结构

外设层API

源文件components/esp_peripherals/include/periph_aw2013.hcomponents/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.hcomponents/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)完成,主要包括以下步骤:

  1. 创建外设句柄:调用 esp_periph_create 函数创建外设句柄。
  2. 分配内部数据结构:分配 periph_aw2013_t 结构体内存,用于存储 AW2013 配置参数。
  3. 设置配置参数:根据传入的配置结构体 aw2013_cfg 设置工作模式、亮度和 RGB 值。
  4. 注册回调函数:设置初始化和销毁回调函数 _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)完成,主要包括以下步骤:

  1. I2C 配置:将 I2C 配置设置为主机模式,时钟速度为 100000 Hz。
  2. 获取 I2C 引脚:调用 get_i2c_pins 函数为指定端口配置 I2C 引脚。
  3. 创建 I2C 总线:使用指定的端口和配置创建 I2C 总线。
  4. 复位 AW2013:调用 aw2013_reset 函数将 AW2013 芯片复位到默认状态。
  5. 错误处理:如果上述任何步骤失败,则使用 ESP_LOGE 记录错误消息。
  6. 返回结果:函数返回初始化过程的结果。
// 文件: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, &reg_addr, 1, &reg_val, 1);  // 写入复位命令

    reg_addr = AW2013_REG_GCR;  // 全局控制寄存器地址
    reg_val = 0x01;  // 启用芯片
    ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_val, 1);  // 写入寄存器

    reg_addr = AW2013_REG_LCTR;  // LED 控制寄存器地址
    reg_val = 0x07;  // 启用所有 LED 通道
    ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_val, 1);  // 写入寄存器
    ret |= aw2013_set_brightness(1);  // 设置默认亮度
    return ret;  // 返回操作结果
}

该函数用于复位 AW2013 芯片,通过向复位寄存器 AW2013_REG_RESET 写入特定值 AW2013_RESET_VALUE 来触发复位操作。复位后,函数还会配置全局控制寄存器启用芯片,设置 LED 控制寄存器启用所有 LED 通道,并设置默认亮度,确保芯片处于已知且可用的状态。

以下是 aw2013_reset 函数的执行时序图:

应用程序 aw2013_reset I2C 总线 AW2013 芯片 aw2013_set_brightness 调用 aw2013_reset() 检查 I2C 句柄是否有效 写入复位寄存器 (AW2013_REG_RESET) 发送复位命令 确认复位 返回操作结果 写入全局控制寄存器 (AW2013_REG_GCR) 设置值 0x01 (启用芯片) 确认写入 返回操作结果 写入 LED 控制寄存器 (AW2013_REG_LCTR) 设置值 0x07 (启用所有 LED 通道) 确认写入 返回操作结果 调用 aw2013_set_brightness(1) 为所有 LED 通道设置默认亮度 写入亮度配置 确认写入 返回操作结果 返回操作结果 返回复位结果 应用程序 aw2013_reset I2C 总线 AW2013 芯片 aw2013_set_brightness

这个时序图展示了 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, &reg_addr, 1, &reg_val, 1);
                    reg_val &= 0x0f;
                    reg_val |= (level << 4);
                    ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_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, &reg_addr, 1, &reg_val, 1);
                    reg_val &= 0x8f;
                    reg_val |= (level << 4);
                    ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_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, &reg_addr, 1, &reg_val, 1);
                    reg_val &= 0xf8;
                    reg_val |= level;
                    ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_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, &reg_addr, 1, &reg_val, 1);
                    reg_val &= 0x8f;
                    reg_val |= (level << 4);
                    ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_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, &reg_addr, 1, &reg_val, 1);
                    reg_val &= 0xf8;
                    reg_val |= level;
                    ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_val, 1);
                    break;
                }
            default: {
                    return ESP_FAIL;
                }
        }
    }
    return ret;  // 返回操作结果
}

该函数用于设置自动闪烁周期中各个时间段(T0~T4)的时长。参数 time 指定时间段,level 指定时长级别。函数会验证参数的有效性,并为所有 LED 通道配置相应的时间寄存器。根据不同的时间段,函数会操作不同的寄存器并应用适当的位掩码,确保正确配置每个时间段的持续时间。每个时间段还有其特定的级别限制,函数会确保不超过这些限制。

以下是 aw2013_set_time 函数的执行时序图:

应用程序 aw2013_set_time I2C 总线 AW2013 芯片 调用 aw2013_set_time(time, level) 检查参数有效性 返回 ESP_FAIL 检查 I2C 句柄是否有效 读取 LED0T0CNT 寄存器 读取请求 返回当前值 返回寄存器值 修改高 4 位为 level 写回修改后的值 写入请求 确认写入 返回操作结果 限制 level 最大值为 7 读取 LED0T1T2 寄存器 读取请求 返回当前值 返回寄存器值 修改中间 3 位为 level 写回修改后的值 写入请求 确认写入 返回操作结果 限制 level 最大值为 5 读取 LED0T1T2 寄存器 读取请求 返回当前值 返回寄存器值 修改低 3 位为 level 写回修改后的值 写入请求 确认写入 返回操作结果 限制 level 最大值为 7 读取 LED0T3T4 寄存器 读取请求 返回当前值 返回寄存器值 修改中间 3 位为 level 写回修改后的值 写入请求 确认写入 返回操作结果 限制 level 最大值为 7 读取 LED0T3T4 寄存器 读取请求 返回当前值 返回寄存器值 修改低 3 位为 level 写回修改后的值 写入请求 确认写入 返回操作结果 返回 ESP_FAIL alt [time = AW2013_TIME_0] [time = AW2013_TIME_1] [time = AW2013_TIME_2] [time = AW2013_TIME_3] [time = AW2013_TIME_4] [其他时间段] loop [对每个 LED 通道] 返回操作结果 alt [参数无效] [参数有效] 应用程序 aw2013_set_time I2C 总线 AW2013 芯片

这个时序图展示了 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, &reg_addr, 1, &reg_val, 1);
        reg_val &= 0xf0;
        reg_val |= cnt;
        ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_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, &reg_addr, 1, &reg_val, 1);
        reg_val &= 0xfc;
        reg_val |= bright;
        ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_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, &reg_addr, 1, &reg_val, 1);

    reg_addr = AW2013_REG_PWM1;
    reg_val = (value >> 8) & 0xff;  // 提取 G 通道 PWM 值
    ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_val, 1);

    reg_addr = AW2013_REG_PWM2;
    reg_val = value & 0xff;  // 提取 B 通道 PWM 值
    ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_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, &reg_addr, 1, &reg_val, 1);
            reg_val |= (0x01 << 4);  // 设置自动闪烁位
            ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_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, &reg_addr, 1, &reg_val, 1);
            reg_val &= ~(0x01 << 4);  // 清除自动闪烁位
            ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_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, &reg_addr, 1, &reg_val, 1);
            reg_val &= ~(0x01 << 4);  // 清除自动闪烁位
            reg_val |=  (0x03 << 5);  // 设置呼吸灯模式位
            ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_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, &reg_addr, 1, &reg_val, 1);
            reg_val &= ~(0x03 << 5);  // 清除呼吸灯模式位
            ret |= i2c_bus_write_bytes(i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_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 外设从应用程序调用到底层驱动完成初始化的完整流程:

应用程序 periph_aw2013_init (periph_aw2013.c) esp_periph库 _aw2013_init (periph_aw2013.c) aw2013_init (aw2013.c) aw2013_reset (aw2013.c) I2C总线 AW2013芯片 periph_aw2013_init(aw2013_cfg) esp_periph_create(PERIPH_ID_AW2013, "periph_aw2013") periph 分配 periph_aw2013_t 结构体 设置 mode、bright、rgb_value 等参数 esp_periph_set_data(periph, aw2013) esp_periph_set_function(periph, _aw2013_init, NULL, _aw2013_destroy) periph 当外设被添加到外设集合并启动时 _aw2013_init(self) esp_periph_get_data(self) aw2013 aw2013_init() 初始化 I2C 配置 get_i2c_pins(AW2013_I2C_PORT, &config) i2c_bus_create(AW2013_I2C_PORT, &config) i2c_handle aw2013_reset() 检查 I2C 句柄是否有效 写入复位寄存器 (AW2013_REG_RESET) 发送复位命令 确认复位 写入全局控制寄存器 (AW2013_REG_GCR) 设置值 0x01 (启用芯片) 确认写入 写入 LED 控制寄存器 (AW2013_REG_LCTR) 设置值 0x07 (启用所有 LED 通道) 确认写入 aw2013_set_brightness(1) 返回复位结果 错误处理 返回初始化结果 aw2013_ch_disable(aw2013->>handle, AW2013_CH_ALL) aw2013_leds_duty(aw2013->>handle, 0, AW2013_CH_ALL) aw2013_set_time(i, time[i]) (循环) aw2013_set_repeat_time(rpt_time) aw2013_set_brightness(bright) _aw2013_set_mode(mode) aw2013_set_pwm_value(rgb_value) 返回初始化结果 应用程序 periph_aw2013_init (periph_aw2013.c) esp_periph库 _aw2013_init (periph_aw2013.c) aw2013_init (aw2013.c) aw2013_reset (aw2013.c) I2C总线 AW2013芯片
总结

AW2013 外设的初始化过程涉及多个层次的组件交互,包括外设层和底层驱动层。初始化完成后,AW2013 外设可以通过不同的工作模式实现 LED 的常亮、呼吸灯和自动闪烁效果。整个初始化流程设计合理,各组件职责明确,便于维护和扩展。

AW2013 外设销毁流程

AW2013 外设的销毁流程同样涉及外设层(Peripheral Layer)和底层驱动层(Driver Layer)两个层次。销毁过程主要负责释放资源和清理内存。下面分别介绍这两个层次的销毁过程。

外设层销毁过程(periph_aw2013.c)

外设层销毁主要通过 _aw2013_destroy 函数(位于 periph_aw2013.c)完成,这个函数在外设被移除或者被停止时由 ESP 外设框架调用。根据实际源码,该函数主要包括以下步骤:

  1. 获取外设数据:从外设句柄中获取之前存储的 periph_aw2013_t 结构体。
  2. 调用底层驱动销毁:调用 aw2013_deinit 函数释放底层资源。
  3. 释放内存:释放 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)完成,主要包括以下步骤:

  1. 复位芯片:向 AW2013 芯片的复位寄存器写入复位值,使其回到默认状态。
  2. 释放 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, &reg_addr, 1, &reg_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 外设从停止到完全释放资源的销毁流程:

esp_periph库 _aw2013_destroy (periph_aw2013.c) aw2013_deinit (aw2013.c) I2C总线 AW2013芯片 外设被停止或移除 _aw2013_destroy(self) esp_periph_get_data(self) aw2013 aw2013_deinit() 检查 I2C 句柄是否有效 写入复位寄存器 (AW2013_REG_RESET) 发送复位命令 确认复位 返回操作结果 i2c_bus_delete(i2c_handle) 释放 I2C 总线资源 返回操作结果 返回操作结果 audio_free(aw2013) 释放外设数据结构内存 返回销毁结果 esp_periph库 _aw2013_destroy (periph_aw2013.c) aw2013_deinit (aw2013.c) I2C总线 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_startesp_periph_stop 等)来管理 AW2013 外设的生命周期。

AW2013 外设控制接口

虽然没有事件处理机制,但 AW2013 外设提供了丰富的控制接口,允许应用程序灵活地控制 LED 显示效果:

  1. 设置 RGB 值:通过 periph_aw2013_set_rgb_value 函数设置 LED 的颜色。

    esp_err_t periph_aw2013_set_rgb_value(esp_periph_handle_t periph, uint32_t value);
    
  2. 设置工作模式:通过 periph_aw2013_set_mode 函数设置 LED 的工作模式(常亮、呼吸或闪烁)。

    esp_err_t periph_aw2013_set_mode(esp_periph_handle_t periph, periph_aw2013_mode_t mode);
    
  3. 设置亮度:通过 periph_aw2013_set_brightless 函数设置 LED 的亮度级别。

    esp_err_t periph_aw2013_set_brightless(esp_periph_handle_t periph, aw2013_brightness_t bright);
    
  4. 设置时间参数:通过 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);
    
  5. 设置重复次数:通过 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 应用中实现视觉反馈的理想选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

omnibots

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值