当前位置: 首页 > news >正文

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

目录

  • ESP-ADF外设子系统深度解析:esp_peripherals组件架构与核心设计(显示输出类外设之IS31FL3216)
    • 简介
    • 模块概述
      • 功能定义
      • 架构位置
      • 核心特性
    • IS31FL3216外设分析
      • IS31FL3216外设概述
        • IS31FL3216外设层次架构图
      • IS31FL3216外设API和数据结构
        • 外设层API
          • 公共API
        • 内部数据结构
        • 底层驱动API
          • 公开API (IS31FL3216.h)
      • IS31FL3216外设工作模式
      • IS31FL3216外设配置选项
        • 外设层配置选项
        • 底层驱动配置选项
      • IS31FL3216外设初始化分析
        • 初始化流程概述
        • 外设层初始化过程(periph_is31fl3216.c)
          • 辅助函数详解
            • is31_leds_duty
            • is31fl3216_write_reg
            • is31fl3216_ch_disable
            • is31fl3216_ch_duty_set
            • is31fl3218S_channel_duty_by_bits
            • is31fl3216_update_reg
        • 底层驱动初始化过程(IS31FL3216.c)
          • 辅助函数详解
            • is31fl3216_power
            • is31fl3216_cur_mode_set
            • is31fl3216_cur_value_set
        • 运行任务创建与状态管理
          • 辅助函数
            • is31_leds_ctrl
            • is31fl3216_ch_enable
        • 状态切换处理
          • 辅助函数
            • is31fl3216_work_mode_set
        • is31fl3216_sample_rate_set
            • is31fl3216_frame_value_set
            • is31fl3216_first_frame_set
        • IS31FL3216外设完整初始化时序图
        • 总结
      • IS31FL3216外设销毁流程分析
        • 销毁流程概述
        • 外设层销毁过程(periph_is31fl3216.c)
        • 底层驱动销毁过程(IS31FL3216.c)
        • 完整销毁时序图
        • 总结
      • IS31FL3216外设事件处理机制
        • 事件类型与消息结构
        • 事件发送机制
        • 事件处理流程
        • 状态机实现
        • 状态控制与参数配置接口
          • 状态控制接口
          • 参数配置接口
        • 事件处理时序图
        • 总结
      • 典型示例
      • 常用参数和配置
        • LED通道模式(用于`periph_is31fl3216_set_blink_pattern`)
        • LED工作状态(用于`periph_is31fl3216_set_state`)
        • 移位模式(用于`periph_is31fl3216_set_shift_mode`)
      • 常见应用场景

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

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

IS31FL3216外设分析

IS31FL3216外设概述

IS31FL3216 是一款 16 通道 LED 驱动芯片,通过 I2C 总线控制,支持 PWM 调光、自动帧播放和音频调制等多种工作模式。在 ESP-ADF 框架中,IS31FL3216 外设被封装为三个层次:

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

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

    • 头文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.h
    • 实现文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.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+ 实现)

IS31FL3216 芯片具有以下主要特性:

  • 16 通道 LED 驱动,每通道最大 60mA 驱动电流
  • 8 位 PWM 调光控制(256 级亮度)
  • 多种工作模式:PWM 控制、自动帧播放、音频调制
  • 支持音频信号调制 LED 亮度,内置 AGC 和增益控制
  • 级联模式支持多芯片扩展
  • 通过 I2C 总线控制(400kHz)
IS31FL3216外设层次架构图
总线层 i2c_bus.c/v2.c
底层驱动层 IS31FL3216.c
外设层 periph_is31fl3216.c
调用
调用
设置
设置
设置
调用
调用
调用
调用
初始化
控制
更新
调用
调用
调用
初始化
写入
写入
访问
访问
发送
通知
I2C总线初始化
I2C总线传输
寄存器配置
is31fl3216_init
PWM寄存器
is31fl3216_ch_duty_set
UPDATE寄存器
is31fl3216_update_reg
i2c_bus_create
i2c_bus_write_bytes
i2c_bus_write_data
_is31fl3216_init
periph_is31fl3216_init
_is31fl3216_run
_is31fl3216_destroy
ESP-ADF应用
esp_periph_create
is31fl3216_deinit
ESP32 I2C硬件
ESP-ADF事件系统

IS31FL3216外设API和数据结构

外设层API

源文件components/esp_peripherals/include/periph_is31fl3216.hcomponents/esp_peripherals/periph_is31fl3216.c

公共API
// IS31FL3216通道数量常量
#define IS31FL3216_CH_NUM 16   // 应小于等于16
#define BLUE_LED_MAX_NUM  12// IS31FL3216状态枚举
typedef enum {IS31FL3216_STATE_UNKNOWN,   // 未知状态IS31FL3216_STATE_OFF,       // 关闭状态IS31FL3216_STATE_ON,        // 开启状态IS31FL3216_STATE_FLASH,     // 闪烁状态IS31FL3216_STATE_BY_AUDIO,  // 音频调制状态IS31FL3216_STATE_SHIFT,     // 移位状态
} periph_is31fl3216_state_t;// 移位模式枚举
typedef enum {PERIPH_IS31_SHIFT_MODE_UNKNOWN,PERIPH_IS31_SHIFT_MODE_ACC,     // 累积模式PERIPH_IS31_SHIFT_MODE_SINGLE,  // 单通道模式
} periph_is31_shift_mode_t;// IS31FL3216配置结构体
typedef struct {uint32_t duty[IS31FL3216_CH_NUM];    // 各通道占空比数组uint16_t is31fl3216_pattern;         // 当前启用的通道periph_is31fl3216_state_t state;     // 所有通道的状态
} periph_is31fl3216_cfg_t;// 初始化IS31FL3216外设
esp_periph_handle_t periph_is31fl3216_init(periph_is31fl3216_cfg_t *is31fl3216_config);// 设置所有通道的状态
esp_err_t periph_is31fl3216_set_state(esp_periph_handle_t periph, periph_is31fl3216_state_t state);// 设置闪烁模式的通道模式
esp_err_t periph_is31fl3216_set_blink_pattern(esp_periph_handle_t periph, uint16_t blink_pattern);// 设置指定通道的占空比
esp_err_t periph_is31fl3216_set_duty(esp_periph_handle_t periph, uint8_t index, uint8_t value);// 设置闪烁模式的步进值
esp_err_t periph_is31fl3216_set_duty_step(esp_periph_handle_t periph, uint8_t step);// 设置时间间隔
esp_err_t periph_is31fl3216_set_interval(esp_periph_handle_t periph, uint16_t interval_ms);// 设置移位模式
esp_err_t periph_is31fl3216_set_shift_mode(esp_periph_handle_t periph, periph_is31_shift_mode_t mode);// 设置点亮的LED数量
esp_err_t periph_is31fl3216_set_light_on_num(esp_periph_handle_t periph, uint16_t light_on_num, uint16_t max_light_num);// 设置动作时间
esp_err_t periph_is31fl3216_set_act_time(esp_periph_handle_t periph, uint16_t act_ms);
内部数据结构
// 重要宏定义
#define IS31FL3216_TASK_STACK_SIZE  (2048 + 1024)  // IS31FL3216任务栈大小
#define IS31FL3216_TASK_PRIORITY    3              // IS31FL3216任务优先级
#define ONE_FRAME_BYTE_SIZE         18             // 帧大小
#define DEFAULT_FLASH_STEP          2              // 默认闪烁步进
#define DESTROY_BIT                 BIT0           // 销毁位// 命令类型枚举
typedef enum {PERIPH_IS31_CMD_CHG_STATE,                     // 改变状态命令PERIPH_IS31_CMD_QUIT,                          // 退出命令
} periph_is31_cmd_t;// IS31FL3216参数结构体
typedef struct {uint16_t                    max_light_num;     // 最大灯数uint16_t                    light_num;         // 工作灯数uint16_t                    light_mask;        // 灯位掩码int                         interval_time;     // 间隔工作时间uint16_t                    act_time;          // 动作时间uint8_t                     duty_step;         // 占空比步进periph_is31_shift_mode_t    shift_mode;        // 移位模式
} periph_is31_arg_t;// IS31FL3216外设内部结构体
typedef struct {periph_is31_arg_t           *arg;              // IS31FL3216参数uint8_t                     duty[IS31FL3216_CH_NUM];    // 各通道占空比is31fl3216_handle_t         handle;            // 底层驱动句柄periph_is31fl3216_state_t   cur_state;         // 当前状态QueueHandle_t               evt;               // 事件队列EventGroupHandle_t          g_event_bit;       // 事件位组
} periph_is31fl3216_t;// IS31FL3216消息结构体
typedef struct {periph_is31_cmd_t   type;                       // 命令类型uint32_t            data;                      // 命令数据
} periph_is31_msg_t;// 音频帧数据
static const uint8_t light_audio_frames[8][ONE_FRAME_BYTE_SIZE] = {{0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},{0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},{0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},{0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff},{0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xff, 0xff},{0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xff, 0xff, 0xff},{0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xff, 0xff, 0xff},{0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xff, 0xFF, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
};// 验证宏
#define VALIDATE_IS31FL3216(periph, ret) if (!(periph && esp_periph_get_id(periph) == PERIPH_ID_IS31FL3216)) { \ESP_LOGE(TAG, "Invalid is31fl3216 periph, at line %d", __LINE__);\return ret;\
}
底层驱动API

源文件components/esp_peripherals/lib/IS31FL3216/IS31FL3216.hcomponents/esp_peripherals/lib/IS31FL3216/IS31FL3216.c

