You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32S3通过I2C驱动IS31FL3236A LED无响应问题排查求助

问题描述

我有一块基于ESP32S3的自定义LED开发板,需要编写程序通过I2C总线让MCU与LED驱动芯片IS31FL3236A通信。我把找到的Arduino示例代码转为ESP-IDF标准库的C/C++代码,但LED无法正常工作(Arduino版本代码可正常运行)。引脚配置和Arduino完全一致,确认SDA、SCL、LED引脚都正确。

程序代码

#include "esp_log.h"
#include "driver/i2c.h"

static const char *TAG = "i2c-simple-example";

#define I2C_MASTER_SCL_IO           CONFIG_I2C_MASTER_SCL
#define I2C_MASTER_SDA_IO           CONFIG_I2C_MASTER_SDA
#define I2C_MASTER_NUM              0
#define I2C_MASTER_FREQ_HZ          400000                     
#define OUT_CURRENT  0x02

#define LED_DRIVER_ADDR     0x3C
#define IS31FL3236A_UPDATE_REG  0x25
#define IS31FL3236A_SHUTDOWN_REG      0x00


esp_err_t i2c_master_init(void)
{
    int i2c_master_port = I2C_MASTER_NUM;
    i2c_config_t conf = {
            .mode = I2C_MODE_MASTER,
            .sda_io_num = I2C_MASTER_SDA_IO,
            .scl_io_num = I2C_MASTER_SCL_IO,
            .sda_pullup_en = GPIO_PULLUP_ENABLE,
            .scl_pullup_en = GPIO_PULLUP_ENABLE,
            .master.clk_speed = I2C_MASTER_FREQ_HZ,
    };
    i2c_param_config(i2c_master_port, &conf);
    return i2c_driver_install(i2c_master_port, conf.mode, 0, 0, 0);
}

void send_data(uint8_t ledDriverRegister, unsigned char data)
{
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    ESP_ERROR_CHECK(i2c_master_start(cmd));
    ESP_ERROR_CHECK(i2c_master_write_byte(cmd, LED_DRIVER_ADDR, true));
    ESP_ERROR_CHECK(i2c_master_write_byte(cmd, ledDriverRegister, true));
    ESP_ERROR_CHECK(i2c_master_write_byte(cmd, data, true));
    ESP_ERROR_CHECK(i2c_master_stop(cmd));
    i2c_cmd_link_delete(cmd);
}

void update_shutdown_register_to_normal_operation()
{
    send_data(IS31FL3236A_SHUTDOWN_REG, 0x01);
}

void update_register()
{
    send_data(IS31FL3236A_UPDATE_REG, 0x00);
}

void init()
{
    ESP_LOGI(TAG, "Init current for leds");
    for (uint8_t i = 0x26; i <= 0x49; i++)
    {
        send_data(i, ((OUT_CURRENT << 1) | 0x01)); // enable all leds
    }
    for (uint8_t i = 0x01; i <= 0x24; i++)
    {
        send_data(i, 0x00); // set PWM for all leds to 0
    }
    ESP_LOGI(TAG, "Updated register");
    update_register();
    update_shutdown_register_to_normal_operation();
}

_Noreturn void app_main(void)
{
    ESP_ERROR_CHECK(i2c_master_init());
    ESP_LOGI(TAG, "I2C initialized successfully GPIO SDA %d SCL %d", I2C_MASTER_SDA_IO, I2C_MASTER_SCL_IO);
    init();
    send_data(0x8, 0x63); // I my board LED is on OUT on port 8 and value 63 max
    update_register();
    ESP_LOGI(TAG, "End Test");
    vTaskDelay(3000 / portTICK_RATE_MS);
}

串口日志

