๐Ÿ› ๏ธ Common HF-TMC9660 Operations

This guide covers the most frequently used operations when working with the HF-TMC9660 driver. Each example includes proper error handling and follows best practices for robust motor control applications.


๐ŸŽฏ What Youโ€™ll Learn


๐Ÿš€ Essential Initialization Pattern

Every application must follow this initialization sequence:

#include "TMC9660.hpp"

// Your communication interface implementation
YourCommInterface bus;
TMC9660 driver(bus);

// STEP 1: CRITICAL - Configure for Parameter Mode
tmc9660::BootloaderConfig cfg{};
cfg.boot.boot_mode = tmc9660::bootcfg::BootMode::Parameter;  // ESSENTIAL!
cfg.boot.start_motor_control = true;
cfg.spiComm.boot_spi_iface = tmc9660::bootcfg::SPIInterface::IFACE0;
cfg.uart.baud_rate = tmc9660::bootcfg::BaudRate::BR115200;

auto result = driver.bootloaderInit(&cfg);
if (result != TMC9660::BootloaderInitResult::Success) {
    // Handle bootloader failure - motor control won't work without this
    return -1;
}

// Now you can use all motor control functions...

๐Ÿ”ง Motor Configuration

BLDC Motor Setup

bool configureBLDCMotor(TMC9660& driver) {
    // Step 1: Set motor type and pole pairs
    if (!driver.motorConfig.setType(tmc9660::tmcl::MotorType::BLDC_MOTOR, 7)) {
        std::cerr << "Failed to set BLDC motor type" << std::endl;
        return false;
    }
    
    // Step 2: Configure current limits (SAFETY FIRST!)
    if (!driver.motorConfig.setMaxTorqueCurrent(2000)) {  // 2A max
        std::cerr << "Failed to set torque current limit" << std::endl;
        return false;
    }
    
    if (!driver.motorConfig.setMaxFluxCurrent(1000)) {    // 1A flux
        std::cerr << "Failed to set flux current limit" << std::endl;
        return false;
    }
    
    // Step 3: Configure feedback sensors
    if (!driver.feedbackSense.configureHall()) {
        std::cerr << "Failed to configure Hall sensors" << std::endl;
        return false;
    }
    
    // Step 4: Set PWM frequency and switching scheme
    if (!driver.motorConfig.setPWMFrequency(25000)) {     // 25 kHz
        std::cerr << "Failed to set PWM frequency" << std::endl;
        return false;
    }
    
    if (!driver.motorConfig.setPWMSwitchingScheme(
            tmc9660::tmcl::PwmSwitchingScheme::SVPWM)) {
        std::cerr << "Failed to set SVPWM scheme" << std::endl;
        return false;
    }
    
    // Step 5: Configure FOC control gains
    if (!driver.focControl.setCurrentLoopGains(50, 100)) {
        std::cerr << "Failed to set current PI gains" << std::endl;
        return false;
    }
    
    if (!driver.focControl.setVelocityLoopGains(800, 1)) {
        std::cerr << "Failed to set velocity PI gains" << std::endl;
        return false;
    }
    
    // Step 6: Enable commutation (LAST STEP!)
    if (!driver.motorConfig.setCommutationMode(
            tmc9660::tmcl::CommutationMode::FOC_HALL_SENSOR)) {
        std::cerr << "Failed to enable FOC commutation" << std::endl;
        return false;
    }
    
    std::cout << "โœ… BLDC motor configured successfully" << std::endl;
    return true;
}

Stepper Motor Setup

bool configureStepperMotor(TMC9660& driver) {
    // Step 1: Set motor type (steppers use 1 pole pair)
    if (!driver.motorConfig.setType(tmc9660::tmcl::MotorType::STEPPER_MOTOR, 1)) {
        return false;
    }
    
    // Step 2: Configure encoder for feedback
    if (!driver.feedbackSense.configureABNEncoder(1024)) {  // 1024 CPR
        return false;
    }
    
    // Step 3: Set current limits
    if (!driver.motorConfig.setMaxTorqueCurrent(1500)) {    // 1.5A
        return false;
    }
    
    // Step 4: Configure for FOC with encoder feedback
    if (!driver.motorConfig.setCommutationMode(
            tmc9660::tmcl::CommutationMode::FOC_ENCODER)) {
        return false;
    }
    
    return true;
}