公开API (IS31FL3216.h)
// 宏定义
#define IS31FL3216_CH_NUM_MAX 16 // 最大通道数
#define IS31FL3216_DUTY_MAX   255 // 最大占空比// 电源模式枚举
typedef enum {IS31FL3216_PWR_NORMAL = 0,         // 正常工作模式IS31FL3216_PWR_SHUTDOWN,           // 软件关断模式IS31FL3216_PWR_MAX,
} is31fl3216_pwr_t;// 工作模式枚举
typedef enum {IS31FL3216_MODE_PWM = 0,           // PWM控制模式IS31FL3216_MODE_AUTO_FRAME,        // 自动帧播放模式IS31FL3216_MODE_FRAME,             // 音频帧模式IS31FL3216_MODE_MAX,
} is31fl3216_work_mode_t;// 电流模式枚举
typedef enum {IS31FL3216_CUR_MODE_REXT = 0,      // 输出电流由寄存器设置IS31FL3216_CUR_MODE_AUDIO,         // 输出电流由音频信号调制IS31FL3216_CUR_MODE_MAX,
} is31fl3216_cur_mode_t;// 电流值枚举
typedef enum {IS31FL3216_CUR_1_00 = 0,           // 输出电流选择IS31FL3216_CUR_0_75,IS31FL3216_CUR_0_50,IS31FL3216_CUR_0_25,IS31FL3216_CUR_2_00,IS31FL3216_CUR_1_75,IS31FL3216_CUR_1_50,IS31FL3216_CUR_1_25,IS31FL3216_CUR_MAX,
} is31fl3216_cur_value_t;// 级联模式枚举
typedef enum {IS31FL3216_CASCADE_MASTER = 0,     // 主机模式IS31FL3216_CASCADE_SLAVE,          // 从机模式
} is31fl3216_cascade_mode_t;// 音频增益枚举
typedef enum {IS31FL3216_AGS_0DB = 0,            // 音频增益选择IS31FL3216_AGS_3DB,IS31FL3216_AGS_6DB,IS31FL3216_AGS_9DB,IS31FL3216_AGS_12DB,IS31FL3216_AGS_15DB,IS31FL3216_AGS_18DB,IS31FL3216_AGS_21DB,IS31FL3216_AGS_MAX,
} is31fl3216_ags_value_t;// 帧延时时间枚举
typedef enum {IS31FL3216_TIME_32MS = 0,          // 帧延时时间IS31FL3216_TIME_64MS,IS31FL3216_TIME_128MS,IS31FL3216_TIME_256MS,IS31FL3216_TIME_512MS,IS31FL3216_TIME_1024MS,IS31FL3216_TIME_2048MS,IS31FL3216_TIME_4096MS,IS31FL3216_TIME_MAX,
} is31fl3216_delay_time_t;// 寄存器地址枚举
typedef enum {IS31FL3216_REG_CONFIG      = 0x00,   // 配置寄存器IS31FL3216_REG_LED_CTRL_H  = 0x01,   // LED控制寄存器 OUT9-OUT16 使能位IS31FL3216_REG_LED_CTRL_L  = 0x02,   // LED控制寄存器 OUT1-OUT8 使能位IS31FL3216_REG_LED_EFFECT  = 0x03,   // 设置输出电流和音频增益IS31FL3216_REG_CH_CONFIG   = 0x04,   // 设置OUT9~OUT16的工作模式IS31FL3216_REG_GPIO_CONFIG = 0x05,   // 设置OUT9~OUT16作为GPIO端口的工作模式IS31FL3216_REG_OUTPUT      = 0x06,   // 设置OUT9~OUT16作为输出端口的逻辑电平IS31FL3216_REG_INPUT_CTRL  = 0x07,   // 设置OUT9~OUT16的中断功能IS31FL3216_REG_STATE       = 0x08,   // 存储OUT9~OUT16作为输入端口的状态IS31FL3216_REG_ADC_RATE    = 0x09,   // 设置输入信号的ADC采样率IS31FL3216_REG_PWM_16      = 0x10,   // 设置PWM占空比数据IS31FL3216_REG_PWM_15,IS31FL3216_REG_PWM_14,IS31FL3216_REG_PWM_13,IS31FL3216_REG_PWM_12,IS31FL3216_REG_PWM_11,IS31FL3216_REG_PWM_10,IS31FL3216_REG_PWM_09,IS31FL3216_REG_PWM_08,IS31FL3216_REG_PWM_07,IS31FL3216_REG_PWM_06,IS31FL3216_REG_PWM_05,IS31FL3216_REG_PWM_04,IS31FL3216_REG_PWM_03,IS31FL3216_REG_PWM_02,IS31FL3216_REG_PWM_01,IS31FL3216_REG_FRAME1_CTRL = 0x20,  // 存储8帧数据IS31FL3216_REG_FRAME1_PWM  = 0x22,IS31FL3216_REG_FRAME2_CTRL = 0x32,IS31FL3216_REG_FRAME2_PWM  = 0x34,IS31FL3216_REG_FRAME3_CTRL = 0x44,IS31FL3216_REG_FRAME3_PWM  = 0x46,IS31FL3216_REG_FRAME4_CTRL = 0x56,IS31FL3216_REG_FRAME4_PWM  = 0x58,IS31FL3216_REG_FRAME5_CTRL = 0x68,IS31FL3216_REG_FRAME5_PWM  = 0x6A,IS31FL3216_REG_FRAME6_CTRL = 0x7A,IS31FL3216_REG_FRAME6_PWM  = 0x7C,IS31FL3216_REG_FRAME7_CTRL = 0x8C,IS31FL3216_REG_FRAME7_PWM  = 0x8E,IS31FL3216_REG_FRAME8_CTRL = 0x9E,IS31FL3216_REG_FRAME8_PWM  = 0xA0,IS31FL3216_REG_UPDATE      = 0xB0,  // 加载PWM寄存器数据IS31FL3216_REG_FRAME_DELAY = 0xB6,  // 设置每帧之间的延迟时间IS31FL3216_REG_FRAME_START = 0xB7,  // 设置自动帧播放模式的起始帧IS31FL3216_REG_MAX,
} is31fl3216_reg_t;// 通道枚举
typedef enum {IS31FL3216_CH_1   = 0x0001,        // 通道位掩码IS31FL3216_CH_2   = 0x0002,IS31FL3216_CH_3   = 0x0004,IS31FL3216_CH_4   = 0x0008,IS31FL3216_CH_5   = 0x0010,IS31FL3216_CH_6   = 0x0020,IS31FL3216_CH_7   = 0x0040,IS31FL3216_CH_8   = 0x0080,IS31FL3216_CH_9   = 0x0100,IS31FL3216_CH_10  = 0x0200,IS31FL3216_CH_11  = 0x0400,IS31FL3216_CH_12  = 0x0800,IS31FL3216_CH_13  = 0x1000,IS31FL3216_CH_14  = 0x2000,IS31FL3216_CH_15  = 0x4000,IS31FL3216_CH_16  = 0x8000,IS31FL3216_CH_ALL = 0xFFFF,
} is31_pwm_channel_t;// 驱动句柄
typedef void *is31fl3216_handle_t;// 设置电源模式
esp_err_t is31fl3216_power(is31fl3216_handle_t handle, is31fl3216_pwr_t mode);// 设置通道占空比
esp_err_t is31fl3216_ch_duty_set(is31fl3216_handle_t handle, is31_pwm_channel_t ch_bits, uint8_t duty);// 设置工作模式
esp_err_t is31fl3216_work_mode_set(is31fl3216_handle_t handle, is31fl3216_work_mode_t mode);// 启用通道
esp_err_t is31fl3216_ch_enable(is31fl3216_handle_t handle, is31_pwm_channel_t ch_bits);// 禁用通道
esp_err_t is31fl3216_ch_disable(is31fl3216_handle_t handle, is31_pwm_channel_t ch_bits);// 设置电流模式
esp_err_t is31fl3216_cur_mode_set(is31fl3216_handle_t handle, is31fl3216_cur_mode_t mode);// 设置电流值
esp_err_t is31fl3216_cur_value_set(is31fl3216_handle_t handle, is31fl3216_cur_value_t value);// 设置音频增益
esp_err_t is31fl3216_ags_value_set(is31fl3216_handle_t handle, is31fl3216_ags_value_t value);// 配置自动增益控制
esp_err_t is31fl3216_agc_cfg(is31fl3216_handle_t handle, uint32_t en);// 设置级联模式
esp_err_t is31fl3216_cascade_mode_set(is31fl3216_handle_t handle, is31fl3216_cascade_mode_t mode);// 更新寄存器
esp_err_t is31fl3216_update_reg(is31fl3216_handle_t handle);// 设置采样率
esp_err_t is31fl3216_sample_rate_set(is31fl3216_handle_t handle, uint32_t value);// 设置帧时间
esp_err_t is31fl3216_frame_time_set(is31fl3216_handle_t handle, is31fl3216_delay_time_t time);// 设置起始帧
esp_err_t is31fl3216_first_frame_set(is31fl3216_handle_t handle, uint32_t frame);// 设置帧数据
esp_err_t is31fl3216_frame_value_set(is31fl3216_handle_t handle, uint32_t num, uint8_t *data, uint32_t len);// 复位芯片
esp_err_t is31fl3216_reset(is31fl3216_handle_t handle);// 初始化驱动
is31fl3216_handle_t is31fl3216_init(void);// 释放驱动
esp_err_t is31fl3216_deinit(is31fl3216_handle_t handle);

IS31FL3216外设工作模式

IS31FL3216 支持多种工作模式,可以通过外设层的 periph_is31fl3216_set_state 函数进行设置:

  1. 常亮模式 (IS31FL3216_STATE_ON)

    • 所有配置的 LED 通道以固定亮度常亮
    • 亮度通过 periph_is31fl3216_set_duty 设置
    • 底层驱动使用 PWM 模式
  2. 闪烁模式 (IS31FL3216_STATE_FLASH)

    • LED 通道按照设定的间隔和步进值闪烁
    • 间隔通过 periph_is31fl3216_set_interval 设置
    • 步进值通过 periph_is31fl3216_set_duty_step 设置
    • 闪烁模式通过 periph_is31fl3216_set_blink_pattern 设置
  3. 音频调制模式 (IS31FL3216_STATE_BY_AUDIO)

    • LED 亮度随音频信号变化
    • 底层使用 IS31FL3216 的音频帧模式
    • 预设了 8 个音频响应帧
    • 内置 AGC 和增益控制
  4. 移位模式 (IS31FL3216_STATE_SHIFT)

    • LED 按照设定的模式和速度移位点亮
    • 支持累积模式和单通道模式
    • 通过 periph_is31fl3216_set_shift_mode 设置模式
    • 通过 periph_is31fl3216_set_light_on_num 设置点亮数量
    • 通过 periph_is31fl3216_set_interval 设置移位速度
  5. 关闭模式 (IS31FL3216_STATE_OFF)

    • 关闭所有 LED 通道
    • 底层驱动使用 is31fl3216_ch_disable 禁用所有通道