--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x9 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:2
load:0x3fce3808,len:0x1664
load:0x403c9700,len:0xbb8
load:0x403cc700,len:0x2e8c
entry 0x403c9954
I (29) boot: ESP-IDF v4.4.3-dirty 2nd stage bootloader
I (29) boot: compile time 22:27:17
I (30) boot: chip revision: 0
I (32) boot.esp32s3: Boot SPI Speed : 40MHz
I (36) boot.esp32s3: SPI Mode       : DIO
I (41) boot.esp32s3: SPI Flash Size : 8MB
I (46) boot: Enabling RNG early entropy source...
I (51) boot: Partition Table:
I (55) boot: ## Label            Usage          Type ST Offset   Length
I (62) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (70) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (77) boot:  2 factory          factory app      00 00 00010000 00100000
I (84) boot: End of partition table
I (89) esp_image: segment 0: paddr=00010020 vaddr=3c020020 size=088c8h ( 35016) map
I (106) esp_image: segment 1: paddr=000188f0 vaddr=3fc91f90 size=02614h (  9748) load
I (109) esp_image: segment 2: paddr=0001af0c vaddr=40374000 size=0510ch ( 20748) load
I (120) esp_image: segment 3: paddr=00020020 vaddr=42000020 size=182f8h ( 99064) map
I (147) esp_image: segment 4: paddr=00038320 vaddr=4037910c size=08e84h ( 36484) load
I (158) esp_image: segment 5: paddr=000411ac vaddr=50000000 size=00010h (    16) load
I (164) boot: Loaded app from partition at offset 0x10000
I (164) boot: Disabling RNG early entropy source...
I (178) cpu_start: Pro cpu up.
I (178) cpu_start: Starting app cpu, entry point is 0x403751e4
0x403751e4: call_start_cpu1 at /home/rafal/esp/esp-idf/components/esp_system/port/cpu_start.c:148

I (0) cpu_start: App cpu up.
I (192) cpu_start: Pro cpu start user code
I (192) cpu_start: cpu freq: 160000000
I (192) cpu_start: Application information:
I (195) cpu_start: Project name:     i2c-simple
I (200) cpu_start: App version:      v4.4.3-dirty
I (206) cpu_start: Compile time:     Nov 25 2022 22:18:32
I (212) cpu_start: ELF file SHA256:  a7bcfcfcba18ab90...
I (218) cpu_start: ESP-IDF:          v4.4.3-dirty
I (223) heap_init: Initializing. RAM available for dynamic allocation:
I (230) heap_init: At 3FC94F98 len 00054778 (337 KiB): D/IRAM
I (237) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM
I (243) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (250) heap_init: At 600FE000 len 00002000 (8 KiB): RTCRAM
I (257) spi_flash: detected chip: generic
I (261) spi_flash: flash io: dio
I (266) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (286) i2c-simple-example: I2C initialized successfully GPIO SDA 10 SCL 9
I (286) i2c-simple-example: Init current for leds
I (296) i2c-simple-example: Updated register
I (296) i2c-simple-example: Set min value for pwm
I (306) i2c-simple-example: End Test
问题排查与解决方案

核心问题点

  1. I2C设备地址格式错误:i2c_master_write_byte的第二个参数需要是带读写位的7位地址。原代码直接传入LED_DRIVER_ADDR(0x3C),但ESP-IDF API要求将7位地址左移1位,再加上写位(0),正确格式应为(0x3C << 1) | 0即0x78。
  2. 缺少I2C命令执行步骤:原代码创建命令链、添加指令后,未调用i2c_master_cmd_begin发送指令,导致所有寄存器写入操作未生效。
  3. 寄存器初始化顺序错误:IS31FL3236A需先退出关断模式,再配置其他寄存器。原代码先配置电流和PWM,再设置关断寄存器,可能导致配置不生效。

修改后的代码

#include "esp_log.h"
#include "driver/i2c.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

static const char *TAG = "i2c-simple-example";

#define I2C_MASTER_SCL_IO           CONFIG_I2C_MASTER_SCL
#define I2C_MASTER_SDA_IO           CONFIG_I2C_MASTER_SDA
#define I2C_MASTER_NUM              0
#define I2C_MASTER_FREQ_HZ          400000                     
#define OUT_CURRENT  0x02