DC Motor Setup

bool configureDCMotor(TMC9660& driver) {
    // Step 1: Set motor type
    if (!driver.motorConfig.setType(tmc9660::tmcl::MotorType::DC_MOTOR)) {
        return false;
    }
    
    // Step 2: Set current limit
    if (!driver.motorConfig.setMaxTorqueCurrent(1500)) {    // 1.5A
        return false;
    }
    
    // Step 3: Configure encoder for velocity feedback
    if (!driver.feedbackSense.configureABNEncoder(1024)) {
        return false;
    }
    
    // Step 4: Enable open-loop current mode
    if (!driver.motorConfig.setCommutationMode(
            tmc9660::tmcl::CommutationMode::FOC_OPENLOOP_CURRENT_MODE)) {
        return false;
    }
    
    return true;
}

โšก FOC Control Operations

Velocity Control

bool setVelocityControl(TMC9660& driver, int32_t target_rpm) {
    // Configure velocity sensor
    if (!driver.focControl.setVelocitySensor(
            tmc9660::tmcl::VelocitySensorSelection::ABN1_ENCODER)) {
        return false;
    }
    
    // Set velocity PI gains (tune these for your system)
    if (!driver.focControl.setVelocityLoopGains(800, 1)) {
        return false;
    }
    
    // Command target velocity
    if (!driver.focControl.setTargetVelocity(target_rpm)) {
        return false;
    }
    
    std::cout << "Velocity control: " << target_rpm << " RPM" << std::endl;
    return true;
}

// Monitor velocity control
void monitorVelocity(TMC9660& driver) {
    int32_t actual_velocity = 0;
    if (driver.focControl.getActualVelocity(actual_velocity)) {
        std::cout << "Current velocity: " << actual_velocity << " RPM" << std::endl;
    }
    
    // Check if velocity target is reached
    uint32_t threshold = 0;
    driver.focControl.getVelocityReachedThreshold(threshold);
    // Implement your logic based on threshold
}

Position Control

bool setPositionControl(TMC9660& driver, int32_t target_position) {
    // Configure position sensor
    if (!driver.focControl.setPositionSensor(
            tmc9660::tmcl::PositionSensorSelection::ABN1_ENCODER)) {
        return false;
    }
    
    // Set position PI gains
    if (!driver.focControl.setPositionLoopGains(100, 0)) {  // P=100, I=0
        return false;
    }
    
    // Set position limits for safety
    if (!driver.focControl.setPositionLimitLow(-100000)) {
        return false;
    }
    
    if (!driver.focControl.setPositionLimitHigh(100000)) {
        return false;
    }
    
    // Command target position
    if (!driver.focControl.setTargetPosition(target_position)) {
        return false;
    }
    
    std::cout << "Position control: " << target_position << " units" << std::endl;
    return true;
}

Torque Control

bool setTorqueControl(TMC9660& driver, int16_t target_current_ma) {
    // Set current PI gains
    if (!driver.focControl.setCurrentLoopGains(50, 100)) {
        return false;
    }
    
    // Command target torque (current)
    if (!driver.focControl.setTargetTorque(target_current_ma)) {
        return false;
    }
    
    std::cout << "Torque control: " << target_current_ma << " mA" << std::endl;
    return true;
}

๐Ÿ“Š Telemetry and Monitoring

Basic Telemetry Reading

struct TelemetryData {
    float chip_temperature;
    int16_t motor_current;
    float supply_voltage;
    int32_t actual_position;
    int32_t actual_velocity;
};

