ESPHome自定义TMC2130组件报错:esp32_esp32internalgpiopin_6已注册
ESPHome自定义TMC2130组件编译错误排查:ID esp32_esp32internalgpiopin_6已注册
编译自定义TMC2130步进电机组件时出现错误:ERROR ID esp32_esp32internalgpiopin_6 is already registered,以下是问题分析与修复方案:
错误核心原因
- SPI设备继承与CS_PIN重复注册:Python层定义组件继承
spi.SPIDevice,但C++类仅继承Component,导致SPI组件自动注册CS_PIN的同时,代码又将CS_PIN作为普通GPIO重复处理。 - 未使用ESPHome规范GPIO管理:C++代码中直接使用未定义的
EN_PIN/STEP_PIN/DIR_PIN宏,编译时会被解析为默认值(如6),该引脚可能已被占用或重复注册。 - 引脚传递与存储错误: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
相关产品推荐
相关产品推荐