#define LED_DRIVER_ADDR     0x3C // 7位地址
#define IS31FL3236A_UPDATE_REG  0x25
#define IS31FL3236A_SHUTDOWN_REG      0x00


esp_err_t i2c_master_init(void)
{
    int i2c_master_port = I2C_MASTER_NUM;
    i2c_config_t conf = {
            .mode = I2C_MODE_MASTER,
            .sda_io_num = I2C_MASTER_SDA_IO,
            .scl_io_num = I2C_MASTER_SCL_IO,
            .sda_pullup_en = GPIO_PULLUP_ENABLE,
            .scl_pullup_en = GPIO_PULLUP_ENABLE,
            .master.clk_speed = I2C_MASTER_FREQ_HZ,
    };
    i2c_param_config(i2c_master_port, &conf);
    return i2c_driver_install(i2c_master_port, conf.mode, 0, 0, 0);
}

esp_err_t send_data(uint8_t ledDriverRegister, unsigned char data)
{
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    ESP_ERROR_CHECK(i2c_master_start(cmd));
    // 修正地址格式:7位地址左移1位 + 写位
    ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (LED_DRIVER_ADDR << 1) | I2C_MASTER_WRITE, true));
    ESP_ERROR_CHECK(i2c_master_write_byte(cmd, ledDriverRegister, true));
    ESP_ERROR_CHECK(i2c_master_write_byte(cmd, data, true));
    ESP_ERROR_CHECK(i2c_master_stop(cmd));
    // 执行I2C命令链
    esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}

void update_shutdown_register_to_normal_operation()
{
    ESP_ERROR_CHECK(send_data(IS31FL3236A_SHUTDOWN_REG, 0x01));
    vTaskDelay(10 / portTICK_RATE_MS); // 等待芯片退出关断模式
}

void update_register()
{
    ESP_ERROR_CHECK(send_data(IS31FL3236A_UPDATE_REG, 0x00));
}

void init()
{
    ESP_LOGI(TAG, "Init current for leds");
    // 先退出关断模式,再配置其他寄存器
    update_shutdown_register_to_normal_operation();
    
    for (uint8_t i = 0x26; i <= 0x49; i++)
    {
        ESP_ERROR_CHECK(send_data(i, ((OUT_CURRENT << 1) | 0x01))); // 启用所有LED
        vTaskDelay(1 / portTICK_RATE_MS); // 避免I2C总线拥堵
    }
    for (uint8_t i = 0x01; i <= 0x24; i++)
    {
        ESP_ERROR_CHECK(send_data(i, 0x00)); // 设置所有LED初始PWM为0
        vTaskDelay(1 / portTICK_RATE_MS);
    }
    ESP_LOGI(TAG, "Updated register");
    update_register();
}

void app_main(void)
{
    ESP_ERROR_CHECK(i2c_master_init());
    ESP_LOGI(TAG, "I2C initialized successfully GPIO SDA %d SCL %d", I2C_MASTER_SDA_IO, I2C_MASTER_SCL_IO);
    init();
    ESP_ERROR_CHECK(send_data(0x08, 0x63)); // 设置第8路LED的PWM值为63
    update_register();
    ESP_LOGI(TAG, "End Test");
    vTaskDelay(3000 / portTICK_RATE_MS);
}

修改说明

  • 地址格式修正:将设备地址转换为ESP-IDF要求的带写位格式,确保I2C通信能正确寻址到IS31FL3236A。
  • 添加命令执行:调用i2c_master_cmd_begin实际发送I2C指令链,让寄存器写入操作生效。
  • 调整初始化顺序:先退出关断模式,再配置电流和PWM寄存器,符合芯片操作时序要求。
  • 增加延时:在多次I2C操作之间添加短暂延时,避免总线拥堵导致通信失败。
  • 错误返回处理:让send_data返回错误码,便于排查通信问题。

内容的提问来源于stack exchange,提问作者Mbded

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 13:41:01