Skip to content

Commit da28a7d

Browse files
committed
fix: improve the state engine and clean boolean by adding a substep.
--- Key Changes: 1. State Machine Asynchronicity: * Added TMC_ControlState::NONE to the enum to represent an idle "post-power" state. * Introduced the postPowerState class member to store pending calibration tasks when power is lost. * Refactored TMC_ControlState::waitPower logic into a dedicated private method handleStateWaitPower(). This method now checks for a postPowerState and automatically resumes the pending task once power is stable. 2. Removal of Blocking Loops: * Removed all while(!hasPower()) { Delay(100); } blocking calls within the Run() state machine. * In states like Pidautotune, CoggingCalibration, and SlewRateCalibration, the driver now detects missing power, sets the postPowerState, and transitions to waitPower asynchronously. 3. Code Architecture & Readability: * Extracted the logic for complex states (waitPower, Running, FullCalibration) into private methods: handleStateWaitPower(), handleStateRunning(), and handleStateFullCalibration(). * Reduced the size of the Run() loop, making the overall state transitions much clearer. * Simplified the FullCalibration workflow to be non-blocking regarding power availability. 4. Stability: * Maintained the allowStateChange guard mechanism to ensure atomic operations (like actual SPI register tuning) are not interrupted by external state requests. * Ensured all code comments and newly added logic are in English.
1 parent 84ac723 commit da28a7d

2 files changed

Lines changed: 133 additions & 117 deletions

File tree

Firmware/FFBoard/UserExtensions/Inc/TMC4671.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ enum class TMC_ControlState : uint32_t {uninitialized,waitPower,Shutdown,Running
6666
#ifdef COGGING_TABLE_FLASH_START_ADDRESS
6767
,CoggingCalibration
6868
#endif
69-
,SlewRateCalibration
69+
,SlewRateCalibration, NONE
7070
};
7171

7272
enum class TMC_PwmMode : uint8_t {off = 0,HSlow_LShigh = 1, HShigh_LSlow = 2, res2 = 3, res3 = 4, PWM_LS = 5, PWM_HS = 6, PWM_FOC = 7};
@@ -680,6 +680,7 @@ friend class TMCDebugBridge;
680680
TMC_ControlState state = TMC_ControlState::uninitialized;
681681
TMC_ControlState laststate = TMC_ControlState::uninitialized;
682682
TMC_ControlState requestedState = TMC_ControlState::Shutdown;
683+
TMC_ControlState postPowerState = TMC_ControlState::NONE;
683684
MotionMode curMotionMode = MotionMode::stop;
684685
MotionMode lastMotionMode = MotionMode::stop;
685686
MotionMode nextMotionMode = MotionMode::stop;
@@ -744,6 +745,10 @@ friend class TMCDebugBridge;
744745
// void ABN_init();
745746
// void AENC_init();
746747

748+
void handleStateWaitPower();
749+
void handleStateRunning();
750+
void handleStateFullCalibration();
751+
747752
void encoderInit();
748753
void errorCallback(const Error &error, bool cleared);
749754
bool pidAutoTune();

Firmware/FFBoard/UserExtensions/Src/TMC4671.cpp

