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

ESPHome自定义TMC2130组件报错:esp32_esp32internalgpiopin_6已注册

ESPHome自定义TMC2130组件编译错误排查:ID esp32_esp32internalgpiopin_6已注册

编译自定义TMC2130步进电机组件时出现错误:ERROR ID esp32_esp32internalgpiopin_6 is already registered,以下是问题分析与修复方案:

错误核心原因

  1. SPI设备继承与CS_PIN重复注册:Python层定义组件继承spi.SPIDevice,但C++类仅继承Component,导致SPI组件自动注册CS_PIN的同时,代码又将CS_PIN作为普通GPIO重复处理。
  2. 未使用ESPHome规范GPIO管理:C++代码中直接使用未定义的EN_PIN/STEP_PIN/DIR_PIN宏,编译时会被解析为默认值(如6),该引脚可能已被占用或重复注册。
  3. 引脚传递与存储错误:Python层传递的引脚未在C++类中存储为成员变量,导致实际操作的引脚与配置不符。

修复步骤

1. 修正C++类定义(tmc2130.h)

让组件正确继承SPI设备,并添加引脚成员变量:

#include "esphome/core/component.h"
#include "esphome/components/spi/spi.h"
#include <TMCStepper.h>

namespace esphome {
namespace tmc2130 {

class TMC2130Component : public Component, public spi::SPIDevice {
 public:
  TMC2130Component(float r_sense) : driver_(this->cs_, r_sense) {}
  
  void setup() override;
  void dump_config() override;
  void set_toff(uint8_t toff);
  void set_blank_time(uint8_t blank_time);
  void set_rms_current(uint16_t rms_current);
  void set_microsteps(int microsteps);
  void set_tcoolthrs(uint32_t tcoolthrs);
  void set_thigh(uint32_t thigh);
  void set_semin(uint8_t semin);
  void set_semax(uint8_t semax);
  void set_sedn(uint8_t sedn);
  void set_sgt(int8_t sgt);
  void set_direction_forward(bool forward);
  void set_step_pin(GPIOPin *pin) { step_pin_ = pin; }
  void set_dir_pin(GPIOPin *pin) { dir_pin_ = pin; }
  void set_en_pin(GPIOPin *pin) { en_pin_ = pin; }

 protected:
  TMC2130Stepper driver_;
  GPIOPin *step_pin_;
  GPIOPin *dir_pin_;
  GPIOPin *en_pin_;
  uint8_t toff_;
  uint8_t blank_time_;
  uint16_t rms_current_;
  int microsteps_;
  uint32_t tcoolthrs_;
  uint32_t thigh_;
  uint8_t semin_;
  uint8_t semax_;
  uint8_t sedn_;
  int8_t sgt_;
  bool motor_direction_{true};
  hw_timer_t *timer_{nullptr};
};

}  // namespace tmc2130
}  // namespace esphome

2. 修正C++实现(tmc2130.cpp)

移除未定义宏,使用成员变量管理引脚:

#include "tmc2130.h"
#include "esphome/core/log.h"
#include <TMCStepper.h>

namespace esphome {
namespace tmc2130 {

static const char *const TAG = "tmc2130";

void TMC2130Component::setup() {
  ESP_LOGD(TAG, "Setting up TMC2130...");
  this->en_pin_->setup();
  this->step_pin_->setup();
  this->dir_pin_->setup();
  this->en_pin_->digital_write(false); // 默认使能驱动器

  this->driver_.begin(); // 初始化SPI
  // 应用YAML配置参数
  this->driver_.toff(this->toff_);
  this->driver_.blank_time(this->blank_time_);
  this->driver_.rms_current(this->rms_current_);
  this->driver_.microsteps(this->microsteps_);
  this->driver_.TCOOLTHRS(this->tcoolthrs_);
  this->driver_.THIGH(this->thigh_);
  this->driver_.semin(this->semin_);
  this->driver_.semax(this->semax_);
  this->driver_.sedn(this->sedn_);
  this->driver_.sgt(this->sgt_);

  // 初始化定时器
  this->timer_ = timerBegin(0, 80, true);
  timerAttachInterrupt(this->timer_, &onTimer, true);
  timerAlarmWrite(this->timer_, 1000, true);
  timerAlarmEnable(this->timer_);
}

// 保留原有setter方法...

void TMC2130Component::set_direction_forward(bool forward) {
  motor_direction_ = forward;
  this->dir_pin_->digital_write(motor_direction_);
}

void TMC2130Component::enable_motor(bool enable) {
  this->en_pin_->digital_write(!enable); // LOW=使能,HIGH=禁用
}

// 注意:中断函数需重构以避免访问非静态成员,此处为临时示例
static void IRAM_ATTR onTimer() {
  // 建议改为通过定时器传递组件实例指针,避免未定义行为
}

}  // namespace tmc2130
}  // namespace esphome