bool readTelemetry(TMC9660& driver, TelemetryData& data) {
    // Read chip temperature
    data.chip_temperature = driver.telemetry.getChipTemperature();
    
    // Read motor current
    data.motor_current = driver.telemetry.getMotorCurrent();
    
    // Read supply voltage
    data.supply_voltage = driver.telemetry.getSupplyVoltage();
    
    // Read actual position and velocity
    bool pos_ok = driver.focControl.getActualPosition(data.actual_position);
    bool vel_ok = driver.focControl.getActualVelocity(data.actual_velocity);
    
    return pos_ok && vel_ok;
}

void printTelemetry(const TelemetryData& data) {
    std::cout << "Telemetry:" << std::endl;
    std::cout << "  Temperature: " << data.chip_temperature << " ยฐC" << std::endl;
    std::cout << "  Current:     " << data.motor_current << " mA" << std::endl;
    std::cout << "  Voltage:     " << data.supply_voltage << " V" << std::endl;
    std::cout << "  Position:    " << data.actual_position << " units" << std::endl;
    std::cout << "  Velocity:    " << data.actual_velocity << " RPM" << std::endl;
}

Advanced Current Sensing

bool configureCurrentSensing(TMC9660& driver) {
    // Set ADC shunt configuration
    if (!driver.currentSensing.setShuntType(
            tmc9660::tmcl::AdcShuntType::THREE_SHUNT)) {
        return false;
    }
    
    // Configure current sense amplifier gains
    if (!driver.currentSensing.setCSAGain(
            tmc9660::tmcl::CsaGain::GAIN_20, 
            tmc9660::tmcl::CsaGain::GAIN_20)) {
        return false;
    }
    
    // Set scaling factor
    if (!driver.currentSensing.setScalingFactor(1000)) {
        return false;
    }
    
    // Calibrate ADC offsets (motor must be stationary!)
    if (!driver.currentSensing.calibrateOffsets(true, 1000)) {
        std::cerr << "ADC calibration failed" << std::endl;
        return false;
    }
    
    std::cout << "โœ… Current sensing configured and calibrated" << std::endl;
    return true;
}

void readDetailedCurrents(TMC9660& driver) {
    // Read raw ADC values
    int16_t adc0, adc1, adc2, adc3;
    if (driver.currentSensing.readRaw(adc0, adc1, adc2, adc3)) {
        std::cout << "Raw ADC: " << adc0 << ", " << adc1 << ", " 
                  << adc2 << ", " << adc3 << std::endl;
    }
    
    // Read scaled and offset-compensated values
    if (driver.currentSensing.readScaledAndOffset(adc0, adc1, adc2, adc3)) {
        std::cout << "Scaled ADC: " << adc0 << ", " << adc1 << ", " 
                  << adc2 << ", " << adc3 << std::endl;
    }
}

๐Ÿ›ก๏ธ Safety and Protection

Configure Protection Limits

bool configureProtection(TMC9660& driver) {
    // Voltage protection
    if (!driver.protection.setOverVoltageLimit(48000)) {    // 48V max
        return false;
    }
    
    if (!driver.protection.setUnderVoltageLimit(8000)) {    // 8V min
        return false;
    }
    
    // Temperature protection
    if (!driver.protection.setOverTemperatureLimit(85)) {   // 85ยฐC max
        return false;
    }
    
    // Current protection (already set in motor config, but can be adjusted)
    if (!driver.motorConfig.setMaxTorqueCurrent(2000)) {    // 2A max
        return false;
    }
    
    std::cout << "โœ… Protection limits configured" << std::endl;
    return true;
}

bool checkFaultStatus(TMC9660& driver) {
    uint32_t fault_status = 0;
    if (!driver.readParameter(tmc9660::tmcl::Parameters::FAULT_STATUS, fault_status)) {
        return false;
    }
    
    if (fault_status != 0) {
        std::cout << "โš ๏ธ  Fault detected: 0x" << std::hex << fault_status << std::endl;
        
        // Clear faults if appropriate
        if (driver.sendCommand(tmc9660::tmcl::Op::CLE, 0xFF, 0, 0)) {
            std::cout << "Faults cleared" << std::endl;
        }
        
        return false; // Indicate fault condition
    }
    
    return true; // No faults
}