Lines changed: 127 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -509,69 +509,21 @@ void TMC4671::Run(){
509509
break;
510510

511511
case TMC_ControlState::waitPower:
512-
{
513-
allowStateChange = false;
514-
pulseClipLed(); // blink led
515-
// if powered check ADCs and go to encoder calibration
516-
if(!hasPower() || emergency){
517-
this->powerCheckCounter = 0;
518-
Delay(250);
519-
break;
520-
}
521-
if(++this->powerCheckCounter > 5 && !powerInitialized){
522-
initializeWithPower();
523-
}
524-
if(powerInitialized){
525-
allowStateChange = true;
526-
}
527-
Delay(100);
512+
handleStateWaitPower();
528513
break;
529-
}
530514

531515
case TMC_ControlState::FullCalibration:
532-
{
533-
fullCalibrationInProgress = true;
534-
/*
535-
* Wait for power (OK)
536-
* Calibrate ADC offsets (OK)
537-
* Measure motor response
538-
* depending on encoder do encoder parameter estimation
539-
* align and store phiE for single phase AENC or indexed ABN enc
540-
*
541-
* If at any point external movement is detected abort
542-
*/
543-
// Wait for Power
544-
while(!hasPower()){
545-
Delay(100);
546-
}
547-
curFilters.flux.params.enable = false;
548-
setBiquadFlux(curFilters.flux);
549-
// Calibrate ADC
550-
enablePin.set();
551-
setPwm(TMC_PwmMode::PWM_FOC); // enable foc to calibrate adc
552-
Delay(50);
553-
if(calibrateAdcOffset(500)){
554-
saveAdcParams();
555-
}else{
556-
calibFailCb();
557-
break;
558-
}
559-
560-
// Encoder
561-
calibrateEncoder();
562-
setEncoderType(conf.motconf.enctype);
563-
recalibrationRequired = false;
564-
curFilters.flux.params.enable = true;
565-
setBiquadFlux(curFilters.flux);
516+
handleStateFullCalibration();
566517
break;
567-
}
518+
568519
case TMC_ControlState::Pidautotune:
569520
{
570-
allowStateChange = false;
571-
// Wait for Power
572-
while(!hasPower()){
573-
Delay(100);
521+
if(!hasPower()){
522+
this->postPowerState = TMC_ControlState::Pidautotune;
523+
changeState(TMC_ControlState::waitPower);
524+
break;
574525
}
526+
allowStateChange = false;
575527
pidAutoTune();
576528
allowStateChange = true;
577529
changeState(laststate,false);
@@ -581,11 +533,12 @@ void TMC4671::Run(){
581533
#ifdef COGGING_TABLE_FLASH_START_ADDRESS
582534
case TMC_ControlState::CoggingCalibration:
583535
{
584-
allowStateChange = false;
585-
// Wait for Power
586-
while(!hasPower()){
587-
Delay(100);
536+
if(!hasPower()){
537+
this->postPowerState = TMC_ControlState::CoggingCalibration;
538+
changeState(TMC_ControlState::waitPower);
539+
break;
588540
}
541+
allowStateChange = false;
589542
calibrateCogging();
590543
allowStateChange = true;
591544
changeState(laststate,false);
@@ -599,57 +552,8 @@ void TMC4671::Run(){
599552
break;
600553

601554
case TMC_ControlState::Running:
602-
{
603-
#ifdef COGGING_TABLE_FLASH_START_ADDRESS
604-
// Update anti-cogging compensation
605-
if(cogging_enabled){
606-
uint16_t pos_mechanical = (uint16_t)getPos(); // Mechanical position 0-65535
607-
const uint16_t current_index = (uint32_t)pos_mechanical * CALIB_MAP_SIZE / 65536;
608-
609-
if(current_index < CALIB_MAP_SIZE){
610-
// Apply compensation torque equal to the measured cogging torque
611-
const int16_t compensation_torque = -data_cogging[current_index];
612-
// Write to PID_TORQUE_OFFSET (register 0x65)
613-
updateReg(0x65, compensation_torque, 0xffff, 16);
614-
} else {
615-
// If the index is out of bounds, ensure the offset is zero
616-
updateReg(0x65, 0, 0xffff, 16);
617-
}
618-
}
619-
#endif
620-
621-
// Check status, Temps, Everything alright?
622-
uint32_t tick = HAL_GetTick();
623-
if(tick - lastStatTime > 2000){ // Every 2s
624-
lastStatTime = tick;
625-
statusCheck();
626-
// Get enable input. If tmc does not reply the result will read 0 or 0xffffffff (not possible normally)
627-
uint32_t pins = readReg(0x76);
628-
bool tmc_en = ((pins >> 15) & 0x01) && pins != 0xffffffff;
629-
if(!tmc_en && motorEnabledRequested){ // Hardware emergency.
630-
this->estopTriggered = true;
631-
this->emergencyStop(false);
632-
ErrorHandler::addError(estopError);
633-
//changeState(TMC_ControlState::HardError);
634-
}
635-
636-
// Temperature sense
637-
if(conf.hwconf.thermistorSettings.temperatureEnabled){
638-
float temp = getTemp();
639-
if(temp > conf.hwconf.thermistorSettings.temp_limit){
640-
changeState(TMC_ControlState::OverTemp);
641-
pulseErrLed();
642-
}
643-
}
644-
645-
}
646-
#ifdef COGGING_TABLE_FLASH_START_ADDRESS
647-
Delay(1); // Update anticogging at ~1khz
648-
#else
649-
Delay(200);
650-
#endif
651-
}
652-
break;
555+
handleStateRunning();
556+
break;
653557

654558
case TMC_ControlState::Shutdown:
655559
Delay(100);
@@ -711,11 +615,12 @@ void TMC4671::Run(){
711615

712616
case TMC_ControlState::SlewRateCalibration:
713617
{
714-
allowStateChange = false;
715-
// Wait for Power
716-
while(!hasPower()){
717-
Delay(100);
618+
if(!hasPower()){
619+
this->postPowerState = TMC_ControlState::SlewRateCalibration;
620+
changeState(TMC_ControlState::waitPower);
621+
break;
718622
}
623+
allowStateChange = false;
719624
measureMaxSlewRate();
720625
allowStateChange = true;
721626
if(fullCalibrationInProgress){
@@ -757,7 +662,6 @@ void TMC4671::Run(){
757662
}
758663
} // End while
759664
}
760-
761665
void TMC4671::calibrateEncoder(){
762666
if(conf.motconf.enctype == EncoderType_TMC::abn) {
763667
estimateABNparams();
@@ -3487,4 +3391,111 @@ void TMC4671::measureMaxSlewRate(){
34873391
setMotionMode(lastmode,true);
34883392
}
34893393

3394+
void TMC4671::handleStateWaitPower() {
3395+
allowStateChange = false;
3396+
pulseClipLed(); // blink led
3397+
3398+
if (!hasPower() || emergency) {
3399+
this->powerCheckCounter = 0;
3400+
Delay(250);
3401+
return;
3402+
}
3403+
3404+
if (++this->powerCheckCounter > 5) {
3405+
if (!powerInitialized) {
3406+
initializeWithPower();
3407+
}
3408+
allowStateChange = true;
3409+
3410+
// If a calibration was pending power, go there now
3411+
if (this->postPowerState != TMC_ControlState::NONE) {
3412+
changeState(this->postPowerState);
3413+
this->postPowerState = TMC_ControlState::NONE;
3414+
} else if (encoderAligned) {
3415+
// Normal flow if encoder is already aligned
3416+
changeState(requestedState);
3417+
}
3418+
}
3419+
Delay(100);
3420+
}
3421+
3422+
void TMC4671::handleStateRunning() {
3423+
#ifdef COGGING_TABLE_FLASH_START_ADDRESS
3424+
// Update anti-cogging compensation
3425+
if (cogging_enabled) {
3426+
uint16_t pos_mechanical = (uint16_t)getPos(); // Mechanical position 0-65535
3427+
const uint16_t current_index = (uint32_t)pos_mechanical * CALIB_MAP_SIZE / 65536;
3428+
3429+
if (current_index < CALIB_MAP_SIZE) {
3430+
// Apply compensation torque equal to the measured cogging torque
3431+
const int16_t compensation_torque = -data_cogging[current_index];
3432+
// Write to PID_TORQUE_OFFSET (register 0x65)
3433+
updateReg(0x65, compensation_torque, 0xffff, 16);
3434+
} else {
3435+
// If the index is out of bounds, ensure the offset is zero
3436+
updateReg(0x65, 0, 0xffff, 16);
3437+
}
3438+
}
3439+
#endif
3440+
3441+
// Check status, Temps, Everything alright?
3442+
uint32_t tick = HAL_GetTick();
3443+
if (tick - lastStatTime > 2000) { // Every 2s
3444+
lastStatTime = tick;
3445+
statusCheck();
3446+
// Get enable input. If tmc does not reply the result will read 0 or 0xffffffff (not possible normally)
3447+
uint32_t pins = readReg(0x76);
3448+
bool tmc_en = ((pins >> 15) & 0x01) && pins != 0xffffffff;
3449+
if (!tmc_en && motorEnabledRequested) { // Hardware emergency.
3450+
this->estopTriggered = true;
3451+
this->emergencyStop(false);
3452+
ErrorHandler::addError(estopError);
3453+
}
3454+
3455+
// Temperature sense
3456+
if (conf.hwconf.thermistorSettings.temperatureEnabled) {
3457+
float temp = getTemp();
3458+
if (temp > conf.hwconf.thermistorSettings.temp_limit) {
3459+
changeState(TMC_ControlState::OverTemp);
3460+
pulseErrLed();
3461+
}
3462+
}
3463+
}
3464+
#ifdef COGGING_TABLE_FLASH_START_ADDRESS
3465+
Delay(1); // Update anticogging at ~1khz
3466+
#else
3467+
Delay(200);
3468+
#endif
3469+
}
3470+
3471+
void TMC4671::handleStateFullCalibration() {
3472+
if (!hasPower()) {
3473+
this->postPowerState = TMC_ControlState::FullCalibration;
3474+
changeState(TMC_ControlState::waitPower);
3475+
return;
3476+
}
3477+
3478+
fullCalibrationInProgress = true;
3479+
curFilters.flux.params.enable = false;
3480+
setBiquadFlux(curFilters.flux);
3481+
3482+
// Calibrate ADC
3483+
enablePin.set();
3484+
setPwm(TMC_PwmMode::PWM_FOC); // enable foc to calibrate adc
3485+
Delay(50);
3486+
if (calibrateAdcOffset(500)) {
3487+
saveAdcParams();
3488+
} else {
3489+
calibFailCb();
3490+
return;
3491+
}
3492+
3493+
// Encoder
3494+
calibrateEncoder();
3495+
setEncoderType(conf.motconf.enctype);
3496+
recalibrationRequired = false;
3497+
curFilters.flux.params.enable = true;
3498+
setBiquadFlux(curFilters.flux);
3499+
}
3500+
34903501
#endif

0 commit comments

Comments
 (0)