IS31FL3216外设配置选项

外设层配置选项
  • duty[IS31FL3216_CH_NUM]: 各通道的初始占空比,范围为0-255
  • is31fl3216_pattern: 指定要使用的LED通道模式,使用位标识表示,如IS31FL3216_CH_ALL表示所有通道
  • state: 初始工作状态,可以是常亮、闪烁、音频调制、移位或关闭模式
底层驱动配置选项
  • 电源模式: 可以设置为正常工作模式或软件关闭模式
  • 工作模式: 可以设置为 PWM 控制模式、自动帧播放模式或音频帧模式
  • 电流模式: 可以设置为寄存器控制或音频信号调制
  • 电流值: 设置输出电流大小,范围从 0.25 倍到 2.00 倍
  • 音频增益: 设置音频信号的增益,范围从 0dB 到 21dB
  • 自动增益控制: 可以启用或禁用自动增益控制
  • 级联模式: 可以设置为主机模式或从机模式
  • 帧时间: 设置自动帧播放模式下的帧间隔,范围从 32ms 到 4096ms

注意:外设层的 API 已经封装了底层驱动的复杂性,应用程序只需要使用外设层的 API 即可实现大部分功能。如果需要更精细的控制,可以直接使用底层驱动的 API。

IS31FL3216外设初始化分析

初始化流程概述

IS31FL3216外设的初始化流程涉及两个层次:外设层(Peripheral Layer)和底层驱动(Driver Layer)。外设层负责创建外设句柄、分配内存、设置配置参数和注册回调函数;底层驱动层负责配置I2C总线、设置设备地址、初始化寄存器和配置工作模式。

外设层初始化过程(periph_is31fl3216.c)

外设层初始化主要通过periph_is31fl3216_init函数(位于periph_is31fl3216.c)完成,主要包括以下步骤:

  1. 创建外设句柄:调用esp_periph_create函数创建外设句柄
  2. 分配内部数据结构:分配periph_is31fl3216_t结构体内存
  3. 创建事件组和队列:用于任务间通信和同步
  4. 设置配置参数:设置默认参数和LED通道占空比
  5. 初始化底层驱动:调用is31fl3216_init函数初始化底层驱动
  6. 注册回调函数:设置初始化和销毁回调函数
// 文件:components/esp_peripherals/periph_is31fl3216.c
esp_periph_handle_t periph_is31fl3216_init(periph_is31fl3216_cfg_t *is31fl3216_config)
{// 1. 创建外设句柄esp_periph_handle_t periph = esp_periph_create(PERIPH_ID_IS31FL3216, "periph_is31fl3216");AUDIO_MEM_CHECK(TAG, periph, return NULL);// 2. 分配内部数据结构periph_is31fl3216_t *is31fl3216 = audio_calloc(1, sizeof(periph_is31fl3216_t));AUDIO_MEM_CHECK(TAG, is31fl3216, {audio_free(periph);return NULL;});// 3. 创建事件组和队列is31fl3216->g_event_bit = xEventGroupCreate();AUDIO_NULL_CHECK(TAG, is31fl3216->g_event_bit, {audio_free(periph);audio_free(is31fl3216);});is31fl3216->evt = xQueueCreate(2, sizeof(periph_is31_msg_t));AUDIO_MEM_CHECK(TAG, is31fl3216->evt, {audio_free(periph);vEventGroupDelete(is31fl3216->g_event_bit);audio_free(is31fl3216);return NULL;});// 分配参数结构体内存is31fl3216->arg = audio_calloc(1, sizeof(periph_is31_arg_t));AUDIO_MEM_CHECK(TAG, is31fl3216->arg, {vQueueDelete(is31fl3216->evt);vEventGroupDelete(is31fl3216->g_event_bit);audio_free(periph);audio_free(is31fl3216);return NULL;});// 4. 设置配置参数is31fl3216->arg->max_light_num = IS31FL3216_CH_NUM;is31fl3216->arg->light_num = 0;is31fl3216->arg->light_mask = 0;is31fl3216->arg->interval_time = 1000;is31fl3216->arg->act_time = 0;is31fl3216->arg->duty_step = DEFAULT_FLASH_STEP;is31fl3216->arg->shift_mode = PERIPH_IS31_SHIFT_MODE_ACC;// 设置每个通道的占空比for (int i = 0; i < IS31FL3216_CH_NUM; i++) {is31fl3216->duty[i] = is31fl3216_config->duty[i];}// 5. 初始化底层驱动is31fl3216->handle = is31fl3216_init();AUDIO_MEM_CHECK(TAG, is31fl3216, {audio_free(is31fl3216->arg);vQueueDelete(is31fl3216->evt);audio_free(periph);vEventGroupDelete(is31fl3216->g_event_bit);audio_free(is31fl3216);return NULL;});// 6. 注册回调函数esp_periph_set_data(periph, is31fl3216);esp_periph_set_function(periph, _is31fl3216_init, NULL, _is31fl3216_destroy);return periph;
}

当外设被添加到外设集合并启动时,会调用_is31fl3216_init函数(位于periph_is31fl3216.c),该函数负责禁用所有LED通道、设置占空比为0,并创建运行任务:

// 文件:components/esp_peripherals/periph_is31fl3216.c
static esp_err_t _is31fl3216_init(esp_periph_handle_t self)
{// 获取IS31FL3216外设数据periph_is31fl3216_t *is31fl3216 = esp_periph_get_data(self);esp_err_t ret = ESP_OK;// 禁用所有LED通道is31fl3216_ch_disable(is31fl3216->handle, IS31FL3216_CH_ALL);// 设置所有通道占空比为0is31_leds_duty(is31fl3216->handle, 0, IS31FL3216_CH_ALL);// 创建运行任务xTaskCreate(is31fl3216_run_task, "is31fl3216_run_task", IS31FL3216_TASK_STACK_SIZE, (void *)self, IS31FL3216_TASK_PRIORITY, NULL);if (ret) {ESP_LOGE(TAG, "Failed to initialize is31fl3216");return ESP_FAIL;}return ESP_OK;
}
辅助函数详解
is31_leds_duty
// 文件:components/esp_peripherals/periph_is31fl3216.c
static esp_err_t is31_leds_duty(is31fl3216_handle_t *handle, int duty, uint16_t mask)
{esp_err_t ret = ESP_OK;// 遍历所有LED通道(16个)for (int i = 0; i < IS31FL3216_CH_NUM; i++) {// 检查当前通道是否在掩码中被选中if (mask & (1UL << i))// 设置选中通道的占空比ret |= is31fl3216_ch_duty_set(handle, 1UL << i, duty);}return ret;
}

该函数用于设置多个LED通道的亮度值。通过掩码(mask)参数选择要设置的通道,并将这些通道的占空比(duty)设置为相同的值。在初始化过程中,该函数用于将所有LED通道的亮度设置为0,即关闭所有LED。

is31fl3216_write_reg
// 文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.c
static esp_err_t is31fl3216_write_reg(is31fl3216_handle_t handle, is31fl3216_reg_t regAddr, uint8_t *data, uint8_t data_num)
{// 参数检查IS31_PARAM_CHECK(NULL != data);// 获取设备结构体is31fl3216_dev_t *dev = (is31fl3216_dev_t *) handle;// 通过I2C总线写入寄存器// IS31FL3216_ADDRESS: 设备地址(0xE8)// IS31FL3216_WRITE_BIT: 写操作位(0)// regAddr: 目标寄存器地址// data: 要写入的数据// data_num: 数据字节数esp_err_t ret = i2c_bus_write_bytes(dev->bus, IS31FL3216_ADDRESS | IS31FL3216_WRITE_BIT, (uint8_t *)&regAddr, 1, data, data_num);return ret;
}

该函数是底层I2C通信的封装,用于向IS31FL3216芯片的指定寄存器写入数据。所有的配置操作最终都调用此函数来实现与IS31FL3216芯片的通信。

is31fl3216_ch_disable
// 文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.c
esp_err_t is31fl3216_ch_disable(is31fl3216_handle_t handle, is31_pwm_channel_t ch_bits)
{// 初始化返回值esp_err_t ret = ESP_OK;// 参数检查IS31_PARAM_CHECK(NULL != handle);// 获取当前的LED控制寄存器值// 将高字节寄存器值左移8位,然后与低字节寄存器值合并uint16_t value = ((uint16_t)Is31Value[IS31FL3216_REG_LED_CTRL_H]) << 8;value |= Is31Value[IS31FL3216_REG_LED_CTRL_L];// 遍历所有通道,将需要禁用的通道对应的位置0for (int i = 0; i < IS31FL3216_CH_NUM_MAX; ++i) {if ((ch_bits >> i) & 0x01) {// 将对应位清零,表示禁用该通道value = value & (~(1 << i));}}// 将新的值分别存入高低字节寄存器Is31Value[IS31FL3216_REG_LED_CTRL_H] = value >> 8;Is31Value[IS31FL3216_REG_LED_CTRL_L] = value;// 写入寄存器,从高字节开始写入2个字节ret = is31fl3216_write_reg(handle, IS31FL3216_REG_LED_CTRL_H, &Is31Value[IS31FL3216_REG_LED_CTRL_H], 2);return ret;
}

该函数用于禁用指定的LED通道。通过位操作将LED控制寄存器中对应的位置0,从而关闭指定的LED通道。该函数与is31fl3216_ch_enable函数功能相反,在需要关闭某些LED通道时使用。

is31fl3216_ch_duty_set
// 文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.c
esp_err_t is31fl3216_ch_duty_set(is31fl3216_handle_t handle, is31_pwm_channel_t ch_bits, uint8_t duty)
{// 初始化返回值esp_err_t ret = ESP_OK;// 参数检查IS31_PARAM_CHECK(NULL != handle);// 调用辅助函数设置指定通道的PWM占空比ret = is31fl3218S_channel_duty_by_bits(handle, ch_bits, duty);if (ret != ESP_OK) {IS31_CHECK_I2C_RES(ret);return ret;}// 更新寄存器,使设置生效ret = is31fl3216_update_reg(handle);if (ret != ESP_OK) {IS31_CHECK_I2C_RES(ret);return ret;}return ESP_OK;
}