๐ŸŽ›๏ธ Motion Ramp Control

Configure Hardware Ramps

bool configureMotionRamps(TMC9660& driver) {
    // Enable ramp generator
    if (!driver.ramp.enable(true)) {
        return false;
    }
    
    // Set acceleration parameters (ยต units/sยฒ)
    if (!driver.ramp.setAcceleration(1000, 2000, 5000)) {  // A1, A2, Amax
        return false;
    }
    
    // Set deceleration parameters (ยต units/sยฒ)  
    if (!driver.ramp.setDeceleration(1000, 2000, 5000)) {  // D1, D2, Dmax
        return false;
    }
    
    // Set velocity parameters (ยต units/s)
    // Vstart, Vstop, V1, V2, Vmax
    if (!driver.ramp.setVelocities(0, 0, 500, 1000, 2000)) {
        return false;
    }
    
    // Enable feedforward control
    if (!driver.ramp.enableFeedForward(
            true, true, 1000, 
            tmc9660::tmcl::AccelerationFFShift::SHIFT_0)) {
        return false;
    }
    
    std::cout << "โœ… Motion ramps configured" << std::endl;
    return true;
}

void monitorRampStatus(TMC9660& driver) {
    int32_t ramp_velocity = 0;
    int32_t ramp_position = 0;
    
    if (driver.ramp.getRampVelocity(ramp_velocity)) {
        std::cout << "Ramp velocity: " << ramp_velocity << std::endl;
    }
    
    if (driver.ramp.getRampPosition(ramp_position)) {
        std::cout << "Ramp position: " << ramp_position << std::endl;
    }
}

๐Ÿšจ Emergency Stop and Safe Shutdown

Emergency Stop Procedure

bool emergencyStop(TMC9660& driver) {
    std::cout << "๐Ÿšจ EMERGENCY STOP ACTIVATED!" << std::endl;
    
    // Immediate motor stop
    if (!driver.focControl.stop()) {
        std::cerr << "Failed to stop motor!" << std::endl;
        return false;
    }
    
    // Disable commutation
    if (!driver.motorConfig.setCommutationMode(
            tmc9660::tmcl::CommutationMode::SYSTEM_OFF)) {
        std::cerr << "Failed to disable commutation!" << std::endl;
        return false;
    }
    
    // Check for faults
    checkFaultStatus(driver);
    
    std::cout << "โœ… Emergency stop completed" << std::endl;
    return true;
}

Graceful Shutdown

bool gracefulShutdown(TMC9660& driver) {
    std::cout << "Initiating graceful shutdown..." << std::endl;
    
    // Ramp down to zero velocity
    if (!driver.focControl.setTargetVelocity(0)) {
        return false;
    }
    
    // Wait for motor to stop (implement your own timeout logic)
    std::this_thread::sleep_for(std::chrono::seconds(2));
    
    // Disable commutation
    if (!driver.motorConfig.setCommutationMode(
            tmc9660::tmcl::CommutationMode::SYSTEM_OFF)) {
        return false;
    }
    
    std::cout << "โœ… Graceful shutdown completed" << std::endl;
    return true;
}

๐Ÿ“‹ Best Practices Checklist

Initialization

Operation

Safety


๐ŸŽฏ Next Steps

With these common operations mastered, explore advanced features:

๐Ÿ‘‰ Hardware-Agnostic Examples - Complete application scenarios

๐Ÿ‘‰ API Reference - Complete function documentation


โฌ…๏ธ Building Examples โฌ†๏ธ Back to Index Next โžก๏ธ GitHub Pages

Remember: Always check return values and implement proper error handling in production code!