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

在WLED项目中使用TWAI时WS28xx LED闪烁问题求助

问题描述

我尝试将CAN-bus命令接收功能与现有WLED源码集成,以驱动WS2812b LED灯带。项目硬件基于ESP32-WROOM-32芯片,搭配电平转换器、CAN收发器等,使用ESP32-TWAI-CAN v1.0.1库,用户模块代码如下:

#include "wled.h"
#include <ESP32-TWAI-CAN.hpp>

#define CAN_RX    18
#define CAN_TX    19
#define CAN_READ_TIMEOUT 0


class CanUsermod : public Usermod
{

setup() {

   [...]

   twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
   twai_general_config_t g_config = {.mode = TWAI_MODE_LISTEN_ONLY, .tx_io = (gpio_num_t) CAN_TX, .rx_io = (gpio_num_t) CAN_RX,
                                            .clkout_io = TWAI_IO_UNUSED, .bus_off_io = TWAI_IO_UNUSED,
                                            .tx_queue_len = 5, .rx_queue_len = 5,
                                            .alerts_enabled = TWAI_ALERT_NONE,  .clkout_divider = 0,
                                            .intr_flags = ESP_INTR_FLAG_LEVEL1};
   twai_timing_config_t t_config = TWAI_TIMING_CONFIG_250KBITS();
   ESP32Can.begin(ESP32Can.convertSpeed(250),
                    CAN_TX,
                    CAN_RX,
                    5,
                    5,
                    &f_config,
                    &g_config,
                    &t_config);
}

[...]

void loop()
{
   while(ESP32Can.readFrame(rxFrame, CAN_READ_TIMEOUT))
      [...]
   }
}

单独运行WLED或CAN总线均正常,能正确接收CAN消息,但同时运行时(有CAN总线流量且点亮WS28xx LED),LED会闪烁,即使选择Solid效果也会出现该问题:

  • 断开CAN总线,闪烁停止
  • 注释ESP32Can.begin([...])代码,闪烁停止

已排查但无效的操作:

  • 修改RX、TX队列长度
  • 设置CAN过滤器为全拒绝:{.acceptance_code = 0, .acceptance_mask = 0x00000000, .single_filter = true}
  • 在g_config中设置.intr_flags=ESP_INTR_FLAG_LEVEL3
  • 修改CAN_READ_TIMEOUT为0、10、100
  • 注释loop()中的while循环
  • 验证控制器板数据输出通道无振铃
  • 验证数据输出通道逻辑电平正确
  • 验证LED灯带供电电压正确
  • 将LED数据输出从GPIO16改为GPIO4

因此我怀疑TWAI接口的ISR导致LED的800kHz位模式生成出现抖动,请问是否需要在LED位生成期间暂停中断?若需要,应如何实现?


解决方案

你的怀疑是正确的:WS2812B的800kHz时序要求极高(误差不能超过±150ns),TWAI的中断会打断LED数据发送的精确时序,导致灯带识别错误从而出现闪烁。

实现思路

WLED内部通过RMT外设发送LED数据,你需要在RMT发送LED帧的前后分别禁用/启用TWAI中断,避免时序被打断。

具体代码修改

  1. 在CAN用户模块中添加控制TWAI中断的函数:
// 禁用TWAI中断
void disableTwaiInterrupts() {
  esp_intr_disable(ESP32Can.getTwaiHandle());
}

// 启用TWAI中断
void enableTwaiInterrupts() {
  esp_intr_enable(ESP32Can.getTwaiHandle());
}
  1. Hook WLED的LED发送回调:
    WLED提供了onBeforeRender()和onAfterRender()钩子函数,你可以在用户模块中重写这两个方法,分别在发送LED数据前后控制TWAI中断:
class CanUsermod : public Usermod
{
  // ... 现有代码 ...

  void onBeforeRender() override {
    disableTwaiInterrupts();
  }

  void onAfterRender() override {
    enableTwaiInterrupts();
  }

  // ... 现有代码 ...
};
  1. 备选方案:调整TWAI中断优先级
    如果禁用中断影响CAN接收的实时性,你可以尝试将TWAI的中断优先级设置为低于RMT外设的中断优先级(ESP32中RMT默认优先级较高)。修改g_config中的intr_flags:
twai_general_config_t g_config = {
  // ... 现有配置 ...
  .intr_flags = ESP_INTR_FLAG_LEVEL2 // 设置为比RMT默认优先级低的等级
};

不过这个方案的可靠性不如直接禁用中断,因为即使优先级低,高负载下仍可能出现抢占。

注意事项

  • 禁用TWAI中断期间,CAN总线的消息会暂时存在TWAI的硬件FIFO中(TWAI控制器有32个消息的硬件FIFO),只要CAN流量不是持续满负荷,不会丢失消息。
  • 如果你的CAN流量极大,超过硬件FIFO容量,可以考虑在禁用中断前先读取所有队列中的消息,减少丢失风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 04:25:13