3. 修正Python代码(stepper.py)

移除CS_PIN的重复处理,规范引脚传递:

import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import spi
from esphome.const import CONF_ID
from esphome.core import coroutine

DEPENDENCIES = ['spi']
AUTO_LOAD = ['sensor']

tmc2130_ns = cg.esphome_ns.namespace('tmc2130')
TMC2130Component = tmc2130_ns.class_('TMC2130Component', cg.Component, spi.SPIDevice)

CONF_TOFF = "toff"
CONF_BLANK_TIME = "blank_time"
CONF_RMS_CURRENT = "rms_current"
CONF_MICROSTEPS = "microsteps"
CONF_TCOOLTHRS = "tcoolthrs"
CONF_THIGH = "thigh"
CONF_SEMIN = "semin"
CONF_SEMAX = "semax"
CONF_SEDN = "sedn"
CONF_SGT = "sgt"
CONF_R_SENSE = "r_sense"
CONF_STEP_PIN = "step_pin"
CONF_DIR_PIN = "dir_pin"
CONF_EN_PIN = "en_pin"

CONFIG_SCHEMA = cv.Schema({
    cv.GenerateID(): cv.declare_id(TMC2130Component),
    cv.Required(CONF_STEP_PIN): pins.gpio_output_pin_schema,
    cv.Required(CONF_DIR_PIN): pins.gpio_output_pin_schema,
    cv.Optional(CONF_EN_PIN): pins.gpio_output_pin_schema,
    cv.Required(CONF_RMS_CURRENT): cv.positive_int,
    cv.Required(CONF_R_SENSE): cv.float_,
    cv.Optional(CONF_TOFF, default=4): cv.int_range(min=0, max=15),
    cv.Optional(CONF_BLANK_TIME, default=24): cv.int_range(min=16, max=54),
    cv.Optional(CONF_MICROSTEPS, default=16): cv.int_range(min=0, max=256),
    cv.Optional(CONF_TCOOLTHRS, default=0xFFFFF): cv.hex_int,
    cv.Optional(CONF_THIGH, default=0): cv.hex_int,
    cv.Optional(CONF_SEMIN, default=5): cv.int_range(min=0, max=15),
    cv.Optional(CONF_SEMAX, default=2): cv.int_range(min=0, max=15),
    cv.Optional(CONF_SEDN, default=0b01): cv.int_range(min=0, max=0b11),
    cv.Optional(CONF_SGT, default=7): cv.int_range(min=-64, max=63),
}).extend(cv.COMPONENT_SCHEMA).extend(spi.spi_device_schema())

async def to_code(config):
    var = cg.new_Pvariable(config[CONF_ID], config[CONF_R_SENSE])
    await cg.register_component(var, config)
    await spi.register_spi_device(var, config)

    cg.add_library('TMCStepper', '0.7.3')
    
    step_pin = await cg.gpio_pin_expression(config[CONF_STEP_PIN])
    cg.add(var.set_step_pin(step_pin))
    
    dir_pin = await cg.gpio_pin_expression(config[CONF_DIR_PIN])
    cg.add(var.set_dir_pin(dir_pin))
    
    if CONF_EN_PIN in config:
        en_pin = await cg.gpio_pin_expression(config[CONF_EN_PIN])
        cg.add(var.set_en_pin(en_pin))

    # 应用配置参数
    cg.add(var.set_toff(config[CONF_TOFF]))
    cg.add(var.set_blank_time(config[CONF_BLANK_TIME]))
    cg.add(var.set_rms_current(config[CONF_RMS_CURRENT]))
    cg.add(var.set_microsteps(config[CONF_MICROSTEPS]))
    cg.add(var.set_tcoolthrs(config[CONF_TCOOLTHRS]))
    cg.add(var.set_thigh(config[CONF_THIGH]))
    cg.add(var.set_semin(config[CONF_SEMIN]))
    cg.add(var.set_semax(config[CONF_SEMAX]))
    cg.add(var.set_sedn(config[CONF_SEDN]))
    cg.add(var.set_sgt(config[CONF_SGT]))

4. 修正YAML配置

添加可选的使能引脚,确保CS_PIN由SPI组件管理:

...
external_components:
  - source:
      type: git
      url: https://github.com/Defozo/esphome
      ref: dev
    components: [ tmc2130 ]
    refresh: 3s

spi:
  clk_pin: 18
  mosi_pin: 23
  miso_pin: 19

stepper:
  - platform: tmc2130
    id: my_stepper
    step_pin: 21
    dir_pin: 16
    en_pin: 22  # 根据硬件连接添加,可选
    cs_pin: 26
    r_sense: 0.11
    microsteps: 16
    rms_current: 1500

额外注意

  • 中断函数onTimer需重构,避免直接访问非静态成员变量,可通过定时器传递组件实例指针解决。
  • 确保所有GPIO引脚未被其他组件重复使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:08:11