该函数用于设置指定通道的PWM占空比,从而控制LED的亮度。函数先调用is31fl3218S_channel_duty_by_bits设置具体的PWM值,然后调用is31fl3216_update_reg使设置生效。该函数是LED亮度控制的核心函数之一。

is31fl3218S_channel_duty_by_bits
// 文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.c
static esp_err_t is31fl3218S_channel_duty_by_bits(is31fl3216_handle_t handle, uint32_t by_bits, uint8_t duty)
{// 遍历所有可能的LED通道for (int i = 0; i < IS31FL3216_CH_NUM_MAX; i++) {// 检查当前通道是否在指定的位掩码中if ((by_bits >> i) & 0x1) {// 写入PWM寄存器,设置占空比// IS31FL3216_REG_PWM_16: PWM寄存器起始地址// IS31FL3216_CH_NUM_MAX - i - 1: 计算具体的寄存器偏移(通道号反向排列)// duty: 要设置的PWM占空比值esp_err_t ret = is31fl3216_write_reg(handle, IS31FL3216_REG_PWM_16 + (IS31FL3216_CH_NUM_MAX - i - 1), &duty, 1);if (ret == ESP_OK) {//成功则继续} else {// 失败则检查错误并返回IS31_CHECK_I2C_RES(ret);return ret;}}}return ESP_OK;
}

该函数是is31fl3216_ch_duty_set的内部辅助函数,用于设置多个通道的PWM占空比值。它通过位操作遍历by_bits参数中指定的所有通道,并将对应的PWM寄存器设置为指定的duty值。注意到IS31FL3216的寄存器映射中,通道号与寄存器偏移是反向排列的。

is31fl3216_update_reg
// 文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.c
esp_err_t is31fl3216_update_reg(is31fl3216_handle_t handle)
{// 参数检查IS31_PARAM_CHECK(NULL != handle);// 准备写入的数据(0值)uint8_t m = 0;// 写入更新寄存器,触发更新操作return is31fl3216_write_reg(handle, IS31FL3216_REG_UPDATE, &m, 1);
}

该函数用于触发IS31FL3216芯片的寄存器更新操作。根据IS31FL3216的数据手册,当写入PWM寄存器或LED控制寄存器后,需要写入更新寄存器(IS31FL3216_REG_UPDATE)来使设置生效。这是一种原子操作机制,确保所有设置同时生效,避免中间状态导致的闪烁或异常。

底层驱动初始化过程(IS31FL3216.c)

底层驱动初始化通过is31fl3216_init函数(位于IS31FL3216.c)完成,主要包括以下步骤:

  1. 配置I2C总线:设置I2C主机模式、SDA/SCL引脚、上拉电阻和时钟频率
  2. 分配驱动结构体:分配is31fl3216_dev_t结构体内存
  3. 创建I2C总线:调用i2c_bus_create函数创建I2C总线
  4. 设置设备地址:设置IS31FL3216的I2C地址(0xE8)
  5. 配置工作模式:设置正常工作模式、电流模式和电流值
// 文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.c
is31fl3216_handle_t is31fl3216_init(void)
{// 1. 配置I2C总线i2c_config_t conf = {0};conf.mode = I2C_MODE_MASTER;conf.sda_io_num = I2C_MASTER_SDA_IO;        // SDA引脚 = 18conf.sda_pullup_en = GPIO_PULLUP_ENABLE;conf.scl_io_num = I2C_MASTER_SCL_IO;        // SCL引脚 = 23conf.scl_pullup_en = GPIO_PULLUP_ENABLE;conf.master.clk_speed = I2C_MASTER_FREQ_HZ;  // 时钟频率 = 100kHz// 2. 分配驱动结构体is31fl3216_dev_t *led = (is31fl3216_dev_t *) audio_calloc(1, sizeof(is31fl3216_dev_t));// 3. 创建I2C总线led->bus = i2c_bus_create(I2C_MASTER_NUM, &conf);// 4. 设置设备地址led->addr = IS31FL3216_ADDRESS;  // I2C地址 = 0xE8// 5. 配置工作模式IS31_ERROR_CHECK(ESP_OK == is31fl3216_power(led, IS31FL3216_PWR_NORMAL));         // 设置正常工作模式IS31_ERROR_CHECK(ESP_OK == is31fl3216_cur_mode_set(led, IS31FL3216_CUR_MODE_REXT)); // 设置电流模式为外部电阻模式IS31_ERROR_CHECK(ESP_OK == is31fl3216_cur_value_set(led, IS31FL3216_CUR_0_75));     // 设置电流值为最大值的75%return (is31fl3216_handle_t) led;
}
辅助函数详解
is31fl3216_power
// 文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.c
esp_err_t is31fl3216_power(is31fl3216_handle_t handle, is31fl3216_pwr_t mode)
{// 参数检查IS31_PARAM_CHECK(NULL != handle);// 根据模式设置配置寄存器的第7位if (IS31FL3216_PWR_SHUTDOWN == mode) {// 关断模式:第7位置1Is31Value[IS31FL3216_REG_CONFIG] = (Is31Value[IS31FL3216_REG_CONFIG] & (~(1 << 7))) | (1 << 7);} else if (IS31FL3216_PWR_NORMAL == mode) {// 正常模式:第7位置0Is31Value[IS31FL3216_REG_CONFIG] = (Is31Value[IS31FL3216_REG_CONFIG] & (~(1 << 7)));} else {return ESP_FAIL;}// 写入寄存器esp_err_t ret = is31fl3216_write_reg(handle, IS31FL3216_REG_CONFIG, (uint8_t *) &Is31Value[IS31FL3216_REG_CONFIG], 1);return ret;
}

该函数通过修改配置寄存器(IS31FL3216_REG_CONFIG)的第7位来控制芯片的工作状态。在初始化时,调用此函数并设置为IS31FL3216_PWR_NORMAL,使芯片进入正常工作模式,以便驱动LED。

is31fl3216_cur_mode_set
// 文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.c
esp_err_t is31fl3216_cur_mode_set(is31fl3216_handle_t handle, is31fl3216_cur_mode_t mode)
{// 参数检查IS31_PARAM_CHECK(NULL != handle);// 根据模式设置配置寄存器的第4位if (IS31FL3216_CUR_MODE_REXT == mode) {// 外部电阻模式:第4位置0Is31Value[IS31FL3216_REG_CONFIG] = (Is31Value[IS31FL3216_REG_CONFIG] & (~(1 << 4)));} else if (IS31FL3216_CUR_MODE_AUDIO == mode) {// 音频调制模式:第4位置1Is31Value[IS31FL3216_REG_CONFIG] = (Is31Value[IS31FL3216_REG_CONFIG] & (~(1 << 4))) | (1 << 4);} else {return ESP_FAIL;}// 写入寄存器esp_err_t ret = is31fl3216_write_reg(handle, IS31FL3216_REG_CONFIG, (uint8_t *) &Is31Value[IS31FL3216_REG_CONFIG], 1);return ret;
}

该函数通过修改配置寄存器(IS31FL3216_REG_CONFIG)的第4位来控制输出电流的来源。在初始化时,调用此函数并设置为IS31FL3216_CUR_MODE_REXT,选择使用外部电阻来设置电流值,而非使用音频信号调制。

is31fl3216_cur_value_set
// 文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.c
esp_err_t is31fl3216_cur_value_set(is31fl3216_handle_t handle, is31fl3216_cur_value_t value)
{// 参数检查IS31_PARAM_CHECK(NULL != handle);// 设置LED效果寄存器的第4-6位为指定的电流值Is31Value[IS31FL3216_REG_LED_EFFECT] = (Is31Value[IS31FL3216_REG_LED_EFFECT] & (~(7 << 4))) | value << 4;// 写入寄存器esp_err_t ret = is31fl3216_write_reg(handle, IS31FL3216_REG_LED_EFFECT, &Is31Value[IS31FL3216_REG_LED_EFFECT], 1);return ret;
}

该函数通过修改LED效果寄存器(IS31FL3216_REG_LED_EFFECT)的第4-6位来设置输出电流的大小。在初始化时,调用此函数并设置为IS31FL3216_CUR_0_75,表示输出电流为最大值的75%,这个值能够提供足够的LED亮度,同时避免过大电流导致的发热和功耗问题。

运行任务创建与状态管理

_is31fl3216_init函数中,会创建一个名为is31fl3216_run_task的任务,该任务负责处理IS31FL3216的各种工作模式和状态转换:

// 文件:components/esp_peripherals/periph_is31fl3216.c
static void is31fl3216_run_task(void *Para)
{esp_periph_handle_t periph = (esp_periph_handle_t) Para;periph_is31fl3216_t *is31 = esp_periph_get_data(periph);periph_is31_arg_t is31_arg = {.max_light_num = IS31FL3216_CH_NUM,.light_num = 1,.light_mask = 1,.interval_time = 1000,.act_time = 0,.duty_step = DEFAULT_FLASH_STEP,.shift_mode = 0,};periph_is31_msg_t msg = {0};int wait_time_ms = portMAX_DELAY;bool task_run = true;// 清除销毁位xEventGroupClearBits(is31->g_event_bit, DESTROY_BIT);// 初始化变量int cur_duty = 0;int sig = 2;int cur_bits_mask = 0;int i = 0;uint16_t act_times = 0;// 任务主循环while (task_run) {// 从队列接收消息if (xQueueReceive(is31->evt, &msg, (wait_time_ms / portTICK_PERIOD_MS))) {ESP_LOGD(TAG, "cmd:%d, data:%"PRIu32, msg.type, msg.data);// 处理消息switch (msg.type) {case PERIPH_IS31_CMD_CHG_STATE:// 处理状态变更命令memcpy(&is31_arg, is31->arg, sizeof(periph_is31_arg_t));wait_time_ms = is31->arg->interval_time;memset(is31->arg, 0, sizeof(periph_is31_arg_t));is31->arg->interval_time = portMAX_DELAY;is31->arg->max_light_num = IS31FL3216_CH_NUM;is31->arg->duty_step = DEFAULT_FLASH_STEP;is31_change_state(is31, msg.data, &is31_arg);// 设置闪烁步长和动作次数if (IS31FL3216_STATE_FLASH == msg.data) {sig = is31_arg.duty_step;}if (is31_arg.act_time && wait_time_ms) {act_times = is31_arg.act_time / wait_time_ms;} else {act_times = 0;}break;case PERIPH_IS31_CMD_QUIT:// 处理退出命令task_run = false;if (is31->g_event_bit) {xEventGroupSetBits(is31->g_event_bit, DESTROY_BIT);}break;default:break;}if (task_run == false) {ESP_LOGW(TAG, "Quit is31fl3216 task ...");break;}}// 根据当前状态执行相应操作switch (is31->cur_state) {case IS31FL3216_STATE_FLASH:// 闪烁模式处理is31_leds_duty(is31->handle, cur_duty, is31_arg.light_mask);is31_leds_ctrl(is31->handle, is31_arg.light_mask);cur_duty += sig;if (cur_duty > IS31FL3216_DUTY_MAX) {cur_duty = IS31FL3216_DUTY_MAX;sig = -(is31_arg.duty_step);}if (cur_duty < 0) {cur_duty = 0;sig = (is31_arg.duty_step);}// 检查动作时间if (is31_arg.act_time == 0) {act_times = 0;break;}act_times--;if (act_times == 0) {wait_time_ms = portMAX_DELAY;is31->cur_state = IS31FL3216_STATE_UNKNOWN;is31_leds_ctrl(is31->handle, 0);}break;case IS31FL3216_STATE_SHIFT:// 移位模式处理if (is31_arg.shift_mode == PERIPH_IS31_SHIFT_MODE_SINGLE) {// 单一模式:固定数量的LED依次移动cur_bits_mask = ((1UL << is31_arg.light_num) - 1) << (i++);if (i == (is31_arg.max_light_num - is31_arg.light_num + 1)) {i = 0;}} else if (is31_arg.shift_mode == PERIPH_IS31_SHIFT_MODE_ACC) {// 累积模式:LED数量逐渐增加,然后重置cur_bits_mask = (1UL << (is31_arg.light_num * ((i++) + 1))) - 1;if ((cur_bits_mask >> is31_arg.max_light_num) & 0x01) {cur_bits_mask = 0;i = 0;}}// 设置LED亮度和控制状态is31_leds_duty(is31->handle, IS31FL3216_DUTY_MAX, cur_bits_mask);is31_leds_ctrl(is31->handle, cur_bits_mask);// 检查动作时间if (is31_arg.act_time == 0) {act_times = 0;break;}act_times--;if (act_times == 0) {wait_time_ms = portMAX_DELAY;is31->cur_state = IS31FL3216_STATE_UNKNOWN;is31_leds_ctrl(is31->handle, 0);}break;default:break;}}// 删除任务vTaskDelete(NULL);
}

is31fl3216_run_task函数是IS31FL3216外设的核心任务,负责处理不同工作模式下的LED控制逻辑。下面是该函数的时序图,展示了其工作流程和状态转换逻辑:

应用层 消息队列(is31->>evt) is31fl3216_run_task IS31FL3216驱动 初始化变量 清除销毁位(DESTROY_BIT) 初始化工作参数 等待接收消息(xQueueReceive) 返回消息(msg) 复制参数(is31_arg) 设置等待时间(wait_time_ms) 重置参数结构(is31->>arg) 调用is31_change_state()改变状态 设置闪烁步长(sig) alt [闪烁模式(IS- 31FL3216_S- TATE_FLAS- H)] 计算动作次数(act_times) task_run = false 设置销毁位(DESTROY_BIT) alt [状态变更命令(PERIPH_IS3- 1_CMD_CHG_STATE)] [退出命令(PERIPH_IS31_CM- D_QUIT)] alt [收到消息] 调用is31_leds_duty()设置亮度 调用is31_leds_ctrl()控制LED 调整亮度值(cur_duty)和方向(sig) 重置等待时间为无限大(portMAX_DELAY) 切换到未知状态(IS31FL3216_STATE_UNKNOWN) 关闭LED(is31_leds_ctrl) alt [动作时间到期(act_times = 0)] 计算移位掩码(cur_bits_mask) 计算累积掩码(cur_bits_mask) alt [单一模式(PERIPH_IS31- _SHIFT_MODE_SINGLE- )] [累积模式(PERIPH_IS31- _SHIFT_MODE_ACC)] 调用is31_leds_duty()设置最大亮度 调用is31_leds_ctrl()控制LED 重置等待时间为无限大(portMAX_DELAY) 切换到未知状态(IS31FL3216_STATE_UNKNOWN) 关闭LED(is31_leds_ctrl) alt [动作时间到期(act_times = 0)] alt [当前状态 = 闪烁模式(IS31FL3216_STATE_FLASH)] [当前状态 = 移位模式(IS31FL3216_STATE_SHIFT)] loop [任务主循环(task_run = true)] 删除任务(vTaskDelete) 应用层 消息队列(is31->>evt) is31fl3216_run_task IS31FL3216驱动

该时序图展示了is31fl3216_run_task函数的主要工作流程:

  1. 初始化阶段:设置初始参数和状态

  2. 消息处理循环

    • 从队列中接收命令消息
    • 处理状态变更命令(PERIPH_IS31_CMD_CHG_STATE)
    • 处理退出命令(PERIPH_IS31_CMD_QUIT)
  3. 状态处理

    • 闪烁模式(IS31FL3216_STATE_FLASH):通过动态调整PWM占空比实现LED亮度的渐变
    • 移位模式(IS31FL3216_STATE_SHIFT):实现LED的移位效果,支持单一模式和累积模式
  4. 超时处理:当动作时间到期时,关闭LED并切换到未知状态

通过这种设计,IS31FL3216外设能够实现多种复杂的LED灯光效果,如呼吸灯、跑马灯等。

辅助函数
is31_leds_ctrl
// 文件:components/esp_peripherals/periph_is31fl3216.c
static esp_err_t is31_leds_ctrl(is31fl3216_handle_t *handle, uint16_t mask)
{// 初始化返回值esp_err_t ret = ESP_OK;// 遍历所有LED通道for (int i = 0; i < IS31FL3216_CH_NUM; i++) {// 检查当前通道是否在掩码中被选中if (mask & (1UL << i)) {// 如果被选中,启用该通道ret |= is31fl3216_ch_enable(handle, 1UL << i);} else {// 如果未被选中,禁用该通道ret |= is31fl3216_ch_disable(handle, 1UL << i);}}return ret;
}

该函数用于控制多个LED通道的开关状态。通过掩码(mask)参数选择要启用的通道,对于掩码中置1的位启用相应的LED通道,对于置0的位禁用相应的LED通道。在闪烁和移位模式中,该函数用于控制哪些LED处于激活状态。

is31fl3216_ch_enable
// 文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.c
esp_err_t is31fl3216_ch_enable(is31fl3216_handle_t handle, is31_pwm_channel_t ch_bits)
{// 初始化返回值esp_err_t ret = ESP_OK;// 参数检查IS31_PARAM_CHECK(NULL != handle);// 初始化值变量uint16_t value = 0;// 遍历所有通道,生成控制值for (int i = 0; i < IS31FL3216_CH_NUM_MAX; ++i) {// 检查当前通道是否在指定的位掩码中if ((ch_bits >> i) & 0x01) {// 将对应位置1,表示启用该通道value |= (1 << i);}}// 更新LED控制寄存器值// 高字节寄存器保存高位通道状态Is31Value[IS31FL3216_REG_LED_CTRL_H] |= value >> 8;// 低字节寄存器保存低位通道状态Is31Value[IS31FL3216_REG_LED_CTRL_L] |= value;// 写入寄存器,从高字节开始写入2个字节ret = is31fl3216_write_reg(handle, IS31FL3216_REG_LED_CTRL_H, &Is31Value[IS31FL3216_REG_LED_CTRL_H], 2);return ret;
}

该函数用于启用指定的LED通道。与is31fl3216_ch_disable函数功能相反,该函数通过位操作将LED控制寄存器中对应的位置1,从而打开指定的LED通道。注意该函数使用按位或操作,保留原有的其他通道状态。

状态切换处理

当应用程序调用periph_is31fl3216_set_state函数改变IS31FL3216的工作状态时,会向任务队列发送状态变更命令,然后由is31_change_state函数处理状态切换:

// 文件:components/esp_peripherals/periph_is31fl3216.c
static esp_err_t is31_change_state(periph_is31fl3216_t *is31, int state, periph_is31_arg_t *arg)
{esp_err_t ret = ESP_OK;switch (state) {case IS31FL3216_STATE_OFF:// 关闭模式:禁用所有LED通道ret |= is31fl3216_ch_disable(is31->handle, arg->light_mask);arg->interval_time = portMAX_DELAY;is31->cur_state = IS31FL3216_STATE_OFF;break;case IS31FL3216_STATE_ON:// 常亮模式:如果之前是音频模式,需要切换到PWM模式if (is31->cur_state == IS31FL3216_STATE_BY_AUDIO) {ret |= is31fl3216_work_mode_set(is31->handle, IS31FL3216_MODE_PWM);is31_leds_duty(is31->handle, IS31FL3216_DUTY_MAX, arg->light_mask);}// 启用指定的LED通道is31_leds_ctrl(is31->handle, arg->light_mask);arg->interval_time = portMAX_DELAY;is31->cur_state = IS31FL3216_STATE_ON;break;case IS31FL3216_STATE_FLASH:// 闪烁模式:如果之前是音频模式,需要切换到PWM模式if (is31->cur_state == IS31FL3216_STATE_BY_AUDIO) {ret |= is31fl3216_work_mode_set(is31->handle, IS31FL3216_MODE_PWM);}is31->cur_state = IS31FL3216_STATE_FLASH;break;case IS31FL3216_STATE_SHIFT:// 移位模式:如果之前是音频模式,需要切换到PWM模式if (is31->cur_state == IS31FL3216_STATE_BY_AUDIO) {ret |= is31fl3216_work_mode_set(is31->handle, IS31FL3216_MODE_PWM);}is31->cur_state = IS31FL3216_STATE_SHIFT;break;case IS31FL3216_STATE_BY_AUDIO:// 音频响应模式:重置芯片,设置帧模式is31fl3216_reset(is31->handle);is31fl3216_work_mode_set(is31->handle, IS31FL3216_MODE_FRAME);is31fl3216_sample_rate_set(is31->handle, 0xB4); // 设置ADC采样率is31fl3216_frame_value_set(is31->handle, 1, (uint8_t *)&light_audio_frames, sizeof(light_audio_frames));is31fl3216_first_frame_set(is31->handle, 0);is31->cur_state = IS31FL3216_STATE_BY_AUDIO;arg->interval_time = portMAX_DELAY;break;default:ESP_LOGE(TAG, "State %d is not supported", state);break;}return ret;
}
IS31FL3216_STATE_OFF
IS31FL3216_STATE_ON
IS31FL3216_STATE_FLASH
IS31FL3216_STATE_SHIFT
IS31FL3216_STATE_BY_AUDIO
初始化
如果前一状态是音频模式
如果前一状态不是音频模式
如果前一状态是音频模式
如果前一状态是音频模式
关闭模式
常亮模式
闪烁模式
移位模式
音频响应模式
IS31FL3216_STATE_UNKNOWN
禁用LED
设置无限等待时间
检查前一状态
切换到PWM模式
设置最大亮度
启用LED
重置芯片
设置帧模式
设置ADC采样率
设置帧值
设置首帧

该状态图展示了IS31FL3216外设的五种主要工作状态及其之间的转换逻辑:

  1. 关闭模式(IS31FL3216_STATE_OFF):禁用指定的LED通道,设置无限等待时间

  2. 常亮模式(IS31FL3216_STATE_ON):启用指定的LED通道,并设置为最大亮度

  3. 闪烁模式(IS31FL3216_STATE_FLASH):设置闪烁模式,在运行任务中实现LED亮度的渐变

  4. 移位模式(IS31FL3216_STATE_SHIFT):设置移位模式,在运行任务中实现LED的移位效果

  5. 音频响应模式(IS31FL3216_STATE_BY_AUDIO):设置芯片为帧模式,使其能够响应音频信号

值得注意的是,当从音频响应模式切换到其他模式时,需要先将芯片切换回 PWM 模式。这是因为音频响应模式使用的是帧模式,而其他模式都基于 PWM 模式实现。

辅助函数
is31fl3216_work_mode_set
// 文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.c
esp_err_t is31fl3216_work_mode_set(is31fl3216_handle_t handle, is31fl3216_work_mode_t mode)
{// 参数检查IS31_PARAM_CHECK(NULL != handle);// 根据模式设置配置寄存器的第5-6位if (IS31FL3216_MODE_PWM == mode) {// PWM模式:第5-6位置0Is31Value[IS31FL3216_REG_CONFIG] = (Is31Value[IS31FL3216_REG_CONFIG] & (~(3 << 5)));} else if (IS31FL3216_MODE_AUTO_FRAME == mode) {// 自动帧模式:第5位置1,第6位置0Is31Value[IS31FL3216_REG_CONFIG] = (Is31Value[IS31FL3216_REG_CONFIG] & (~(3 << 5))) | (1 << 5);} else if (IS31FL3216_MODE_FRAME == mode) {// 帧模式:第5位置0,第6位置1Is31Value[IS31FL3216_REG_CONFIG] = (Is31Value[IS31FL3216_REG_CONFIG] & (~(3 << 5))) | (2 << 5);} else {return ESP_FAIL;}// 写入寄存器esp_err_t ret = is31fl3216_write_reg(handle, IS31FL3216_REG_CONFIG, (uint8_t *) &Is31Value[IS31FL3216_REG_CONFIG], 1);return ret;
}

该函数用于设置IS31FL3216芯片的工作模式。IS31FL3216支持三种工作模式:

  1. PWM模式:直接控制每个LED的PWM占空比,用于常亮、闪烁和移位模式
  2. 自动帧模式:自动播放预定义的帧序列
  3. 帧模式:响应音频信号,用于音频响应模式
is31fl3216_sample_rate_set
// 文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.c
esp_err_t is31fl3216_sample_rate_set(is31fl3216_handle_t handle, uint32_t value)
{// 参数检查IS31_PARAM_CHECK(NULL != handle);// 将值转换为字节uint8_t dat = value;// 写入ADC采样率寄存器esp_err_t ret = is31fl3216_write_reg(handle, IS31FL3216_REG_ADC_RATE, &dat, 1);return ret;
}

该函数用于设置IS31FL3216芯片的ADC采样率。在音频响应模式下,芯片需要采样外部音频信号,该函数设置采样的速率。在状态切换中,音频模式使用的值为0xB4,这是一个适合大多数音频应用的采样率。

is31fl3216_frame_value_set
// 文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.c
esp_err_t is31fl3216_frame_value_set(is31fl3216_handle_t handle, uint32_t num, uint8_t *data, uint32_t len)
{// 参数检查IS31_PARAM_CHECK(NULL != handle);IS31_PARAM_CHECK(NULL != data);// 计算帧控制寄存器的起始地址// IS31FL3216_REG_FRAME1_CTRL: 第一帧的起始地址// (num - 1) * 18: 每个帧占据18个字节,计算偏移uint8_t startAddr = IS31FL3216_REG_FRAME1_CTRL + (num - 1) * 18;// 写入帧数据esp_err_t ret = is31fl3216_write_reg(handle, startAddr, data, len);return ret;
}

该函数用于设置IS31FL3216芯片的帧数据。在帧模式或自动帧模式下,芯片可以存储多个帧,每个帧定义了16个LED通道的状态。在音频响应模式下,该函数用于设置音频响应的帧数据,定义了不同音频强度下的LED显示效果。

is31fl3216_first_frame_set
// 文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.c
esp_err_t is31fl3216_first_frame_set(is31fl3216_handle_t handle, uint32_t frame)
{// 参数检查IS31_PARAM_CHECK(NULL != handle);// 将帧编号左移5位,存入到寄存器的第5-7位uint8_t dat = frame << 5;// 写入帧起始寄存器esp_err_t ret = is31fl3216_write_reg(handle, IS31FL3216_REG_FRAME_START, &dat, 1);return ret;
}

该函数用于设置IS31FL3216芯片的起始帧。在帧模式或自动帧模式下,芯片需要知道从哪一帧开始播放。在音频响应模式下,该函数将起始帧设置为0,表示从第一帧开始响应音频信号。

IS31FL3216外设完整初始化时序图

下图展示了IS31FL3216外设从应用程序调用到底层驱动完成初始化的完整流程:

应用程序 periph_is31fl3216_init (外设层) esp_periph库 _is31fl3216_init (外设层) is31fl3216_init (底层驱动) I2C总线驱动 is31fl3216_run_task (外设层) periph_is31fl3216_init(config) esp_periph_create(PERIPH_ID_IS31FL3216, "periph_is31fl3216") periph句柄 分配 periph_is31fl3216_t 结构体 创建事件组(xEventGroupCreate) 创建消息队列(xQueueCreate) 分配参数结构体(audio_calloc) 设置默认参数(max_light_num, interval_time等) 设置各通道占空比(duty) is31fl3216_init() 配置I2C参数(mode, SDA/SCL引脚, 时钟频率) 分配 is31fl3216_dev_t 结构体 i2c_bus_create(I2C_MASTER_NUM, &conf) bus句柄 设置设备地址(0xE8) is31fl3216_power(led, IS31FL3216_PWR_NORMAL) 设置正常工作模式 is31fl3216_cur_mode_set(led, IS31FL3216_CUR_MODE_REXT) 设置外部电阻控制模式 is31fl3216_cur_value_set(led, IS31FL3216_CUR_0_75) 设置电流值为最大值的75% 返回驱动句柄(handle) esp_periph_set_data(periph, is31fl3216) esp_periph_set_function(periph, _is31fl3216_init, NULL, _is31fl3216_destroy) 返回外设句柄(periph) 当外设被添加到外设集合并启动时 _is31fl3216_init(self) esp_periph_get_data(self) 返回外设数据(is31fl3216) is31fl3216_ch_disable(handle, IS31FL3216_CH_ALL) 禁用所有LED通道 is31_leds_duty(handle, 0, IS31FL3216_CH_ALL) 设置所有通道占空比为0 xTaskCreate(is31fl3216_run_task, ...) 返回初始化结果(ESP_OK) 清除销毁位(DESTROY_BIT) 初始化参数(cur_duty, sig, cur_bits_mask等) 等待队列消息(xQueueReceive) loop [任务主循环(task_run = true)] 当应用程序调用periph_is31fl3216_set_state时 periph_is31fl3216_set_state(periph, state) 创建状态消息(PERIPH_IS31_CMD_CHG_STATE) 发送状态消息到队列(xQueueSend) 接收并处理状态消息 is31_change_state(is31, state, arg) is31fl3216_work_mode_set(handle, IS31FL3216_MODE_PWM) is31_leds_duty(handle, IS31FL3216_DUTY_MAX, mask) is31_leds_ctrl(handle, mask) is31fl3216_work_mode_set(handle, IS31FL3216_MODE_PWM) is31fl3216_work_mode_set(handle, IS31FL3216_MODE_PWM) is31fl3216_reset(handle) is31fl3216_work_mode_set(handle, IS31FL3216_MODE_FRAME) is31fl3216_sample_rate_set(handle, 0xB4) is31fl3216_frame_value_set(handle, 1, data, len) is31fl3216_first_frame_set(handle, 0) alt [常亮模式(IS31FL3216_STATE_ON)] [闪烁模式(IS31FL3216_STATE_FLASH)] [移位模式(IS31FL3216_STATE_SHIFT)] [音频响应模式(IS31FL3216_STATE_BY_AUDIO)] 应用程序 periph_is31fl3216_init (外设层) esp_periph库 _is31fl3216_init (外设层) is31fl3216_init (底层驱动) I2C总线驱动 is31fl3216_run_task (外设层)

这个时序图详细展示了IS31FL3216外设的完整生命周期,包括以下几个主要阶段:

  1. 外设初始化阶段:应用程序调用periph_is31fl3216_init创建外设句柄、分配内存、创建同步对象并初始化底层驱动

  2. 底层驱动初始化:配置I2C总线、设置芯片工作模式和电流参数

  3. 外设启动阶段:当外设被添加到外设集合并启动时,调用_is31fl3216_init函数初始化LED状态并创建运行任务

  4. 任务运行阶段is31fl3216_run_task初始化参数并进入主循环,等待队列消息

  5. 状态切换阶段:应用程序调用periph_is31fl3216_set_state发送状态变更命令,任务根据不同的状态执行相应的操作

这个完整的时序图清晰地展示了各个组件之间的交互和数据流向,有助于理解IS31FL3216外设的工作原理和实现机制。

总结

IS31FL3216外设的初始化过程涉及多个层次的组件交互,包括外设层、底层驱动、I2C总线和任务管理。初始化完成后,IS31FL3216外设可以通过状态切换实现不同的LED效果,如常亮、闪烁、移位和音频响应等。整个初始化流程设计合理,各组件职责明确,便于维护和扩展。

IS31FL3216外设销毁流程分析

销毁流程概述

IS31FL3216外设的销毁流程是初始化流程的逆过程,主要涉及资源释放、任务终止和内存回收。销毁过程同样分为外设层(Peripheral Layer)和底层驱动(Driver Layer)两个层次,确保所有在初始化时分配的资源都被正确释放,防止内存泄漏和资源占用。

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

外设层销毁主要通过_is31fl3216_destroy函数(位于periph_is31fl3216.c)完成,该函数在外设被移除时由ESP-ADF框架调用。主要步骤包括:

  1. 验证参数:验证外设句柄的有效性
  2. 获取外设数据:从外设句柄中获取IS31FL3216外设数据
  3. 发送退出命令:向任务发送退出命令,通知任务终止运行
  4. 等待任务退出:等待任务设置销毁位,确认任务已安全退出,并删除事件组
  5. 禁用LED通道:禁用所有LED通道,确保LED关闭
  6. 释放底层驱动:调用is31fl3216_deinit函数释放底层驱动资源
  7. 释放内存和同步对象:释放事件组、消息队列和分配的内存
// 文件:components/esp_peripherals/periph_is31fl3216.c
static esp_err_t _is31fl3216_destroy(esp_periph_handle_t self)
{// 1. 验证参数VALIDATE_IS31FL3216(self, ESP_FAIL);// 2. 获取外设数据periph_is31fl3216_t *is31fl3216 = esp_periph_get_data(self);// 3. 发送退出命令is31_evt_send(is31fl3216->evt, PERIPH_IS31_CMD_QUIT, 0, 0);// 4. 等待任务退出并删除事件组if (is31fl3216->g_event_bit) {xEventGroupWaitBits(is31fl3216->g_event_bit, DESTROY_BIT, pdTRUE, pdFALSE, portMAX_DELAY);vEventGroupDelete(is31fl3216->g_event_bit);is31fl3216->g_event_bit = NULL;}// 5. 禁用所有LED通道并释放底层驱动esp_err_t ret = ESP_OK;ret |= is31fl3216_ch_disable(is31fl3216->handle, IS31FL3216_CH_ALL);ret |= is31fl3216_deinit(is31fl3216->handle);// 6. 释放内存和同步对象audio_free(is31fl3216->arg);vQueueDelete(is31fl3216->evt);audio_free(is31fl3216);// 7. 检查错误并返回结果if (ret) {ESP_LOGE(TAG, "Error occurred when stopping the is31fl3216");return ESP_FAIL;}return ESP_OK;
}// 发送事件消息
static void is31_evt_send(void *que, periph_is31_cmd_t type, uint32_t data, int dir)
{periph_is31_msg_t evt = {0};evt.type = type;evt.data = data;if (dir) {xQueueSendToFront(que, &evt, 0) ;} else {xQueueSend(que, &evt, 0);}
}
底层驱动销毁过程(IS31FL3216.c)

底层驱动销毁通过is31fl3216_deinit函数(位于IS31FL3216.c)完成,主要包括以下步骤:

  1. 释放I2C总线:释放I2C总线资源并将总线指针设置为NULL
  2. 释放驱动结构体:释放分配的驱动结构体内存
// 文件:components/esp_peripherals/lib/IS31FL3216/IS31FL3216.c
esp_err_t is31fl3216_deinit(is31fl3216_handle_t handle)
{// 获取设备结构体is31fl3216_dev_t *dev = (is31fl3216_dev_t *) handle;// 1. 释放I2C总线if (dev->bus) {i2c_bus_delete(dev->bus);dev->bus = NULL;}// 2. 释放驱动结构体audio_free(dev);return ESP_OK;
}
完整销毁时序图

下图展示了IS31FL3216外设从应用程序调用到底层驱动完成销毁的完整流程:

应用程序 esp_periph库 _is31fl3216_IS31Destroy is31fl3216_run_task is31fl3216_deinit I2C总线驱动 esp_periph_remove(periph) _is31fl3216_IS31Destroy(self) VALIDATE_IS31FL3216(self, ESP_FAIL) esp_periph_get_data(self) 返回外设数据(is31fl3216) is31_evt_send(is31fl3216->>evt, PERIPH_IS31_CMD_QUIT, 0, 0) 接收退出消息 task_run = false 设置销毁位(IS31Destroy_BIT) 删除任务(vTaskDelete) 任务退出 xEventGroupWaitBits(is31fl3216->>g_event_bit, IS31Destroy_BIT, pdTRUE, pdFALSE, portMAX_DELAY) vEventGroupDelete(is31fl3216->>g_event_bit) is31fl3216->>g_event_bit = NULL is31fl3216_ch_disable(is31fl3216->>handle, IS31FL3216_CH_ALL) is31fl3216_deinit(is31fl3216->>handle) i2c_bus_delete(dev->>bus) 释放I2C资源 dev->>bus = NULL audio_free(dev) 返回结果(ESP_OK) audio_free(is31fl3216->>arg) vQueueDelete(is31fl3216->>evt) audio_free(is31fl3216) 检查错误(ret) 返回销毁结果(ESP_OK/ESP_FAIL) 返回移除结果(ESP_OK) 应用程序 esp_periph库 _is31fl3216_IS31Destroy is31fl3216_run_task is31fl3216_deinit I2C总线驱动

这个时序图详细展示了IS31FL3216外设的完整销毁流程,包括以下几个主要阶段:

  1. 外设销毁阶段:应用程序调用esp_periph_remove函数移除外设,ESP-ADF框架调用注册的销毁回调函数。

  2. 任务终止阶段:销毁函数向任务发送退出命令,任务接收命令后设置退出标志并安全退出。

  3. 同步与事件组释放阶段:销毁函数等待任务设置销毁位,确保任务已完全退出,并删除事件组。

  4. 底层驱动销毁:调用is31fl3216_deinit函数释放I2C总线和驱动结构体。

  5. 资源释放阶段:释放事件组、消息队列和分配的内存,完成所有资源的回收。

通过这种设计,IS31FL3216外设能够安全、有序地释放所有资源,避免内存泄漏和资源占用问题。

总结

IS31FL3216外设的销毁流程是一个有序、安全的资源释放过程,涉及多个层次的组件交互,包括外设层、底层驱动、I2C总线和任务管理。通过发送退出命令、等待任务退出、释放底层驱动和释放内存等步骤,确保所有资源都被正确回收,避免内存泄漏和资源占用问题。整个销毁流程与初始化流程形成了完整的对应关系,体现了良好的软件设计原则。

IS31FL3216外设事件处理机制

事件类型与消息结构

IS31FL3216外设的事件处理机制基于消息队列和状态机实现,通过事件驱动方式控制LED灯的不同工作模式和状态切换。事件类型主要包括:

typedef enum {PERIPH_IS31_CMD_CHG_STATE,  // 状态切换命令PERIPH_IS31_CMD_QUIT,        // 退出命令
} periph_is31_cmd_t;

事件消息结构定义如下:

typedef struct {periph_is31_cmd_t   type;    // 事件类型uint32_t            data;    // 事件数据
} periph_is31_msg_t;
事件发送机制

IS31FL3216外设通过is31_evt_send函数发送事件消息,该函数将事件消息放入消息队列,供任务处理:

static void is31_evt_send(void *que, periph_is31_cmd_t type, uint32_t data, int dir)
{periph_is31_msg_t evt = {0};evt.type = type;evt.data = data;if (dir) {xQueueSendToFront(que, &evt, 0) ;  // 高优先级消息,放入队列前端} else {xQueueSend(que, &evt, 0);          // 普通消息,放入队列尾部}
}

应用程序通过调用以下API函数间接发送事件:

  1. 状态切换事件:通过periph_is31fl3216_set_state函数发送状态切换事件
  2. 参数设置事件:通过各种参数设置函数修改参数,在下一次状态切换时生效
事件处理流程

IS31FL3216外设的事件处理在is31fl3216_run_task任务中进行,主要处理流程如下:

  1. 事件接收:任务通过xQueueReceive函数从消息队列接收事件消息
  2. 事件解析:根据事件类型执行相应的处理逻辑
  3. 状态切换:对于状态切换事件,调用is31_change_state函数切换到新状态
  4. 状态处理:根据当前状态执行相应的LED控制逻辑
// 事件接收与处理示例代码片段
if (xQueueReceive(is31->evt, &msg, (wait_time_ms / portTICK_PERIOD_MS))) {switch (msg.type) {case PERIPH_IS31_CMD_CHG_STATE:memcpy(&is31_arg, is31->arg, sizeof(periph_is31_arg_t));wait_time_ms = is31->arg->interval_time;// 重置参数并切换状态memset(is31->arg, 0, sizeof(periph_is31_arg_t));is31->arg->interval_time = portMAX_DELAY;is31->arg->max_light_num = IS31FL3216_CH_NUM;is31->arg->duty_step = DEFAULT_FLASH_STEP;is31_change_state(is31, msg.data, &is31_arg);break;case PERIPH_IS31_CMD_QUIT:task_run = false;if (is31->g_event_bit) {xEventGroupSetBits(is31->g_event_bit, DESTROY_BIT);}break;default:break;}
}
状态机实现

IS31FL3216外设通过状态机管理不同的工作模式,主要状态包括:

  1. IS31FL3216_STATE_OFF:关闭状态,禁用所有LED通道
  2. IS31FL3216_STATE_ON:常亮状态,启用指定的LED通道
  3. IS31FL3216_STATE_FLASH:闪烁状态,LED亮度周期性变化
  4. IS31FL3216_STATE_SHIFT:移位状态,LED通道按照指定模式移位
  5. IS31FL3216_STATE_BY_AUDIO:音频响应状态,LED亮度随音频信号变化

状态切换通过is31_change_state函数实现:

static esp_err_t is31_change_state(periph_is31fl3216_t *is31, int state, periph_is31_arg_t *arg)
{esp_err_t ret = ESP_OK;switch (state) {case IS31FL3216_STATE_OFF:ret |= is31fl3216_ch_disable(is31->handle, arg->light_mask);arg->interval_time = portMAX_DELAY;is31->cur_state = IS31FL3216_STATE_OFF;break;case IS31FL3216_STATE_ON:if (is31->cur_state == IS31FL3216_STATE_BY_AUDIO) {ret |= is31fl3216_work_mode_set(is31->handle, IS31FL3216_MODE_PWM);is31_leds_duty(is31->handle, IS31FL3216_DUTY_MAX, arg->light_mask);}is31_leds_ctrl(is31->handle, arg->light_mask);arg->interval_time = portMAX_DELAY;is31->cur_state = IS31FL3216_STATE_ON;break;// 其他状态处理...}return ret;
}
状态控制与参数配置接口
状态控制接口

IS31FL3216外设的核心控制接口是periph_is31fl3216_set_state函数,用于切换LED的工作状态:

esp_err_t periph_is31fl3216_set_state(esp_periph_handle_t periph, periph_is31fl3216_state_t state)
{periph_is31fl3216_t *is31fl3216 = esp_periph_get_data(periph);is31_evt_send(is31fl3216->evt, PERIPH_IS31_CMD_CHG_STATE, state, 0);return ESP_OK;
}

这个函数的实现非常简洁,它通过以下步骤实现状态切换:

  1. 从外设句柄中获取IS31FL3216外设数据
  2. 调用is31_evt_send函数发送PERIPH_IS31_CMD_CHG_STATE事件,并将目标状态作为事件数据
  3. 事件消息被放入消息队列,等待is31fl3216_run_task任务处理

这种设计实现了控制逻辑与实际执行的解耦,应用程序只需要发送状态切换请求,而不需要关心具体的实现细节。

参数配置接口

IS31FL3216外设提供了一系列参数配置接口,用于设置LED的工作参数:

  1. periph_is31fl3216_set_blink_pattern:设置LED通道掩码,指定哪些通道参与工作

    esp_err_t periph_is31fl3216_set_blink_pattern(esp_periph_handle_t periph, uint16_t blink_pattern)
    {periph_is31fl3216_t *is31fl3216 = esp_periph_get_data(periph);is31fl3216->arg->light_mask = blink_pattern;return ESP_OK;
    }
    
  2. periph_is31fl3216_set_duty_step:设置闪烁模式下的亮度变化步长

  3. periph_is31fl3216_set_interval:设置状态更新的时间间隔

  4. periph_is31fl3216_set_shift_mode:设置移位模式(单通道移位或累积移位)

  5. periph_is31fl3216_set_light_on_num:设置移位模式下点亮的LED数量

  6. periph_is31fl3216_set_act_time:设置动作持续时间

事件处理时序图
应用程序 API函数 消息队列 is31fl3216_run_task 状态处理函数 底层驱动 periph_is31fl3216_set_state(state) is31_evt_send(PERIPH_IS31_CMD_CHG_STATE) xQueueReceive() 处理事件消息 is31_change_state(state) 配置底层驱动 periph_is31fl3216_set_xxx(param) 更新参数 根据当前状态执行相应操作 更新LED亮度 更新LED通道掩码 alt [IS31FL3216_STATE_FLASH] [IS31FL3216_STATE_SHIFT] 检查动作时间 loop [状态处理] esp_periph_remove(periph) is31_evt_send(PERIPH_IS31_CMD_QUIT) xQueueReceive() 设置退出标志 设置销毁位 退出任务 应用程序 API函数 消息队列 is31fl3216_run_task 状态处理函数 底层驱动
总结

IS31FL3216外设的事件处理机制基于消息队列和状态机实现,通过事件驱动方式控制LED灯的不同工作模式和状态切换。应用程序通过调用API函数发送事件,任务接收事件并执行相应的处理逻辑。状态机管理不同的工作模式,实现LED灯的常亮、闪烁、移位和音频响应等效果。参数配置接口提供了灵活的LED控制能力,满足不同应用场景的需求。

典型示例

#include "esp_log.h"
#include "esp_peripherals.h"
#include "periph_is31fl3216.h"#define TAG "IS31FL3216_DEMO"void is31fl3216_demo(void)
{// 1. 初始化外设管理器esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();esp_periph_set_handle_t set = esp_periph_set_init(&periph_cfg);// 2. 配置IS31FL3216参数periph_is31fl3216_cfg_t is31_cfg = {.is31fl3216_pattern = 0xFFFF,  // 启用所有LED.state = IS31FL3216_STATE_OFF  // 初始状态为关闭};// 3. 设置所有LED通道亮度为最大for (int i = 0; i < IS31FL3216_CH_NUM; i++) {is31_cfg.duty[i] = 255;}// 4. 初始化并启动IS31FL3216外设esp_periph_handle_t is31_handle = periph_is31fl3216_init(&is31_cfg);esp_periph_start(set, is31_handle);// 5. 设置常亮模式(所有LED常亮)periph_is31fl3216_set_blink_pattern(is31_handle, 0xFFFF);periph_is31fl3216_set_state(is31_handle, IS31FL3216_STATE_ON);vTaskDelay(3000 / portTICK_PERIOD_MS);  // 持续3秒// 6. 设置闪烁模式(所有LED闪烁)periph_is31fl3216_set_blink_pattern(is31_handle, 0xFFFF);periph_is31fl3216_set_interval(is31_handle, 100);     // 100ms间隔periph_is31fl3216_set_duty_step(is31_handle, 5);      // 亮度变化步长periph_is31fl3216_set_state(is31_handle, IS31FL3216_STATE_FLASH);vTaskDelay(3000 / portTICK_PERIOD_MS);  // 持续3秒// 7. 设置移位模式(跑马灯效果)periph_is31fl3216_set_shift_mode(is31_handle, PERIPH_IS31_SHIFT_MODE_SINGLE);periph_is31fl3216_set_light_on_num(is31_handle, 1, IS31FL3216_CH_NUM);periph_is31fl3216_set_interval(is31_handle, 200);     // 200ms间隔periph_is31fl3216_set_state(is31_handle, IS31FL3216_STATE_SHIFT);vTaskDelay(3000 / portTICK_PERIOD_MS);  // 持续3秒// 8. 设置音频响应模式(LED亮度随音频变化)periph_is31fl3216_set_state(is31_handle, IS31FL3216_STATE_BY_AUDIO);// 9. 清理资源(实际应用中在退出前调用)// esp_periph_set_stop_all(set);// esp_periph_set_destroy(set);
}

常用参数和配置

LED通道模式(用于periph_is31fl3216_set_blink_pattern
#define LED_PATTERN_ALL   0xFFFF  // 所有LED
#define LED_PATTERN_EVEN  0xAAAA  // 偶数LED
#define LED_PATTERN_ODD   0x5555  // 奇数LED
LED工作状态(用于periph_is31fl3216_set_state
typedef enum {IS31FL3216_STATE_OFF = 0,       // LED关闭IS31FL3216_STATE_ON,            // LED常亮IS31FL3216_STATE_FLASH,         // LED闪烁IS31FL3216_STATE_SHIFT,         // LED移位(跑马灯)IS31FL3216_STATE_BY_AUDIO,      // LED随音频变化IS31FL3216_STATE_UNKNOWN        // 未知状态
} periph_is31fl3216_state_t;
移位模式(用于periph_is31fl3216_set_shift_mode
typedef enum {PERIPH_IS31_SHIFT_MODE_SINGLE = 0,  // 单个LED移位PERIPH_IS31_SHIFT_MODE_ACC,         // 累积LED移位(逐渐增加)
} periph_is31_shift_mode_t;

常见应用场景

  1. 音频可视化:在音频播放器中实现音频频谱显示
  2. 状态指示:用不同的LED模式指示设备的不同工作状态
  3. 用户界面反馈:为用户操作提供可视化反馈
  4. 装饰照明:实现各种装饰性照明效果

注意:使用音频响应模式时,需确保音频输入正确连接到IS31FL3216芯片的音频输入引脚。

相关文章:

  • 【无人机】无人机的电调校准,ESC Calibration,PX4使用手册电调校准详细步骤
  • 超详细实现单链表的基础增删改查——基于C语言实现
  • 基于 FFmpeg 的音视频处理基础原理与实验探究
  • 运维概述(linux 系统)
  • 《解锁增强型上下文学习,打造你的专属智能助手》
  • 徐州服务器租用:虚拟主机的应用场景
  • Spring AI MCP
  • Linux之信号
  • Linux——系统安全及应用
  • 2025年pta团队设计天梯赛题解
  • 【软件工程】 适配器模式
  • C#接口开发异常:System.Web.HttpRequestValidationException
  • 怎么建立自然语言领域的评价标准
  • 人工智能在智能家居中的应用与发展
  • ubuntu20.04安装安装x11vnc服务基于gdm3或lightdm这两种主流的显示管理器。
  • PyTorch深度学习框架60天进阶学习计划 - 第47天:模型压缩蒸馏技术(一)
  • Java面试(2025)—— Spring MVC
  • CentOS7系统安装Docker教程
  • 目标跟踪中的聚类算法:DBSCAN Kmeans GMM
  • 【第十六届 蓝桥杯 省 C/Python A/Java C 登山】题解
  • 夸大事实拍视频发网络,镇雄两名网红勒索两千元删帖费被拘
  • 安且吉兮,西泠印社雅集吴昌硕故里
  • 用8年还原曹操墓鉴定过程,探寻曹操墓新书创作分享会举行
  • 淄博张店区国资公司挂牌转让所持“假国企”股权,转让底价为1元
  • 多地市场监管部门公开征集居民水电气计量不准确、收费不规范问题线索
  • 经济日报:“关税讹诈”拦不住中国制造升级