Open FFBoard
Open source force feedback firmware
Loading...
Searching...
No Matches
TMC4671.cpp
Go to the documentation of this file.
1/*
2 * TMC4671.cpp
3 *
4 * Created on: Feb 1, 2020
5 * Author: Yannick
6 */
7
8#include "TMC4671.h"
9#ifdef TMC4671DRIVER
10#include "ledEffects.h"
11#include "voltagesense.h"
12#include <math.h>
13#include <assert.h>
14#include "ErrorHandler.h"
15#include "cpp_target_config.h"
16#define MAX_TMC_DRIVERS 3
17
19 .name = "TMC4671 (CS 1)",
20 .id=CLSID_MOT_TMC0, // 1
21};
22
23
25 return motor_spi.isPinFree(*motor_spi.getCsPin(0));
26}
27
28
30 .name = "TMC4671 (CS 2)" ,
31 .id=CLSID_MOT_TMC1,
32};
33
34
36 return motor_spi.isPinFree(*motor_spi.getCsPin(1));
37}
38
39
40
41
43 .name = "TMC4671" ,
44 .id=CLSID_MOT_TMC0,
45};
46
47
48
49TMC4671::TMC4671(SPIPort& spiport,OutputPin cspin,uint8_t address) :
50 CommandHandler("tmc", CLSID_MOT_TMC0,address-1), SPIDevice{motor_spi,cspin},Thread("TMC", TMC_THREAD_MEM, TMC_THREAD_PRIO)
51{
53 setAddress(address);
55 spiConfig.peripheral = motor_spi.getPortHandle()->Init;
56 spiConfig.peripheral.Mode = SPI_MODE_MASTER;
57 spiConfig.peripheral.Direction = SPI_DIRECTION_2LINES;
58 spiConfig.peripheral.DataSize = SPI_DATASIZE_8BIT;
59 spiConfig.peripheral.CLKPolarity = SPI_POLARITY_HIGH;
60 spiConfig.peripheral.CLKPhase = SPI_PHASE_2EDGE;
61 spiConfig.peripheral.NSS = SPI_NSS_SOFT;
62 spiConfig.peripheral.BaudRatePrescaler = spiPort.getClosestPrescaler(8e6,0,10e6).first; // 8 target, 10MHz max
63 spiConfig.peripheral.FirstBit = SPI_FIRSTBIT_MSB;
64 spiConfig.peripheral.TIMode = SPI_TIMODE_DISABLE;
65 spiConfig.peripheral.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
66 spiConfig.cspol = true;
67
68#ifdef TMC4671_SPI_DATA_IDLENESS
69 spiConfig.peripheral.MasterInterDataIdleness = TMC4671_SPI_DATA_IDLENESS;
70#endif
71
72 spiPort.takeSemaphore();
73 spiPort.configurePort(&spiConfig.peripheral);
74 spiPort.giveSemaphore();
75
76 this->restoreFlash();
78}
79
80
82 enablePin.reset();
83 //recordSpiAddrUsed(0);
84}
85
86
88
89 return info;
90}
91
92
93void TMC4671::setAddress(uint8_t address){
94 if (address == 1){
95 this->flashAddrs = TMC4671FlashAddrs({ADR_TMC1_MOTCONF, ADR_TMC1_CPR, ADR_TMC1_ENCA, ADR_TMC1_OFFSETFLUX, ADR_TMC1_TORQUE_P, ADR_TMC1_TORQUE_I, ADR_TMC1_FLUX_P, ADR_TMC1_FLUX_I,ADR_TMC1_ADC_I0_OFS,ADR_TMC1_ADC_I1_OFS,ADR_TMC1_ENC_OFFSET,ADR_TMC1_PHIE_OFS,ADR_TMC1_TRQ_FILT});
96 }else if (address == 2)
97 {
98 this->flashAddrs = TMC4671FlashAddrs({ADR_TMC2_MOTCONF, ADR_TMC2_CPR, ADR_TMC2_ENCA, ADR_TMC2_OFFSETFLUX, ADR_TMC2_TORQUE_P, ADR_TMC2_TORQUE_I, ADR_TMC2_FLUX_P, ADR_TMC2_FLUX_I,ADR_TMC2_ADC_I0_OFS,ADR_TMC2_ADC_I1_OFS,ADR_TMC2_ENC_OFFSET,ADR_TMC2_PHIE_OFS,ADR_TMC2_TRQ_FILT});
99 }else if (address == 3)
100 {
101 this->flashAddrs = TMC4671FlashAddrs({ADR_TMC3_MOTCONF, ADR_TMC3_CPR, ADR_TMC3_ENCA, ADR_TMC3_OFFSETFLUX, ADR_TMC3_TORQUE_P, ADR_TMC3_TORQUE_I, ADR_TMC3_FLUX_P, ADR_TMC3_FLUX_I,ADR_TMC3_ADC_I0_OFS,ADR_TMC3_ADC_I1_OFS,ADR_TMC3_ENC_OFFSET,ADR_TMC3_PHIE_OFS,ADR_TMC3_TRQ_FILT});
102 }
103 //this->setAxis((char)('W'+address));
104}
105
106
108 uint16_t mconfint = TMC4671::encodeMotToInt(this->conf.motconf);
109 uint16_t abncpr = this->conf.motconf.enctype == EncoderType_TMC::abn ? this->abnconf.cpr : this->aencconf.cpr;
110 // Save flash
111 Flash_Write(flashAddrs.mconf, mconfint);
112 Flash_Write(flashAddrs.cpr, abncpr);
115
116 Flash_Write(flashAddrs.torque_p, curPids.torqueP);
117 Flash_Write(flashAddrs.torque_i, curPids.torqueI);
118 Flash_Write(flashAddrs.flux_p, curPids.fluxP);
119 Flash_Write(flashAddrs.flux_i, curPids.fluxI);
120 Flash_Write(flashAddrs.encOffset,(uint16_t)abnconf.posOffsetFromIndex);
121
122 // If encoder is ABN and uses index save the last configured offset
123// if(this->conf.motconf.enctype == EncoderType_TMC::abn && this->abnconf.useIndex && encoderAligned){
124// Flash_Write(flashAddrs.phieOffset, abnconf.phiEoffset);
125// }
126
127 uint16_t filterval = (torqueFilterConf.params.freq & 0x1fff) | ((uint8_t)(torqueFilterConf.mode) << 13);
128 Flash_Write(flashAddrs.torqueFilter, filterval);
129
130}
131
136 Flash_Write(flashAddrs.ADC_i0_ofs, conf.adc_I0_offset);
137 Flash_Write(flashAddrs.ADC_i1_ofs, conf.adc_I1_offset);
138 adcSettingsStored = true;
139}
140
146 uint16_t mconfint;
147 uint16_t abncpr = 0;
148
149 // Read flash
150 if(Flash_Read(flashAddrs.mconf, &mconfint))
151 this->conf.motconf = TMC4671::decodeMotFromInt(mconfint);
152
153 if(Flash_Read(flashAddrs.cpr, &abncpr))
154 setCpr(abncpr);
155
156 // Pids
157 Flash_Read(flashAddrs.torque_p, &this->curPids.torqueP);
158 Flash_Read(flashAddrs.torque_i, &this->curPids.torqueI);
159 Flash_Read(flashAddrs.flux_p, &this->curPids.fluxP);
160 Flash_Read(flashAddrs.flux_i, &this->curPids.fluxI);
161 uint16_t encofs;
162 Flash_Read(flashAddrs.encOffset,&encofs);
163 this->abnconf.posOffsetFromIndex = (int16_t)encofs;
164
165 Flash_Read(flashAddrs.offsetFlux, (uint16_t*)&this->maxOffsetFlux);
166
167 // Restore ADC settings
168 if(Flash_Read(flashAddrs.ADC_i0_ofs,&conf.adc_I0_offset) && Flash_Read(flashAddrs.ADC_i1_ofs,&conf.adc_I1_offset)){
169 adcSettingsStored = true; // Previous adc settings restored
170 }else{
171 recalibrationRequired = true; // Never stored
172 }
173
174// abnconf.phiEoffset = Flash_ReadDefault(flashAddrs.phieOffset,0);
175// if(abnconf.phiEoffset != 0){
176// phiErestored = true;
177// }
178
179 uint16_t miscval;
180 if(Flash_Read(flashAddrs.encA, &miscval)){
181 restoreEncHallMisc(miscval);
182 encHallRestored = true;
183 }else{
184 // set first hwconf if we can't restore
185 this->setHwType(TMC4671::tmc4671_hw_configs[0].hwVersion);
186 }
187 uint16_t filterval;
188 if(Flash_Read(flashAddrs.torqueFilter, &filterval)){
189 torqueFilterConf.params.freq = filterval & 0x1fff;
190 torqueFilterConf.mode = static_cast<TMCbiquadpreset>((filterval >> 13) & 0x7);
191 }
192
193}
194
196 int32_t intV = getIntV();
197 return (intV > 10000) && (getExtV() > 10000) && (intV < 78000);
198}
199
200// Checks if important parameters are set to valid values
202
203 if(this->conf.motconf.motor_type == MotorType::NONE ||!adcCalibrated || !initialized || !powerInitialized){
204 return false;
205 }
206
207 // Encoder
208 if(this->conf.motconf.phiEsource == PhiE::abn && abnconf.cpr == 0){
209 return false;
210 }
211 if(this->conf.motconf.phiEsource == PhiE::abn || this->conf.motconf.phiEsource == PhiE::aenc){
212 if(!encoderAligned){
213 return false;
214 }
215 }
216 if(this->conf.motconf.phiEsource == PhiE::ext && drvEncoder->getEncoderType() == EncoderType::NONE && !encoderAligned){
217 return false;
218 }
219
220 return true;
221}
222
227 writeReg(1, 0);
228 return(readReg(0) == 0x34363731);
229}
230
235 writeReg(0x03, 1); // adc raw data to VM/agpiA
236 uint32_t agpiA_VM = readReg(0x02);
237 agpiA_VM = (agpiA_VM & 0xFFFF) - 0x7FFF - conf.hwconf.adcOffset;
238
239 return ((float)agpiA_VM * conf.hwconf.vmScaler) * 1000;
240}
241
242
248// active = true;
249// if(state == TMC_ControlState::uninitialized){
250// state = TMC_ControlState::Init_wait;
251// }
252 // Check if a TMC4671 is active and replies correctly
253 if(!pingDriver()){
255 return false;
256 }
257
258 writeReg(1, 1);
259 if(readReg(0) == 0x00010000 && allowSlowSPI){
260 /* Slow down SPI if old TMC engineering sample is detected
261 * The first version has a high chance of glitches of the MSB
262 * when high spi speeds are used.
263 * This can cause problems for some operations.
264 */
265 pulseClipLed();
266
267 this->spiConfig.peripheral.BaudRatePrescaler = spiPort.getClosestPrescaler(1e6).first; // 1MHz target
268 spiPort.configurePort(&this->spiConfig.peripheral);
269 ES_TMCdetected = true;
270 }
271
272 if(!ES_TMCdetected){
274 }
275
276 // Detect if tmc was previously uninitialized
280 }else{
282 }
283 }
284
285 // Write main constants
286
287 writeReg(0x64, 0); // No flux/torque
288 setPwm(0,conf.pwmcnt,conf.bbmL,conf.bbmH); // Set FOC @ 25khz but turn off pwm for now
289 setMotorType(conf.motconf.motor_type,conf.motconf.pole_pairs);
290 setPhiEtype(conf.motconf.phiEsource);
291 setup_HALL(hallconf); // Enables hall filter and masking
292
293 initAdc(conf.mdecA,conf.mdecB,conf.mclkA,conf.mclkB);
294 setAdcOffset(conf.adc_I0_offset, conf.adc_I1_offset);
295 setAdcScale(conf.adc_I0_scale, conf.adc_I1_scale);
297 setBiquadFlux(TMC4671Biquad(Biquad(BiquadType::lowpass, fluxFilterFreq / getPwmFreq(), 0.7,0.0), true)); // Create flux filter
298
299 // Initial adc calibration and check without PWM if power off to get basic offsets. PWM is off!
300 if(!hasPower()){
301 if(!calibrateAdcOffset(150)){
302 changeState(TMC_ControlState::HardError); // ADC or shunt amp is broken!
303 enablePin.reset();
304 return false;
305 }
306 }
307 // brake res failsafe.
308// /*
309// * Single ended input raw value
310// * 0V = 0x7fff
311// * 4.7k / (360k+4.7k) Divider on old board.
312// * 1.5k / (71.5k+1.5k) 16.121 counts 60V new. 100V VM => 2V
313// * 13106 counts/V input.
314// */
315 setBrakeLimits(this->conf.hwconf.brakeLimLow,this->conf.hwconf.brakeLimHigh); // update limit from previously loaded constants or defaults
316
317 // Status mask
318 if(ES_TMCdetected){
319 setStatusMask(0); // ES Version status output is broken
320 }else{
321 /*
322 * Enable adc clipping and pll errors
323 */
324 statusMask.asInt = 0;
325 statusMask.flags.adc_i_clipped = 1;
326 statusMask.flags.not_PLL_locked = 1;
328 }
329
330 setPids(curPids); // Write basic pids
331
332// if(hasPower()){
333// enablePin.set();
334// setPwm(TMC_PwmMode::PWM_FOC);
335// calibrateAdcOffset(400); // Calibrate ADC again with power
336// motorEnabledRequested = true;
337// }
338 //setEncoderType(conf.motconf.enctype);
339
340 // Update flags
341 readFlags(false); // Read all flags
342
343 initialized = true;
344 initTime = HAL_GetTick();
345 return initialized;
346}
347
353 if(!this->conf.hwconf.thermistorSettings.temperatureEnabled){
354 return 0;
355 }
356 TMC4671HardwareTypeConf* hwconf = &conf.hwconf;
357
358 writeReg(0x03, 2);
359 int32_t adcval = ((readReg(0x02)) & 0xffff) - 0x7fff; // Center offset
360 adcval -= hwconf->adcOffset;
361 if(adcval <= 0){
362 return 0.0;
363 }
364 float r = hwconf->thermistorSettings.thermistor_R2 * (((float)43252 / (float)adcval)); //43252 equivalent ADC count if it was 3.3V and not 2.5V
365
366 // Beta
367 r = (1.0 / 298.15) + log(r / hwconf->thermistorSettings.thermistor_R) / hwconf->thermistorSettings.thermistor_Beta;
368 r = 1.0 / r;
369 r -= 273.15;
370 return r;
371
372}
373
378 setFluxTorque(0, 0);
379 int32_t total = 0;
380 for(uint8_t i = 0;i<50;i++){
381 std::pair<int32_t,int32_t> ft = getActualTorqueFlux();
382 total += (ft.first+ft.second);
383 Delay(2);
384 }
385 return(abs(total / 50) < 100); // Check if average has a low bias
386}
387
390 return;
391 }
392 powerInitialized = true;
393 // Load ADC settings
394 if(Flash_Read(flashAddrs.ADC_i0_ofs,&conf.adc_I0_offset) && Flash_Read(flashAddrs.ADC_i1_ofs,&conf.adc_I1_offset)){
395 adcSettingsStored = true; // Previous adc settings restored
396 setAdcOffset(conf.adc_I0_offset, conf.adc_I1_offset);
397 }
398
400 adcCalibrated = true;
401 }else{
402 if(!calibrateAdcOffset(300)){
403 powerInitialized = false;
404 return; // Abort
405 }
406 }
407
408 // got power long enough. proceed to set up encoder
409 // if encoder not set up
410 enablePin.set();
411 setPwm(TMC_PwmMode::PWM_FOC); // enable foc
412 if(!encoderAligned){
413 setEncoderType(conf.motconf.enctype);
414 }else{
415 //last state
416 if(!emergency){
417 allowStateChange = true;
421 }
422 }
423
424}
425
429
431 // Main state machine
432 while(1){
433
436 }
437
438 // check if we are in a privileged state otherwise use requested state as new state
441 }
442
443 switch(this->state){
444
446 allowStateChange = false;
447 // check communication and write constants
448 if(!pingDriver() || emergency){ // driver not available or emergency was set before startup
449 initialized = false; // Assume driver is not initialized if we can not detect it
450 Delay(250);
451 break;
452 }
453 // Driver available. Write constants and go to next step
454 if(!initialized){
455 initialize();
456 }
458 break;
459
461 {
462 allowStateChange = false;
463 pulseClipLed(); // blink led
464 static uint8_t powerCheckCounter = 0;
465 // if powered check ADCs and go to encoder calibration
466 if(!hasPower() || emergency){
467 powerCheckCounter = 0;
468 Delay(250);
469 break;
470 }
471 if(++powerCheckCounter > 5 && !powerInitialized){
473 }
475 allowStateChange = true;
476 }
477 Delay(100);
478 break;
479 }
480
482 {
484 /*
485 * Wait for power (OK)
486 * Calibrate ADC offsets (OK)
487 * Measure motor response
488 * depending on encoder do encoder parameter estimation
489 * align and store phiE for single phase AENC or indexed ABN enc
490 *
491 * If at any point external movement is detected abort
492 */
493 // Wait for Power
494 while(!hasPower()){
495 Delay(100);
496 }
497 curFilters.flux.params.enable = false;
499 // Calibrate ADC
500 enablePin.set();
501 setPwm(TMC_PwmMode::PWM_FOC); // enable foc to calibrate adc
502 Delay(50);
503 if(calibrateAdcOffset(500)){
505 }else{
506 calibFailCb();
507 break;
508 }
509
510 // Encoder
512 setEncoderType(conf.motconf.enctype);
513 recalibrationRequired = false;
514 curFilters.flux.params.enable = true;
516 break;
517 }
519 {
520 allowStateChange = false;
521 // Wait for Power
522 while(!hasPower()){
523 Delay(100);
524 }
525 pidAutoTune();
526 allowStateChange = true;
527 changeState(laststate,false);
528 break;
529 }
530
532 autohome();
534
535 break;
536
538 {
539 // Check status, Temps, Everything alright?
540 uint32_t tick = HAL_GetTick();
541 if(tick - lastStatTime > 2000){ // Every 2s
542 lastStatTime = tick;
543 statusCheck();
544 // Get enable input. If tmc does not reply the result will read 0 or 0xffffffff (not possible normally)
545 uint32_t pins = readReg(0x76);
546 bool tmc_en = ((pins >> 15) & 0x01) && pins != 0xffffffff;
547 if(!tmc_en && motorEnabledRequested){ // Hardware emergency.
548 this->estopTriggered = true;
549 this->emergencyStop(false);
551 //changeState(TMC_ControlState::HardError);
552 }
553
554 // Temperature sense
555 if(conf.hwconf.thermistorSettings.temperatureEnabled){
556 float temp = getTemp();
557 if(temp > conf.hwconf.thermistorSettings.temp_limit){
559 pulseErrLed();
560 }
561 }
562
563 }
564 Delay(200);
565 }
566 break;
567
569 Delay(100);
570 if(estopTriggered){
571 uint32_t pins = readReg(0x76);
572 bool tmc_en = ((pins >> 15) & 0x01) && pins != 0xffffffff;
573 if(tmc_en){
574 // Emergency stop reset
576 this->estopTriggered = false; // TODO resume correctly
578 }
579 }
580 break;
581
583 if(powerInitialized && hasPower() && conf.motconf.motor_type != MotorType::NONE)
584 encoderInit();
585 break;
586
588 if(powerInitialized && hasPower() && drvEncoder != nullptr && conf.motconf.motor_type != MotorType::NONE)
589 encoderInit();
590 break;
591
593
594 break; // Broken
595
597 this->stopMotor();
599 break;
600
601 case TMC_ControlState::EncoderFinished: // Startup sequence done
602 //setEncoderIndexFlagEnabled(false); // TODO
603// curFilters.flux.params.enable = true;
604// setBiquadFlux(curFilters.flux); // Enable flux filter
605 encoderAligned = true;
607 startMotor();
609 }else{
610 stopMotor();
611 laststate = TMC_ControlState::Running; // Go to running when starting again
612 }
613
616 Flash_Write(flashAddrs.encA,encodeEncHallMisc()); // Save encoder settings
617 }
618
619
620 break;
621
622 default:
623
624 break;
625 }
626
627
628 // Optional update methods for safety
629
630 if(!hasPower() && state != TMC_ControlState::waitPower && initialized && powerInitialized){ // low voltage or overvoltage
631
634 setMotionMode(MotionMode::stop,true); // Disable tmc
636 allowStateChange = false;
637 }
638
639 if(flagCheckInProgress){ // cause some delay until reenabling the status interrupt checking
641 flagCheckInProgress = false;
642 }
643 Delay(10);
644
645 if(emergency && !motorReady()){
646 this->Suspend(); // we can not safely run. wait until resumed by estop
647 }
648 } // End while
649}
650
652 if(conf.motconf.enctype == EncoderType_TMC::abn) {
654 // Report changes
656 }else if(conf.motconf.enctype == EncoderType_TMC::sincos || conf.motconf.enctype == EncoderType_TMC::uvw){
657 if(!conf.hwconf.flags.analog_enc_skip_cal){
659 }
660 }else if(conf.motconf.enctype == EncoderType_TMC::ext){
662 }
664
665
666}
667
678 curFilters.flux.params.enable = false;
680 PhiE lastphie = getPhiEtype();
681 MotionMode lastmode = getMotionMode();
683 setPhiEtype(PhiE::ext); // Fixed phase
685 setFluxTorque(0, 0);
686 TMC4671PIDConf newpids = curPids;
687 int16_t targetflux = std::min<int16_t>(this->curLimits.pid_torque_flux,bangInitPower); // Respect limits
688 int16_t targetflux_p = targetflux * 0.75;
689
690 uint16_t fluxI = 0,fluxP = 100; // Startvalues
691 writeReg(0x54, fluxI | (fluxP << 16));
692 int32_t flux = 0;
693 setFluxTorque(targetflux, 0); // Start flux step
694 while(fluxP < 20000){
695 writeReg(0x54, fluxI | (fluxP << 16)); // Update P
696 Delay(50); // Wait a bit. not critical
697 flux = getActualFlux();
698 if(flux > targetflux_p){
699 break;
700 }else if(flux > targetflux * 0.5){
701 // Reduce steps when we are close
702 fluxP+=10;
703 }else{
704 fluxP+=100;
705 }
706 }
707 setFluxTorque(0, 0);
708 Delay(100); // Let the current settle down
709
710 // Tune I. This is more difficult because we need to take overshoot into account
711 uint32_t measuretime = 50; // ms to wait per measurement
712 uint16_t step_i = 64;
713 fluxI = 100;
714 flux = 0;
715 while(fluxI < 20000){
716 writeReg(0x54, fluxI | (fluxP << 16));
717 uint32_t tick = HAL_GetTick();//micros();
718 int32_t peakflux = 0;
719 setFluxTorque(targetflux, 0);
720
721 while(HAL_GetTick() - tick < measuretime){ // Measure current for this pulse
722 flux = getActualFlux();
723 peakflux = std::max<int32_t>(peakflux, flux);
724 }
725 setFluxTorque(0, 0);
726 uint8_t timeout = 100; // Let the current settle down
727 while(timeout-- && flux > 10){
728 Delay(1);
729 flux = getActualFlux();
730 }
731
732 if(peakflux > (targetflux + ( targetflux * TMC4671_ITUNE_CUTOFF))) // Overshoot target by 4% default
733 {
734 fluxI -= step_i; // Revert last step
735 break;
736 }
737 if(peakflux < targetflux*0.95){ // Do larger steps if we don't even reach near the target within the time.
738 step_i = 100;
739 }else{
740 step_i = 10;
741 }
742 fluxI += step_i;
743
744 }
745 curFilters.flux.params.enable = true;
747
748 if(fluxP && fluxP < 20000 && fluxI && fluxI < 20000){
749 newpids.fluxP = fluxP;
750 newpids.torqueP = fluxP;
751 newpids.fluxI = fluxI;
752 newpids.torqueI = fluxI;
753 }else{
755 setPhiEtype(lastphie);
756 setMotionMode(lastmode,true);
757 return false;
758 }
759
760 setPids(newpids); // Apply new values
762 setPhiEtype(lastphie);
763 setMotionMode(lastmode,true);
764 return true;
765}
766
768 // Moves motor to index
769 if(findEncoderIndex(abnconf.posOffsetFromIndex < 0 ? 10 : -10,bangInitPower/2,false,false)){
770 // Load position offset
771 if(abnconf.useIndex)
772 setTmcPos(getPosAbs() - abnconf.posOffsetFromIndex);
773 return true;
774 }
775 return false;
776}
777
778/*
779 * Returns the current state of the driver controller
780 */
782 return this->state;
783}
784
785inline void TMC4671::changeState(TMC_ControlState newState,bool force){
786 if(newState != this->state){
787 this->laststate = this->state; // save last state if new state wants to jump back
788 }
789 if(!force){
790 this->requestedState = newState;
791 }else{
792 state = newState;
793 }
794
795}
796
797bool TMC4671::reachedPosition(uint16_t tolerance){
798 int32_t actualPos = readReg(0x6B);
799 int32_t targetPos = readReg(0x68);
800 if( abs(targetPos - actualPos) < tolerance){
801 return true;
802 }else{
803 return false;
804 }
805}
806
807void TMC4671::zeroAbnUsingPhiM(bool offsetPhiE){
808 int32_t npos = (int32_t)readReg(0x28); // raw encoder counts at index hit
809 int32_t npos_M = (npos * 0xffff) / abnconf.cpr; // Scaled encoder angle at index
810 abnconf.phiMoffset = -npos_M;
811 if(offsetPhiE){
812 abnconf.phiEoffset += npos_M*conf.motconf.pole_pairs;
813 // change index to zero phiM
814 uint32_t phiEphiM = readReg(0x29);
815 int16_t phiE = ((phiEphiM >> 16) & 0xffff); // Write back phiE offset
816 int16_t phiM = phiEphiM & 0xffff;
817 //updateReg(0x29, abnconf.phiMoffset, 0xffff, 0);
818 writeReg(0x29,(phiE << 16) | phiM);
819 }else{
820 updateReg(0x29, abnconf.phiMoffset, 0xffff, 0);
821 }
822 setTmcPos(getPosAbs()); // Set position to absolute position = ~zero
823}
824
828bool TMC4671::findEncoderIndex(int32_t speed, uint16_t power,bool offsetPhiM,bool zeroCount){
829
830 if(conf.motconf.enctype != EncoderType_TMC::abn){
831 return false; // Only valid for ABN encoders
832 }
833
834 PhiE lastphie = getPhiEtype();
835 MotionMode lastmode = getMotionMode();
836 curFilters.flux.params.enable = false;
838 setFluxTorque(0, 0);
839// setPhiE_ext(getPhiE());
840// setPhiEtype(PhiE::openloop);
841
842// abnconf.clear_on_N = true;
843// setup_ABN_Enc(abnconf);
844
845 // Arm encoder signal
846 setEncoderIndexFlagEnabled(true,zeroCount);
847 // Rotate
848
849 //uint32_t mposStart = readReg(0x2A);
850 int32_t timeout = 1000; // 10s
851 rampFlux(power, 500);
852 runOpenLoop(power, 0, speed, 10, true);
853 while(!encoderIndexHitFlag && timeout-- > 0){
854 Delay(10);
855 }
856 //int32_t speed = 10;
857 rampFlux(0, 100);
858 runOpenLoop(0, 0, 0, 10, true);
860 pulseErrLed();
862 }
863
864 // If zero count on index write a phiM offset so that phiM is 0 on index and we don't need to change the raw encoder count (possible timing danger)
865 if(offsetPhiM){
866 zeroAbnUsingPhiM(false);
867 }
868
869// abnconf.clear_on_N = false;
870// setup_ABN_Enc(abnconf);
871 curFilters.flux.params.enable = true;
873
874 setMotionMode(lastmode,true);
875 setPhiEtype(lastphie);
876 return encoderIndexHitFlag;
877}
878
882void TMC4671::setEncoderIndexFlagEnabled(bool enabled,bool zeroEncoder){
883 //zeroEncoderOnIndexHit = zeroEncoder;
884
885 updateReg(0x25, zeroEncoder ? 1 : 0, 0x1, 9); // Enable encoder clearing
886 if(zeroEncoder){
887 writeReg(0x28,0); // Preload 0 into n register
888 }
889
890 if(enabled)
891 encoderIndexHitFlag = false;
892 setStatusFlags(0); // Reset flags
893 this->statusMask.flags.AENC_N = this->conf.motconf.enctype == EncoderType_TMC::sincos && enabled;
894 this->statusMask.flags.ENC_N = this->conf.motconf.enctype == EncoderType_TMC::abn && enabled;
895 setStatusMask(statusMask); // Enable flag output for encoder
896}
897
904 setPhiEtype(this->conf.motconf.phiEsource);
905 }
906 writeReg(0x68,pos);
907}
909
910 return readReg(0x68);
911}
912
913
920 setPhiEtype(this->conf.motconf.phiEsource);
921 }
922 writeReg(0x66,vel);
923}
925 return readReg(0x66);
926}
928 return readReg(0x6A);
929}
930
932 writeReg(0x1E, pos);
933}
934
935void TMC4671::setPhiE_ext(int16_t phiE){
936 writeReg(0x1C, phiE);
937}
938
940 int64_t phiE_t = (int64_t)drvEncoder->getPosAbs() * 0xffff;
941 if(this->conf.encoderReversed){
942 phiE_t = -phiE_t;
943 }
944 int32_t phiE = (phiE_t / (int64_t)drvEncoder->getCpr());
945 phiE = (phiE * conf.motconf.pole_pairs) & 0xffff; // scale to pole pairs
946 //int16_t phiE = (drvEncoder->getPosAbs_f() * (float)0xffff) * conf.motconf.pole_pairs + externalEncoderPhieOffset;
947 return(phiE+externalEncoderPhieOffset);
948}
949
950// PhiE is read only
952 return readReg(0x53);
953}
954
955
956
963 if(!hasPower() || (this->conf.motconf.motor_type != MotorType::STEPPER && this->conf.motconf.motor_type != MotorType::BLDC)){ // If not stepper or bldc return
964 return;
965 }
966 blinkClipLed(50, 0);
967 PhiE lastphie = getPhiEtype();
968 MotionMode lastmode = getMotionMode();
969 setFluxTorque(0, 0);
970
971 uint8_t phiEoffsetReg = 0;
972 if(conf.motconf.enctype == EncoderType_TMC::abn){
973 phiEoffsetReg = 0x29;
976 }else if(conf.motconf.enctype == EncoderType_TMC::sincos || conf.motconf.enctype == EncoderType_TMC::uvw){
977 writeReg(0x41,0); //Zero encoder
978 writeReg(0x47,0); //Zero encoder
979 phiEoffsetReg = 0x45;
980 }else if (usingExternalEncoder()){
982 }else{
983 return; // Not relevant
984 }
985
986 //setTmcPos(0);
987
988 //setMotionMode(MotionMode::uqudext);
989
990 //Delay(100);
991 int16_t phiEpos = getPhiE();// readReg(phiEreg)>>16; // starts at current encoder position
992 updateReg(phiEoffsetReg, 0, 0xffff, 16); // Set phiE offset to zero
993 setPhiE_ext(phiEpos);
995 // Ramp up flux
996 rampFlux(power, 1000);
997 int16_t phiE_enc = getPhiE_Enc();
998
999 Delay(50);
1000 int16_t phiE_abn_old = 0;
1001 int16_t c = 0;
1002 uint16_t still = 0;
1003 while(still < 30 && c++ < 1000){
1004 // Wait for motor to stop moving
1005 if(abs(phiE_enc - phiE_abn_old) < 100){
1006 still++;
1007 }else{
1008 still = 0;
1009 }
1010 phiE_abn_old = phiE_enc;
1011
1012 phiE_enc = getPhiE_Enc();
1013
1014 //phiE_enc=readReg(phiEreg)>>16;
1015 Delay(10);
1016 }
1017 rampFlux(0, 100);
1018
1019 //Write offset
1020 //int16_t phiE_abn = readReg(0x2A)>>16;
1021 int16_t phiEoffset = phiEpos-phiE_enc;
1022
1023 if(phiEoffset == 0){ // 0 invalid
1024 phiEoffset = 1;
1025 }
1026 if (usingExternalEncoder()){
1027 externalEncoderPhieOffset = phiEoffset;
1028 }else{
1029 updateReg(phiEoffsetReg, phiEoffset, 0xffff, 16);
1030 }
1031
1032 if(conf.motconf.enctype == EncoderType_TMC::abn){
1033 abnconf.phiEoffset = phiEoffset;
1034 }else if(conf.motconf.enctype == EncoderType_TMC::sincos || conf.motconf.enctype == EncoderType_TMC::uvw){
1035 aencconf.phiEoffset = phiEoffset;
1036 }
1037
1038
1039 setPhiE_ext(0);
1040 setPhiEtype(lastphie);
1041 setMotionMode(lastmode,true);
1042 //setTmcPos(pos+getPos());
1043 //setTmcPos(0);
1044
1045 blinkClipLed(0, 0);
1046}
1047
1052
1053 // Rotate and measure min/max
1054 blinkClipLed(250, 0);
1055 PhiE lastphie = getPhiEtype();
1056 MotionMode lastmode = getMotionMode();
1057 //int32_t pos = getPos();
1058 PosSelection possel = this->conf.motconf.pos_sel;
1060 setTmcPos(0);
1061 // Ramp up flux
1062 setFluxTorque(0, 0);
1063 writeReg(0x23,0); // set phie openloop 0
1066
1067 if(this->conf.motconf.motor_type == MotorType::STEPPER || this->conf.motconf.motor_type == MotorType::BLDC){
1068 rampFlux(bangInitPower, 250);
1069 }
1070 uint32_t minVal_0 = 0xffff, minVal_1 = 0xffff, minVal_2 = 0xffff;
1071 uint32_t maxVal_0 = 0, maxVal_1 = 0, maxVal_2 = 0;
1072 int32_t minpos = -0x8fff/std::max<int32_t>(1,std::min<int32_t>(this->aencconf.cpr/4,20)), maxpos = 0x8fff/std::max<int32_t>(1,std::min<int32_t>(this->aencconf.cpr/4,20));
1073 uint32_t speed = std::max<uint32_t>(1,20/std::max<uint32_t>(1,this->aencconf.cpr/10));
1074
1075 if(this->conf.motconf.motor_type != MotorType::STEPPER && this->conf.motconf.motor_type != MotorType::BLDC){
1076 speed*=10; // dc motors turn at a random speed. reduce the rotation time a bit by increasing openloop speed
1077 }
1078
1079 runOpenLoop(bangInitPower, 0, speed, 100,true);
1080
1081 uint8_t stage = 0;
1082 int32_t poles = conf.motconf.pole_pairs;
1083 int32_t initialDirPos = 0;
1084 while(stage != 3){
1085 Delay(2);
1086 if(getPos() > maxpos*poles && stage == 0){
1087 runOpenLoop(bangInitPower, 0, -speed, 100,true);
1088 stage = 1;
1089 }else if(getPos() < minpos*poles && stage == 1){
1090 // Scale might still be wrong... maxVal-minVal is too high. In theory its 0xffff range and scaler /256. Leave some room to prevent clipping
1091 aencconf.AENC0_offset = ((maxVal_0 + minVal_0) / 2);
1092 aencconf.AENC0_scale = 0xF6FF00 / (maxVal_0 - minVal_0);
1093 if(conf.motconf.enctype == EncoderType_TMC::uvw){
1094 aencconf.AENC1_offset = ((maxVal_1 + minVal_1) / 2);
1095 aencconf.AENC1_scale = 0xF6FF00 / (maxVal_1 - minVal_1);
1096 }
1097
1098 aencconf.AENC2_offset = ((maxVal_2 + minVal_2) / 2);
1099 aencconf.AENC2_scale = 0xF6FF00 / (maxVal_2 - minVal_2);
1100 aencconf.rdir = false;
1102 rampFlux(0, 100);
1103 runOpenLoop(0, 0, 0, 1000,true);
1104 Delay(250);
1105 // Zero aenc
1106 writeReg(0x41, 0);
1107 initialDirPos = readReg(0x41);
1108 runOpenLoop(bangInitPower, 0, speed, 100,true);
1109 stage = 2;
1110 }else if(getPos() > 0 && stage == 2){
1111 stage = 3;
1112 rampFlux(0, 100);
1113 runOpenLoop(0, 0, 0, 1000,true);
1114 }
1115
1116 writeReg(0x03,2);
1117 uint32_t aencUX = readReg(0x02)>>16;
1118 writeReg(0x03,3);
1119 uint32_t aencWY_VN = readReg(0x02) ;
1120 uint32_t aencWY = aencWY_VN >> 16;
1121 uint32_t aencVN = aencWY_VN & 0xffff;
1122
1123 minVal_0 = std::min(minVal_0,aencUX);
1124 minVal_1 = std::min(minVal_1,aencVN);
1125 minVal_2 = std::min(minVal_2,aencWY);
1126
1127 maxVal_0 = std::max(maxVal_0,aencUX);
1128 maxVal_1 = std::max(maxVal_1,aencVN);
1129 maxVal_2 = std::max(maxVal_2,aencWY);
1130 }
1131 // Scale is not actually important. but offset must be perfect
1132 aencconf.AENC0_offset = ((maxVal_0 + minVal_0) / 2);
1133 aencconf.AENC0_scale = 0xF6FF00 / (maxVal_0 - minVal_0);
1134 if(conf.motconf.enctype == EncoderType_TMC::uvw){
1135 aencconf.AENC1_offset = ((maxVal_1 + minVal_1) / 2);
1136 aencconf.AENC1_scale = 0xF6FF00 / (maxVal_1 - minVal_1);
1137 }
1138 aencconf.AENC2_offset = ((maxVal_2 + minVal_2) / 2);
1139 aencconf.AENC2_scale = 0xF6FF00 / (maxVal_2 - minVal_2);
1140 int32_t newDirPos = readReg(0x41);
1141 aencconf.rdir = (initialDirPos - newDirPos) > 0;
1143 // Restore settings
1144 setPhiEtype(lastphie);
1145 setMotionMode(lastmode,true);
1146 setPosSel(possel);
1147 setTmcPos(0);
1148
1149 blinkClipLed(0, 0);
1150}
1151
1156 if(conf.motconf.enctype == EncoderType_TMC::abn){
1157 return (int16_t)(readReg(0x2A)>>16);
1158 }else if(conf.motconf.enctype == EncoderType_TMC::sincos || conf.motconf.enctype == EncoderType_TMC::uvw){
1159 return (int16_t)(readReg(0x46)>>16);
1160 }else if(conf.motconf.enctype == EncoderType_TMC::hall){
1161 return (int16_t)(readReg(0x39)>>16);
1162 }else if(usingExternalEncoder()){
1164 }else{
1165 return getPhiE();
1166 }
1167}
1168
1173 if((this->conf.motconf.motor_type != MotorType::STEPPER && this->conf.motconf.motor_type != MotorType::BLDC) || (
1174 conf.motconf.enctype != EncoderType_TMC::uvw && conf.motconf.enctype != EncoderType_TMC::sincos && conf.motconf.enctype != EncoderType_TMC::abn && conf.motconf.enctype != EncoderType_TMC::ext))
1175 { // If not stepper or bldc return
1176 return true;
1177 }
1178 blinkClipLed(150, 0);
1179
1180 const uint16_t maxcount = 50; // Allowed reversals
1181 const uint16_t maxfail = 10; // Allowed fails
1182 const int16_t startAngle = getPhiE_Enc(); // Start angle offsets all angles later so there is no jump if angle is already properly aligned
1183 const int16_t targetAngle = 0x3FFF;
1184
1185 bool result = true;
1186 PhiE lastphie = getPhiEtype();
1187 MotionMode lastmode = getMotionMode();
1188 setFluxTorque(0, 0);
1190
1191 setPhiE_ext(startAngle);
1192 // Ramp up flux
1193 rampFlux(2*bangInitPower/3, 250);
1194
1195 //Forward
1196 int16_t phiE_enc = 0;
1197 uint16_t failcount = 0;
1198 int16_t revCount = 0;
1199 for(int16_t angle = 0;angle<targetAngle;angle+=0x00ff){
1200 uint16_t c = 0;
1201 setPhiE_ext(angle+startAngle);
1202 Delay(5);
1203 phiE_enc = getPhiE_Enc() - startAngle;
1204 int16_t err = abs(phiE_enc - angle);
1205 int16_t nErr = abs(phiE_enc + angle);
1206 // Wait more until encoder settles a bit
1207 while(err > 2000 && nErr > 2000 && c++ < 50){
1208 phiE_enc = getPhiE_Enc() - startAngle;
1209 err = abs(phiE_enc - angle);
1210 nErr = abs(angle - phiE_enc);
1211 Delay(10);
1212 }
1213 if(err > nErr){
1214 revCount++;
1215 }
1216 if(c >= maxcount){
1217 failcount++;
1218 if(failcount > maxfail){
1219 result = false;
1220 break;
1221 }
1222 }
1223 }
1224 /* If we are still at the start angle the encoder did not move at all.
1225 * Possible issues:
1226 * Encoder connection wrong
1227 * Wrong encoder selection
1228 * No motor movement
1229 * No encoder power
1230 */
1231 if(startAngle == getPhiE_Enc()){
1234 result = false;
1235 }
1236
1237 // Backward
1238
1239 if(result){ // Only if not already failed
1240 for(int16_t angle = targetAngle;angle>0;angle -= 0x00ff){
1241 uint16_t c = 0;
1242 setPhiE_ext(angle+startAngle);
1243 Delay(5);
1244 phiE_enc = getPhiE_Enc() - startAngle;
1245 int16_t err = abs(phiE_enc - angle);
1246 int16_t nErr = abs(phiE_enc + angle);
1247 // Wait more
1248 while(err > 2500 && nErr > 2500 && c++ < 50){
1249 phiE_enc = getPhiE_Enc() - startAngle;
1250 err = abs(phiE_enc - angle);
1251 nErr = abs(angle - phiE_enc);
1252 Delay(10);
1253 }
1254 if(err > nErr){
1255 revCount++;
1256 }
1257 if(c >= maxcount){
1258 failcount++;
1259 if(failcount > maxfail){
1260 result = false;
1261 break;
1262 }
1263 }
1264 }
1265 }
1266
1267 // TODO check if we want that
1268 if(revCount > maxcount){ // Encoder seems reversed
1269 // reverse encoder
1270 if(this->conf.motconf.enctype == EncoderType_TMC::abn){
1271 this->abnconf.rdir = !this->abnconf.rdir;
1273 }else if(this->conf.motconf.enctype == EncoderType_TMC::sincos || this->conf.motconf.enctype == EncoderType_TMC::uvw){
1274 this->aencconf.rdir = !this->aencconf.rdir;
1276 }else if(this->conf.motconf.enctype == EncoderType_TMC::ext){
1277 this->conf.encoderReversed = !this->conf.encoderReversed;
1278 }
1279 ErrorHandler::addError(Error(ErrorCode::encoderReversed,ErrorType::warning,"Encoder direction reversed during check"));
1280 }
1281
1282 rampFlux(0, 100);
1283 setPhiE_ext(0);
1284 setPhiEtype(lastphie);
1285 setMotionMode(lastmode,true);
1286
1287 if(result){
1288 encoderAligned = true;
1289 }
1290 blinkClipLed(0, 0);
1291 return result;
1292}
1293
1295 this->abnconf = encconf;
1296 this->conf.encoderReversed = encconf.rdir;
1297 uint32_t abnmode =
1298 (encconf.apol |
1299 (encconf.bpol << 1) |
1300 (encconf.npol << 2) |
1301 (encconf.ab_as_n << 3) |
1302 (encconf.latch_on_N << 8) |
1303 (encconf.rdir << 12));
1304
1305 writeReg(0x25, abnmode);
1306 //int32_t pos = getPos();
1307 writeReg(0x26, encconf.cpr);
1308 writeReg(0x29, ((uint16_t)encconf.phiEoffset << 16) | (uint16_t)encconf.phiMoffset);
1309 //setTmcPos(pos);
1310 //writeReg(0x27,0); //Zero encoder
1311 //conf.motconf.phiEsource = PhiE::abn;
1312 if(encconf.useIndex){
1313 encoderIndexHitFlag = false; // Reset flag
1314 }
1315
1316
1317}
1319 this->conf.encoderReversed = encconf.rdir;
1320 // offsets
1321 writeReg(0x0D,encconf.AENC0_offset | ((uint16_t)encconf.AENC0_scale << 16));
1322 writeReg(0x0E,encconf.AENC1_offset | ((uint16_t)encconf.AENC1_scale << 16));
1323 writeReg(0x0F,encconf.AENC2_offset | ((uint16_t)encconf.AENC2_scale << 16));
1324
1325 writeReg(0x40,encconf.cpr);
1326 writeReg(0x3e,(uint16_t)encconf.phiAoffset);
1327 writeReg(0x45,(uint16_t)encconf.phiEoffset | ((uint16_t)encconf.phiMoffset << 16));
1328 writeReg(0x3c,(uint16_t)encconf.nThreshold | ((uint16_t)encconf.nMask << 16));
1329
1330 uint32_t mode = encconf.uvwmode & 0x1;
1331 mode |= (encconf.rdir & 0x1) << 12;
1332 writeReg(0x3b, mode);
1333
1334}
1336 this->hallconf = hallconf;
1337
1338 uint32_t hallmode =
1339 hallconf.polarity |
1340 hallconf.filter << 4 |
1341 hallconf.interpolation << 8 |
1342 hallconf.direction << 12 |
1343 (hallconf.blank & 0xfff) << 16;
1344 writeReg(0x33, hallmode);
1345 // Positions
1346 uint32_t posA = (uint16_t)hallconf.pos0 | (uint16_t)hallconf.pos60 << 16;
1347 writeReg(0x34, posA);
1348 uint32_t posB = (uint16_t)hallconf.pos120 | (uint16_t)hallconf.pos180 << 16;
1349 writeReg(0x35, posB);
1350 uint32_t posC = (uint16_t)hallconf.pos240 | (uint16_t)hallconf.pos300 << 16;
1351 writeReg(0x36, posC);
1352
1353 uint32_t phiOffsets = (uint16_t)hallconf.phiMoffset | (uint16_t)hallconf.phiEoffset << 16;
1354 writeReg(0x37, phiOffsets);
1355 writeReg(0x38, hallconf.dPhiMax);
1356
1357 //conf.motconf.phiEsource = PhiE::hall;
1358}
1359
1360
1365
1366 uint16_t measuretime_idle = time;
1367 uint32_t measurements_idle = 0;
1368 uint64_t totalA=0;
1369 uint64_t totalB=0;
1370 bool allowTemp = conf.hwconf.thermistorSettings.temperatureEnabled;
1371 conf.hwconf.thermistorSettings.temperatureEnabled = false; // Temp check interrupts adc
1372 writeReg(0x03, 0); // Read raw adc
1373 PhiE lastphie = getPhiEtype();
1374 MotionMode lastmode = getMotionMode();
1376 Delay(100); // Wait a bit before sampling
1377 uint16_t lastrawA=conf.adc_I0_offset, lastrawB=conf.adc_I1_offset;
1378
1379 //pulseClipLed(); // Turn on led
1380 // Disable drivers and measure many samples of zero current
1381 //enablePin.reset();
1382 uint32_t tick = HAL_GetTick();
1383 while(HAL_GetTick() - tick < measuretime_idle){ // Measure idle
1384 writeReg(0x03, 0); // Read raw adc
1385 uint32_t adcraw = readReg(0x02);
1386 uint16_t rawA = adcraw & 0xffff;
1387 uint16_t rawB = (adcraw >> 16) & 0xffff;
1388 // Signflip filter for SPI bug
1389 if(abs(lastrawA-rawA) < 10000 && abs(lastrawB-rawB) < 10000){
1390 totalA += rawA;
1391 totalB += rawB;
1392 measurements_idle++;
1393 lastrawA = rawA;
1394 lastrawB = rawB;
1395 }
1396// uint32_t lastMicros = micros();
1397// while(micros()-lastMicros < 100){} // Wait 100µs at least
1398 }
1399 //enablePin.set();
1400 int32_t offsetAidle = totalA / (measurements_idle);
1401 int32_t offsetBidle = totalB / (measurements_idle);
1402
1403 // Check if offsets are in a valid range
1404 if(totalA < 100 || totalB < 100 || ((abs(offsetAidle - 0x7fff) > TMC_ADCOFFSETFAIL) || (abs(offsetBidle - 0x7fff) > TMC_ADCOFFSETFAIL)) ){
1406// blinkErrLed(100, 0); // Blink forever
1407// setPwm(TMC_PwmMode::off); //Disable pwm
1408// this->changeState(TMC_ControlState::HardError);
1409 adcCalibrated = false;
1410 conf.hwconf.thermistorSettings.temperatureEnabled = allowTemp;
1411 return false; // An adc or shunt amp is likely broken. do not proceed.
1412 }
1413 conf.adc_I0_offset = offsetAidle;
1414 conf.adc_I1_offset = offsetBidle;
1415 setAdcOffset(conf.adc_I0_offset, conf.adc_I1_offset);
1416 // ADC Offsets should now be close to perfect
1417
1418 setPhiEtype(lastphie);
1419 setMotionMode(lastmode,true);
1420 adcCalibrated = true;
1421 conf.hwconf.thermistorSettings.temperatureEnabled = allowTemp;
1422 return true;
1423}
1424
1435
1436 if(!powerInitialized || !hasPower()){
1439 return;
1440 }
1441
1442 // Initializes encoder
1443 if(conf.motconf.enctype == EncoderType_TMC::abn){
1444 setPosSel(PosSelection::PhiM_abn); // Mechanical Angle
1445 setVelSel(VelSelection::PhiM_abn); // Mechanical Angle (RPM)
1446 //setup_ABN_Enc(abnconf);
1447 if(!encHallRestored){
1448 estimateABNparams(); // If not saved try to estimate parameters
1449 recalibrationRequired = true;
1450 }
1451 }else if(conf.motconf.enctype == EncoderType_TMC::sincos || conf.motconf.enctype == EncoderType_TMC::uvw){
1452 setPosSel(PosSelection::PhiM_aenc); // Mechanical Angle
1453 setVelSel(VelSelection::PhiM_aenc); // Mechanical Angle (RPM)
1454 //setup_AENC(aencconf);
1455 if(!conf.hwconf.flags.analog_enc_skip_cal){
1456 calibrateAenc();
1457 }
1458 }
1459
1460 // find index
1461
1462 if(conf.motconf.enctype == EncoderType_TMC::abn && abnconf.useIndex && !encoderIndexHitFlag){ // TODO changing direction might invalidate phiE offset because of index pulse width
1463 findEncoderIndex(abnconf.posOffsetFromIndex < 0 ? 10 : -10,bangInitPower/2,true,true); // Go to index and zero encoder
1464 setPhiEtype(PhiE::openloop); // Openloop used in last step. Use for aligning too
1465 }else{
1468 }
1469
1470 // Align encoder
1471 // TODO handle absolute external encoders
1473
1474 // Check encoder
1475 if(!checkEncoder()){
1476 if(++enc_retry > enc_retry_max){
1477 encoderAligned = false;
1480 stopMotor();
1481 allowStateChange = false;
1483 }
1484
1485 if(manualEncAlign){
1486 manualEncAlign = false;
1488 }
1489 return;
1490 }
1491 encoderAligned = true;
1492
1493
1494
1495 if(conf.motconf.enctype == EncoderType_TMC::abn && abnconf.useIndex && encoderIndexHitFlag)
1496 setTmcPos(getPosAbs() - abnconf.posOffsetFromIndex); // Load stored position
1497
1498 if(manualEncAlign){
1499 manualEncAlign = false;
1501 }
1503
1504 if(conf.motconf.enctype == EncoderType_TMC::abn){
1506 }else if(conf.motconf.enctype == EncoderType_TMC::sincos || conf.motconf.enctype == EncoderType_TMC::uvw){
1508 }else if(usingExternalEncoder()){
1509// setPosSel(PosSelection::PhiE_ext);
1510// setVelSel(VelSelection::PhiE_ext); // Mechanical Angle (RPM)
1512 }
1513
1514}
1515
1521 // If no external timer is set external encoder is not valid
1522 if( !conf.hwconf.isEncSupported(type) || ((!externalEncoderTimer || !externalEncoderAllowed()) && type == EncoderType_TMC::ext)){
1523 type = EncoderType_TMC::NONE;
1524 }
1525
1526 this->conf.motconf.enctype = type;
1527 this->statusMask.flags.AENC_N = 0;
1528 this->statusMask.flags.ENC_N = 0;
1529 //encoderIndexHitFlag = false;
1531 encoderAligned = false;
1532
1533 abnconf.rdir = this->conf.encoderReversed;
1534 aencconf.rdir = this->conf.encoderReversed;
1535
1536 if(type == EncoderType_TMC::abn){
1537 encoderAligned = false;
1538 // Not initialized if cpr not set
1539 if(this->abnconf.cpr == 0){
1540 return;
1541 }
1543
1545
1546 // SinCos encoder
1547 }else if(type == EncoderType_TMC::sincos){
1548 encoderAligned = false;
1550 this->aencconf.uvwmode = false; // sincos mode
1552
1553 // Analog UVW encoder
1554 }else if(type == EncoderType_TMC::uvw){
1555 encoderAligned = false;
1557 this->aencconf.uvwmode = true; // uvw mode
1559
1560 }else if(type == EncoderType_TMC::hall){ // Hall sensor. Just trust it
1564 encoderAligned = true;
1567
1568 }else if(type == EncoderType_TMC::ext && drvEncoder && drvEncoder->getEncoderType() != EncoderType::NONE){
1569 // TODO check different encoder type
1570 encoderAligned = false;
1572 //changeState(TMC_ControlState::Shutdown);
1574 }else{
1576 encoderAligned = true;
1577 }
1578
1579}
1580
1582 EncoderType_TMC type = conf.motconf.enctype;
1583 if(type == EncoderType_TMC::abn || type == EncoderType_TMC::NONE){
1584 return abnconf.cpr;
1585 }else if(type == EncoderType_TMC::sincos || type == EncoderType_TMC::uvw){
1586 return aencconf.cpr;
1587 }
1588 else{
1589 return getCpr();
1590 }
1591}
1592
1594 conf.motconf.phiEsource = type;
1595
1596 // External encoder is phiE ext but enables constant phiE updates too
1597 if(type == PhiE::extEncoder){
1598 type = PhiE::ext;
1599 }
1600
1601 writeReg(0x52, (uint8_t)type & 0xff);
1602}
1604 PhiE phie = PhiE(readReg(0x52) & 0x7);
1605 if(phie == PhiE::ext && conf.motconf.phiEsource == PhiE::extEncoder){
1606 return PhiE::extEncoder;
1607 }
1608 return phie;
1609}
1610
1611void TMC4671::setMotionMode(MotionMode mode, bool force){
1612 if(!force){
1613 nextMotionMode = mode;
1614 return;
1615 }
1616 if(mode != curMotionMode){
1618 }
1619 curMotionMode = mode;
1620 updateReg(0x63, (uint8_t)mode, 0xff, 0);
1621}
1626
1627void TMC4671::setOpenLoopSpeedAccel(int32_t speed,uint32_t accel){
1628 writeReg(0x21, speed);
1629 writeReg(0x20, accel);
1630}
1631
1632
1633void TMC4671::runOpenLoop(uint16_t ud,uint16_t uq,int32_t speed,int32_t accel,bool torqueMode){
1634 if(this->conf.motconf.motor_type == MotorType::DC){
1635 uq = ud+uq; // dc motor has no flux. add to torque
1636 }
1637 startMotor();
1638 if(torqueMode){
1639 if(this->conf.motconf.motor_type == MotorType::DC){
1640 uq = ud+uq; // dc motor has no flux. add to torque
1641 }
1642 setFluxTorque(ud, uq);
1643 }else{
1645 setUdUq(ud,uq);
1646 }
1647 int16_t oldPhiE = getPhiE();
1649 writeReg(0x23,oldPhiE); // Start running at last phiE value
1650
1651 setOpenLoopSpeedAccel(speed, accel);
1652}
1653
1654void TMC4671::setUdUq(int16_t ud,int16_t uq){
1655 writeReg(0x24, ud | (uq << 16));
1656}
1657
1659 // Stop driver if running
1660
1661// enablePin.reset();
1662 motorEnabledRequested = false;
1665 setPwm(TMC_PwmMode::off); // disable foc
1667 }
1668}
1670 motorEnabledRequested = true;
1671
1674 }
1675 // Start driver if powered and emergency flag reset
1676 if(hasPower() && !emergency){
1677 setPwm(TMC_PwmMode::PWM_FOC); // enable foc
1678 enablePin.set();
1680
1681 }
1682 else{
1684 }
1685
1686}
1687
1688void TMC4671::emergencyStop(bool reset){
1689 if(!reset){
1690// setPwm(TMC_PwmMode::HSlow_LShigh); // Short low side for instant stop
1691 emergency = true;
1692 enablePin.reset(); // Release enable pin to disable the whole driver
1693 motorEnabledRequested = false;
1694 this->stopMotor();
1695
1696 }else{
1697// enablePin.set();
1698// writeReg(0x64, 0); // Set flux and torque 0 directly. Make sure motor does not jump
1699// setPwm(TMC_PwmMode::PWM_FOC);
1700 emergency = false;
1701 motorEnabledRequested = true;
1702 //this->changeState(TMC_ControlState::waitPower, true); // Reinit
1703 this->startMotor();
1704 if(!motorReady()){
1705 if(inIsr()){
1706 ResumeFromISR();
1707 }else{
1708 Resume();
1709 }
1710 }
1711 }
1712}
1713
1719
1720 int32_t vDiff = getIntV() - getExtV();
1721 if(vDiff > fluxDissipationLimit){
1722 // Reaches limit at +5v if scaler is 1
1723 return(clip<int32_t,int32_t>(vDiff * conf.hwconf.fluxDissipationScaler * curLimits.pid_torque_flux * 0.0002,0,curLimits.pid_torque_flux));
1724 }
1725 return 0;
1726}
1727
1732void TMC4671::turn(int16_t power){
1733 if(!(this->motorReady() && motorEnabledRequested))
1734 return;
1735 int32_t flux = 0;
1736
1737 // Flux offset for field weakening
1738
1740 if((this->conf.encoderReversed && conf.motconf.enctype == EncoderType_TMC::ext) || conf.invertForce){
1741 power = -power; // Encoder does not match
1742 }
1743
1744 /*
1745 * If flux dissipation is on prefer this over the resistor.
1746 * Warning: The axis only calls this function when active and if torque changed.
1747 * It may not update during sustained force and still cause overvoltage conditions.
1748 * TODO periodically check and update if driver is on but no torque update is sent
1749 */
1750 if(conf.hwconf.fluxDissipationScaler && conf.enableFluxDissipation){
1751 int16_t dissipationFlux = controlFluxDissipate();
1752 if(dissipationFlux != 0){
1753 flux = dissipationFlux;
1754 }
1755 }
1756
1757 setFluxTorque(flux, power);
1758}
1759
1764 writeReg(0x51, (uint8_t)psel);
1765 this->conf.motconf.pos_sel = psel;
1766}
1767
1772void TMC4671::setVelSel(VelSelection vsel,uint8_t mode){
1773 uint32_t vselMode = ((uint8_t)vsel & 0xff) | ((mode & 0xff) << 8);
1774 writeReg(0x50, vselMode);
1775 this->conf.motconf.vel_sel = vsel;
1776}
1777
1783 uint8_t modeReg = 0;
1784 switch(mode){
1785 default:
1787 modeReg = 0; break;
1789 modeReg = 0b1100111; break;
1791 modeReg = 0b0000111; break;
1793 modeReg = 0b0000001; break;
1795 modeReg = 0b0010001; break;
1797 modeReg = 0b0001001; break;
1799 modeReg = 0b0011001; break;
1800 }
1801
1802 updateReg(0x7B, modeReg,0xff,0);
1803}
1804
1809 return readReg(0x7B) >> 24;
1810}
1811
1816void TMC4671::setGpioPins(uint8_t pins){
1817 uint32_t reg = pins << 16;
1818 updateReg(0x7B, reg,0xff,16);
1819}
1820
1821
1825std::pair<uint32_t,std::string> TMC4671::getTmcType(){
1826
1827 std::string reply = "";
1828 writeReg(1, 0);
1829 uint32_t nameInt = readReg(0);
1830 if(nameInt == 0 || nameInt == 0xffffffff){
1831 reply = "No driver connected";
1832 return std::pair<uint32_t,std::string>(0,reply);
1833 }
1834
1835 nameInt = __REV(nameInt);
1836 char* name = reinterpret_cast<char*>(&nameInt);
1837 std::string namestring = std::string(name,sizeof(nameInt));
1838
1839 writeReg(1, 1);
1840 uint32_t versionInt = readReg(0);
1841
1842 std::string versionstring = std::to_string((versionInt >> 16) && 0xffff) + "." + std::to_string((versionInt) && 0xffff);
1843
1844 reply += "TMC" + namestring + " v" + versionstring;
1845 return std::pair<uint32_t,std::string>(versionInt,reply);
1846}
1847
1849 if((conf.motconf.enctype == EncoderType_TMC::ext && externalEncoderTimer) || conf.combineEncoder){
1850 return MotorDriver::drvEncoder.get();
1851 }else{
1852 return static_cast<Encoder*>(this);
1853 }
1854}
1855
1856void TMC4671::setEncoder(std::shared_ptr<Encoder>& encoder){
1857 MotorDriver::drvEncoder = encoder;
1858 if(conf.motconf.enctype == EncoderType_TMC::ext && externalEncoderTimer){
1859 if(!extEncUpdater){ // If updater has not been set up because the encoder mode was changed before the external encoder passed force it now
1861 }
1863 }
1864}
1865
1867 // Use internal encoder if not external encoder is selected
1868 return conf.motconf.enctype != EncoderType_TMC::ext && !this->conf.combineEncoder;
1869}
1870
1874void TMC4671::setPos(int32_t pos){
1875 if(this->conf.motconf.enctype == EncoderType_TMC::abn && abnconf.useIndex){
1876
1877 int32_t tmcpos = readReg(0x6B); // Current Position
1878 int32_t offset = (tmcpos - pos) % 0xffff; // Difference between current position and target
1879
1880// setup_ABN_Enc(abnconf);
1881 abnconf.posOffsetFromIndex += offset;
1882 setTmcPos(getPosAbs() - abnconf.posOffsetFromIndex);
1883 }else{
1884 setTmcPos(pos);
1885 }
1886
1887}
1888
1893
1894 writeReg(0x6B, pos);
1895}
1896
1898
1899 int32_t pos = (int32_t)readReg(0x6B);
1900 return pos;
1901}
1902
1904 int16_t pos;
1905 if(this->conf.motconf.enctype == EncoderType_TMC::abn){
1906 pos = (int16_t)readReg(0x2A) & 0xffff; // read phiM
1907 }else if(this->conf.motconf.enctype == EncoderType_TMC::hall){
1908 pos = (int16_t)readReg(0x3A); // read phiM
1909 }else if(this->conf.motconf.enctype == EncoderType_TMC::sincos || this->conf.motconf.enctype == EncoderType_TMC::uvw){
1910 pos = (int16_t)readReg(0x46) & 0xffff; // read phiM
1911 }else{
1912 pos = getPos(); // read phiM
1913 }
1914
1915 return pos;
1916}
1917
1918
1920// if(this->conf.motconf.phiEsource == PhiE::abn){
1921// return abnconf.cpr;
1922// }else{
1924 return drvEncoder->getCpr();
1925 }
1926 return 0xffff;
1927// }
1928
1929}
1930void TMC4671::setCpr(uint32_t cpr){
1931 if(cpr == 0)
1932 cpr = 1;
1933
1934
1935 this->abnconf.cpr = cpr;
1936 this->aencconf.cpr = cpr;
1937 writeReg(0x26, abnconf.cpr); //ABN
1938 writeReg(0x40, aencconf.cpr); //AENC
1939
1940}
1941
1945uint32_t TMC4671::encToPos(uint32_t enc){
1946 return enc*(0xffff / abnconf.cpr); //*(conf.motconf.pole_pairs)
1947}
1948uint32_t TMC4671::posToEnc(uint32_t pos){
1949 return pos/((0xffff / abnconf.cpr)) % abnconf.cpr; //(conf.motconf.pole_pairs)
1950}
1951
1958
1959
1960
1961void TMC4671::setAdcOffset(uint32_t adc_I0_offset,uint32_t adc_I1_offset){
1962 conf.adc_I0_offset = adc_I0_offset;
1963 conf.adc_I1_offset = adc_I1_offset;
1964
1965 updateReg(0x09, adc_I0_offset, 0xffff, 0);
1966 updateReg(0x08, adc_I1_offset, 0xffff, 0);
1967}
1968
1969void TMC4671::setAdcScale(uint32_t adc_I0_scale,uint32_t adc_I1_scale){
1970 conf.adc_I0_scale = adc_I0_scale;
1971 conf.adc_I1_scale = adc_I1_scale;
1972
1973 updateReg(0x09, adc_I0_scale, 0xffff, 16);
1974 updateReg(0x08, adc_I1_scale, 0xffff, 16);
1975}
1976
1977void TMC4671::setupFeedForwardTorque(int32_t gain, int32_t constant){
1978 writeReg(0x4E, 42);
1979 writeReg(0x4D, gain);
1980 writeReg(0x4E, 43);
1981 writeReg(0x4D, constant);
1982}
1983void TMC4671::setupFeedForwardVelocity(int32_t gain, int32_t constant){
1984 writeReg(0x4E, 40);
1985 writeReg(0x4D, gain);
1986 writeReg(0x4E, 41);
1987 writeReg(0x4D, constant);
1988}
1989
1991 updateReg(0x63, (uint8_t)mode, 0xff, 16);
1992 if(mode!=FFMode::none){
1993
1994 setSequentialPI(true);
1995 }
1996}
1997
1998void TMC4671::setSequentialPI(bool sequential){
1999 curPids.sequentialPI = sequential;
2000 updateReg(0x63, sequential ? 1 : 0, 0x1, 31);
2001}
2002
2004#ifndef TIM_TMC
2005 allowExternalEncoder = false;
2006#else
2007 bool lastAllowed = allowExternalEncoder;
2008 allowExternalEncoder = allow;
2009 // External encoder was previously used but now not allowed anymore. Change to none type encoder
2010 if(!allow && lastAllowed && conf.motconf.enctype == EncoderType_TMC::ext){
2011 setEncoderType(EncoderType_TMC::NONE); // Reinit encoder
2012 }
2013#endif
2014}
2015
2017#ifndef TIM_TMC
2018 return false;
2019#else
2020 return allowExternalEncoder && conf.hwconf.flags.enc_ext;
2021#endif
2022}
2023
2025
2026 if(!conf.hwconf.isMotSupported(motor)){
2027 motor = MotorType::NONE;
2028 }
2029 if(motor == MotorType::DC){
2030 poles = 1;
2031 }
2032
2033 conf.motconf.motor_type = motor;
2034 conf.motconf.pole_pairs = poles;
2035 uint32_t mtype = poles | ( ((uint8_t)motor&0xff) << 16);
2036// if(motor != MotorType::STEPPER){
2037// maxOffsetFlux = 0; // Offsetflux only helpful for steppers. Has no effect otherwise
2038// }
2039 writeReg(0x1B, mtype);
2040 if(motor == MotorType::BLDC && !ES_TMCdetected){
2041 setSvPwm(conf.motconf.svpwm); // Higher speed for BLDC motors. Not available in engineering samples
2042 }
2043}
2044
2048 }
2049 updateReg(0x64,torque,0xffff,16);
2050}
2052 return readReg(0x64) >> 16;
2053}
2054
2055void TMC4671::setFlux(int16_t flux){
2058 }
2059 updateReg(0x64,flux,0xffff,0);
2060}
2062 return readReg(0x64) && 0xffff;
2063}
2064void TMC4671::setFluxTorque(int16_t flux, int16_t torque){
2067 }
2068#ifdef TMC4671_TORQUE_USE_ASYNC
2069 writeRegAsync(0x64, (flux & 0xffff) | (torque << 16));
2070#else
2071 writeReg(0x64, (flux & 0xffff) | (torque << 16));
2072#endif
2073}
2074
2075void TMC4671::setFluxTorqueFF(int16_t flux, int16_t torque){
2078 }
2079 writeReg(0x65, (flux & 0xffff) | (torque << 16));
2080}
2081
2085void TMC4671::rampFlux(uint16_t target,uint16_t time_ms){
2086 uint16_t startFlux = readReg(0x64) & 0xffff;
2087 int32_t stepsize = (target - startFlux) / std::max<uint16_t>(1, time_ms/2);
2088 if(stepsize == 0){
2089 stepsize = startFlux < target ? 1 : -1;
2090 }
2091 uint16_t flux = startFlux;
2092 while(abs(target - flux) >= abs(stepsize)){
2093 flux+=stepsize;
2094 setFluxTorque(std::max<int32_t>(0,flux), 0);
2095 Delay(2);
2096 }
2097}
2098
2100 curPids = pids;
2101 writeReg(0x54, pids.fluxI | (pids.fluxP << 16));
2102 writeReg(0x56, pids.torqueI | (pids.torqueP << 16));
2103 writeReg(0x58, pids.velocityI | (pids.velocityP << 16));
2104 writeReg(0x5A, pids.positionI | (pids.positionP << 16));
2106}
2107
2109 uint32_t f = readReg(0x54);
2110 uint32_t t = readReg(0x56);
2111 uint32_t v = readReg(0x58);
2112 uint32_t p = readReg(0x5A);
2113 // Update pid storage
2114 curPids = {(uint16_t)(f&0xffff),(uint16_t)(f>>16),(uint16_t)(t&0xffff),(uint16_t)(t>>16),(uint16_t)(v&0xffff),(uint16_t)(v>>16),(uint16_t)(p&0xffff),(uint16_t)(p>>16)};
2115 return curPids;
2116}
2117
2121void TMC4671::setUqUdLimit(uint16_t limit){
2122 this->curLimits.pid_uq_ud = limit;
2123 writeReg(0x5D, limit);
2124}
2125
2126void TMC4671::setTorqueLimit(uint16_t limit){
2127 this->curLimits.pid_torque_flux = limit;
2128 bangInitPower = (float)limit*0.75;
2129 writeReg(0x5E, limit);
2130}
2131
2133
2134 this->pidPrecision = setting;
2135 uint16_t dat = setting.current_I;
2136 dat |= setting.current_P << 1;
2137 dat |= setting.velocity_I << 2;
2138 dat |= setting.velocity_P << 3;
2139 dat |= setting.position_I << 4;
2140 dat |= setting.position_P << 5;
2141 writeReg(0x4E, 62); // set config register address
2142 writeReg(0x4D, dat);
2143}
2144
2146 this->curLimits = limits;
2147 writeReg(0x5C, limits.pid_torque_flux_ddt);
2148 writeReg(0x5D, limits.pid_uq_ud);
2149 writeReg(0x5E, limits.pid_torque_flux);
2150 writeReg(0x5F, limits.pid_acc_lim);
2151 writeReg(0x60, limits.pid_vel_lim);
2152 writeReg(0x61, limits.pid_pos_low);
2153 writeReg(0x62, limits.pid_pos_high);
2154}
2155
2157 curLimits.pid_acc_lim = readReg(0x5F);
2158 curLimits.pid_torque_flux = readReg(0x5E);
2159 curLimits.pid_torque_flux_ddt = readReg(0x5C);
2160 curLimits.pid_uq_ud= readReg(0x5D);
2161 curLimits.pid_vel_lim = readReg(0x60);
2162 curLimits.pid_pos_low = readReg(0x61);
2163 curLimits.pid_pos_high = readReg(0x62);
2164 return curLimits;
2165}
2166
2172 const TMC4671Biquad_t& bq = filter.params;
2173 curFilters.flux = filter;
2174 writeReg(0x4E, 25);
2175 writeReg(0x4D, bq.a1);
2176 writeReg(0x4E, 26);
2177 writeReg(0x4D, bq.a2);
2178 writeReg(0x4E, 28);
2179 writeReg(0x4D, bq.b0);
2180 writeReg(0x4E, 29);
2181 writeReg(0x4D, bq.b1);
2182 writeReg(0x4E, 30);
2183 writeReg(0x4D, bq.b2);
2184 writeReg(0x4E, 31);
2185 writeReg(0x4D, bq.enable & 0x1);
2186}
2187
2193 const TMC4671Biquad_t& bq = filter.params;
2194 curFilters.pos = filter;
2195 writeReg(0x4E, 1);
2196 writeReg(0x4D, bq.a1);
2197 writeReg(0x4E, 2);
2198 writeReg(0x4D, bq.a2);
2199 writeReg(0x4E, 4);
2200 writeReg(0x4D, bq.b0);
2201 writeReg(0x4E, 5);
2202 writeReg(0x4D, bq.b1);
2203 writeReg(0x4E, 6);
2204 writeReg(0x4D, bq.b2);
2205 writeReg(0x4E, 7);
2206 writeReg(0x4D, bq.enable & 0x1);
2207}
2208
2214 const TMC4671Biquad_t& bq = filter.params;
2215 curFilters.vel = filter;
2216 writeReg(0x4E, 9);
2217 writeReg(0x4D, bq.a1);
2218 writeReg(0x4E, 10);
2219 writeReg(0x4D, bq.a2);
2220 writeReg(0x4E, 12);
2221 writeReg(0x4D, bq.b0);
2222 writeReg(0x4E, 13);
2223 writeReg(0x4D, bq.b1);
2224 writeReg(0x4E, 14);
2225 writeReg(0x4D, bq.b2);
2226 writeReg(0x4E, 15);
2227 writeReg(0x4D, bq.enable & 0x1);
2228}
2229
2235 const TMC4671Biquad_t& bq = filter.params;
2236 curFilters.torque = filter;
2237 writeReg(0x4E, 17);
2238 writeReg(0x4D, bq.a1);
2239 writeReg(0x4E, 18);
2240 writeReg(0x4D, bq.a2);
2241 writeReg(0x4E, 20);
2242 writeReg(0x4D, bq.b0);
2243 writeReg(0x4E, 21);
2244 writeReg(0x4D, bq.b1);
2245 writeReg(0x4E, 22);
2246 writeReg(0x4D, bq.b2);
2247 writeReg(0x4E, 23);
2248 writeReg(0x4D, bq.enable & 0x1);
2249}
2250
2251
2256// this->torqueFilter = params;
2257// setBiquadTorque(makeLpTmcFilter(params,enable));
2258//
2259 // Presets: off, Lowpass, notch, peak
2260 this->torqueFilterConf = conf;
2261 TMC4671Biquad filter;
2262 switch(conf.mode){
2263 default:
2265 filter = TMC4671Biquad(false);
2266 break;
2268 filter = TMC4671Biquad(Biquad(BiquadType::lowpass, (float)conf.params.freq / getPwmFreq(), (float)conf.params.q/100.0,0.0), true);
2269 break;
2271 filter = TMC4671Biquad(Biquad(BiquadType::notch, (float)conf.params.freq / getPwmFreq(), (float)conf.params.q/10.0,0.0), true);
2272 break;
2274 filter = TMC4671Biquad(Biquad(BiquadType::peak, (float)conf.params.freq / getPwmFreq(), (float)conf.params.q/10.0,conf.gain), true);
2275 break;
2276 }
2277 setBiquadTorque(filter);
2278}
2279
2280
2286void TMC4671::setBrakeLimits(uint16_t low,uint16_t high){
2287 uint32_t val = low | (high << 16);
2288 writeReg(0x75,val);
2289}
2290
2297 blinkClipLed(100, 0);
2298 int32_t pos = getPos();
2299 setTmcPos(0);
2300 PhiE lastphie = getPhiEtype();
2301 MotionMode lastmode = getMotionMode();
2302 updateReg(0x25, 0,0x1000,12); // Set dir normal
2303 setPhiE_ext(0);
2305 setFluxTorque(0, 0);
2307 rampFlux(bangInitPower, 1000);
2308
2309 int16_t phiE_abn = readReg(0x2A)>>16;
2310 int16_t phiE_abn_old = 0;
2311 int16_t rcount=0,c = 0; // Count how often direction was in reverse
2312 uint16_t highcount = 0; // Count high state of n pulse for polarity estimation
2313
2314 // Rotate a bit
2315 for(int16_t p = 0;p<0x0fff;p+=0x2f){
2316 setPhiE_ext(p);
2317 Delay(10);
2318 c++;
2319 phiE_abn_old = phiE_abn;
2320 phiE_abn = readReg(0x2A)>>16;
2321 // Count how often the new position was lower than the previous indicating a reversed encoder or motor direction
2322 if(phiE_abn < phiE_abn_old){
2323 rcount++;
2324 }
2325 if((readReg(0x76) & 0x04) >> 2){
2326 highcount++;
2327 }
2328 }
2329 setTmcPos(pos+getPos());
2330
2331 rampFlux(0, 100);
2332 setPhiEtype(lastphie);
2333 setMotionMode(lastmode,true);
2334
2335 bool npol = highcount > c/2;
2336 abnconf.rdir = rcount > c/2;
2337 if(npol != abnconf.npol) // Invert dir if polarity was reversed TODO correct? likely wrong at the moment
2338 abnconf.rdir = !abnconf.rdir;
2339
2340 abnconf.apol = npol;
2341 abnconf.bpol = npol;
2342 abnconf.npol = npol;
2343 blinkClipLed(0, 0);
2344}
2345
2350 blinkClipLed(100, 0);
2351
2352 PhiE lastphie = getPhiEtype();
2353 MotionMode lastmode = getMotionMode();
2354 int16_t oldPhiE = getPhiE();
2355 setPhiE_ext(oldPhiE);
2357 setFluxTorque(0, 0);
2359 rampFlux(bangInitPower, 1000);
2360 int16_t phiE_enc = getPhiEfromExternalEncoder();
2361 int16_t phiE_enc_old = 0;
2362 int16_t rcount=0,c = 0; // Count how often direction was in reverse
2363
2364 // Rotate a bit
2365 for(int16_t p = 0;p<0x0fff;p+=0x2f){
2366 setPhiE_ext(p+oldPhiE);
2367 Delay(10);
2368 c++;
2369 phiE_enc_old = phiE_enc;
2370 phiE_enc = getPhiEfromExternalEncoder();
2371 // Count how often the new position was lower than the previous indicating a reversed encoder or motor direction
2372 if(phiE_enc < phiE_enc_old){
2373 rcount++;
2374 }
2375 }
2376
2377 rampFlux(0, 100);
2378 setPhiEtype(lastphie);
2379 setMotionMode(lastmode,true);
2380
2381 if(rcount > c/2)
2382 conf.encoderReversed = !conf.encoderReversed;
2383
2384 blinkClipLed(0, 0);
2385}
2386
2387
2388
2401 updateReg(0x1A,(uint8_t)val,0xff,0);
2402}
2403
2404void TMC4671::setBBM(uint8_t bbmL,uint8_t bbmH){
2405 this->conf.bbmH = bbmH;
2406 this->conf.bbmL = bbmL;
2407 uint32_t bbmr = bbmL | (bbmH << 8);
2408 writeReg(0x19, bbmr);
2409}
2410
2411void TMC4671::setPwm(uint8_t val,uint16_t maxcnt,uint8_t bbmL,uint8_t bbmH){
2412 setPwmMaxCnt(maxcnt);
2413 setPwm((TMC_PwmMode)val);
2414 setBBM(bbmL, bbmH);
2415 writeReg(0x17,0); //Polarity
2416}
2417
2422void TMC4671::setSvPwm(bool enable){
2423 conf.motconf.svpwm = enable;
2424 if(conf.motconf.motor_type != MotorType::BLDC){
2425 enable = false; // Only valid for 3 phase motors with isolated star point
2426 }
2427
2428 updateReg(0x1A,enable,0x01,8);
2429}
2430
2436 return (4.0 * this->conf.hwconf.clockfreq) / (this->conf.pwmcnt +1);
2437}
2438
2444void TMC4671::setPwmMaxCnt(uint16_t maxcnt){
2445 maxcnt = clip(maxcnt, 255, 4095);
2446 this->conf.pwmcnt = maxcnt;
2447 writeReg(0x18, maxcnt);
2448}
2449
2455void TMC4671::setPwmFreq(float freq){
2456 if(freq <= 0)
2457 return;
2458 uint16_t maxcnt = ((4.0 * this->conf.hwconf.clockfreq) / freq) -1;
2459 setPwmMaxCnt(maxcnt);
2460}
2461
2462
2463void TMC4671::initAdc(uint16_t mdecA, uint16_t mdecB,uint32_t mclkA,uint32_t mclkB){
2464 uint32_t dat = mdecA | (mdecB << 16);
2465 writeReg(0x07, dat);
2466
2467 writeReg(0x05, mclkA);
2468 writeReg(0x06, mclkB);
2469 // Enable/Disable adcs
2470 updateReg(0x04, mclkA == 0 ? 0 : 1, 0x1, 4);
2471 updateReg(0x04, mclkB == 0 ? 0 : 1, 0x1, 20);
2472
2473 writeReg(0x0A,0x18000100); // ADC Selection
2474}
2475
2480std::pair<int32_t,int32_t> TMC4671::getActualTorqueFlux(){
2481 uint32_t tfluxa = readReg(0x69);
2482 int16_t af = (tfluxa & 0xffff);
2483 int16_t at = (tfluxa >> 16);
2484 return std::pair<int16_t,int16_t>(af,at);
2485}
2486
2491 uint32_t tfluxa = readReg(0x69);
2492 int16_t af = (tfluxa & 0xffff);
2493 return af;
2494}
2495
2500 uint32_t tfluxa = readReg(0x69);
2501 int16_t at = (tfluxa >> 16);
2502 return at;
2503}
2504
2505
2506//__attribute__((optimize("-Ofast")))
2507uint32_t TMC4671::readReg(uint8_t reg){
2508 spiPort.takeSemaphore();
2509 uint8_t req[5] = {(uint8_t)(0x7F & reg),0,0,0,0};
2510 uint8_t tbuf[5];
2511 // 500ns delay after sending first byte
2512 spiPort.transmitReceive(req, tbuf, 5,this, SPITIMEOUT);
2513 uint32_t ret;
2514 memcpy(&ret,tbuf+1,4);
2515 ret = __REV(ret);
2516
2517 return ret;
2518}
2519
2520//__attribute__((optimize("-Ofast")))
2521void TMC4671::writeReg(uint8_t reg,uint32_t dat){
2522
2523 // wait until ready
2524 spiPort.takeSemaphore();
2525 spi_buf[0] = (uint8_t)(0x80 | reg);
2526 dat =__REV(dat);
2527 memcpy(spi_buf+1,&dat,4);
2528
2529 // -----
2530 spiPort.transmit(spi_buf, 5, this, SPITIMEOUT);
2531}
2532
2533void TMC4671::writeRegAsync(uint8_t reg,uint32_t dat){
2534
2535 // wait until ready
2536 spiPort.takeSemaphore();
2537 spi_buf[0] = (uint8_t)(0x80 | reg);
2538 dat =__REV(dat);
2539 memcpy(spi_buf+1,&dat,4);
2540
2541 // -----
2542#ifdef TMC4671_ALLOW_DMA
2543 spiPort.transmit_DMA(this->spi_buf, 5, this);
2544#else
2545 spiPort.transmit_IT(this->spi_buf, 5, this);
2546#endif
2547}
2548
2549void TMC4671::updateReg(uint8_t reg,uint32_t dat,uint32_t mask,uint8_t shift){
2550
2551 uint32_t t = readReg(reg) & ~(mask << shift);
2552 t |= ((dat & mask) << shift);
2553 writeReg(reg, t);
2554}
2555
2561 port->giveSemaphore();
2562}
2563
2569 uint32_t flags = readReg(0x7C);
2570 if(maskedOnly){
2571 flags = flags & this->statusMask.asInt;
2572 }
2573 this->statusFlags.asInt = flags; // Only set flags that are marked to trigger a notification
2574 return statusFlags;
2575}
2576
2578 writeReg(0x7D, mask.asInt);
2579}
2580
2581void TMC4671::setStatusMask(uint32_t mask){
2582 writeReg(0x7D, mask);
2583}
2584
2585void TMC4671::setStatusFlags(uint32_t flags){
2586 writeReg(0x7C, flags);
2587}
2588
2590 writeReg(0x7C, flags.asInt);
2591}
2592
2597 flagCheckInProgress = true;
2598 statusFlags = readFlags(); // Update current flags
2599
2600 // encoder index flag was set since last check. Check if the flag matching the current encoder is set
2601 if( (statusFlags.flags.ENC_N && this->conf.motconf.enctype == EncoderType_TMC::abn) || (statusFlags.flags.AENC_N && this->conf.motconf.enctype == EncoderType_TMC::sincos) ){
2603 }
2604
2605 if(statusFlags.flags.not_PLL_locked){
2606 // Critical error. PLL not locked
2607 // Creating error object not allowed. Function is called from flag isr! ignore for now.
2608 //ErrorHandler::addError(Error(ErrorCode::tmcPLLunlocked, ErrorType::critical, "TMC PLL not locked"));
2609 }
2610
2611
2612 setStatusFlags(0); // Reset flags
2613 if(readFlags().asInt != statusFlags.asInt){ // Condition is cleared. if not we will reset it in the main loop later to get out of the isr and cause some delay
2614 flagCheckInProgress = false;
2615 }
2616}
2617
2618void TMC4671::exti(uint16_t GPIO_Pin){
2619 if(GPIO_Pin == FLAG_Pin && !flagCheckInProgress){ // Flag pin went high and flag check is currently not in progress (prevents interrupt flooding)
2620 statusCheck(); // In isr!
2621 }
2622}
2623
2625 //pulseClipLed();
2626// if(zeroEncoderOnIndexHit){
2627// writeReg(0x27, 0);
2628// }
2629 setEncoderIndexFlagEnabled(false,false); // Found the index. disable flag
2630 encoderIndexHitFlag = true;
2631}
2632
2634 // 0-2: MotType 3-5: Encoder source 6-15: Poles
2635 TMC4671MotConf mot;
2636 mot.motor_type = MotorType(val & 0x3);
2637 mot.svpwm = !(val & 0x4);
2638 mot.enctype = EncoderType_TMC( (val >> 3) & 0x7);
2639 mot.pole_pairs = val >> 6;
2640 return mot;
2641}
2643 uint16_t val = (uint8_t)mconf.motor_type & 0x3;
2644 val |= !mconf.svpwm ? 0x4 : 0;
2645 val |= ((uint8_t)mconf.enctype & 0x7) << 3;
2646 val |= (mconf.pole_pairs & 0x3FF) << 6;
2647 return val;
2648}
2649
2651 uint16_t val = 0;
2652 val |= (this->abnconf.npol) & 0x01;
2653 val |= (this->conf.encoderReversed & 0x01) << 1; // Direction
2654
2655
2656 val |= (this->abnconf.ab_as_n & 0x01) << 2;
2657 val |= (this->pidPrecision.current_I) << 3;
2658 val |= (this->pidPrecision.current_P) << 4;
2659
2660 val |= (this->abnconf.useIndex) << 5;
2661
2662 val |= (this->conf.combineEncoder) << 6;
2663 val |= (this->conf.invertForce) << 7;
2664
2665 val |= ((this->conf.enableFluxDissipation & 0x01) << 8);
2666 val |= (this->hallconf.interpolation & 0x01) << 9;
2667
2668 val |= (this->curPids.sequentialPI & 0x01) << 10;
2669
2670 //11,12,13,14,15 hw version
2671 val |= ((uint8_t)this->conf.hwconf.hwVersion & 0x1F) << 11;
2672
2673 return val;
2674}
2675
2677
2678 this->abnconf.apol = (val) & 0x01;
2679
2680 this->abnconf.bpol = this->abnconf.apol;
2681 this->abnconf.npol = this->abnconf.apol;
2682
2683 this->conf.encoderReversed = (val>>1) & 0x01;// Direction
2684 this->abnconf.rdir = this->conf.encoderReversed;
2685 this->aencconf.rdir = this->conf.encoderReversed;
2686 this->hallconf.direction = this->conf.encoderReversed;
2687
2688 this->abnconf.ab_as_n = (val>>2) & 0x01;
2689 this->pidPrecision.current_I = (val>>3) & 0x01;
2690 this->pidPrecision.velocity_I = this->pidPrecision.current_I;
2691 this->pidPrecision.position_I = this->pidPrecision.current_I;
2692 this->pidPrecision.current_P = (val>>4) & 0x01;
2693 this->pidPrecision.velocity_P = this->pidPrecision.current_P;
2694 this->pidPrecision.velocity_P = this->pidPrecision.current_P;
2695
2696 this->abnconf.useIndex = (val>>5) & 0x01;
2697 this->conf.combineEncoder = (val>>6) & 0x01;
2698 this->conf.invertForce = ((val>>7) & 0x01) && this->conf.combineEncoder;
2699
2700 this->conf.enableFluxDissipation = ((val>>8) & 0x01);
2701 this->hallconf.interpolation = (val>>9) & 0x01;
2702 this->curPids.sequentialPI = (val>>10) & 0x01;
2703
2704 setHwType((uint8_t)((val >> 11) & 0x1F));
2705
2706}
2707
2708
2709
2713void TMC4671::setHwType(uint8_t type){
2714 // If only one config is valid use this regardless of requested type
2715 if(TMC4671::tmc4671_hw_configs.size() == 1){
2716 this->conf.hwconf = TMC4671::tmc4671_hw_configs[0];
2717 }else{ // Search for config matching requested type
2719 if(type == newConf.hwVersion){
2720 this->conf.hwconf = newConf;
2721 break;
2722 }
2723 }
2724 }
2725
2726 setVSenseMult(this->conf.hwconf.vSenseMult); // Update vsense multiplier
2727 //setupBrakePin(vdiffAct, vdiffDeact, vMax); // TODO if required
2728 setBrakeLimits(this->conf.hwconf.brakeLimLow,this->conf.hwconf.brakeLimHigh);
2729 setBBM(this->conf.hwconf.bbm,this->conf.hwconf.bbm);
2730 // Force changing motor and encoder types to prevent invalid types being selected if new hw type does not support them
2731 setMotorType(this->conf.motconf.motor_type, this->conf.motconf.pole_pairs);
2732 setEncoderType(this->conf.motconf.enctype);
2733}
2734
2738void TMC4671::replyHardwareVersions(const std::span<const TMC4671HardwareTypeConf>& versions,std::vector<CommandReply>& replies){
2739// uint8_t idx = 0;
2740 for(const TMC4671HardwareTypeConf& c : versions){
2741 if(this->canChangeHwType || c.hwVersion == this->conf.hwconf.hwVersion){
2742 replies.emplace_back( std::to_string((uint8_t)c.hwVersion) + ":" + c.name,(uint8_t)c.hwVersion);
2743 }
2744 }
2745}
2746
2749
2750 registerCommand("cpr", TMC4671_commands::cpr, "CPR in TMC",CMDFLAG_GET | CMDFLAG_SET);
2751 registerCommand("mtype", TMC4671_commands::mtype, "Motor type",CMDFLAG_GET | CMDFLAG_SET | CMDFLAG_INFOSTRING);
2752 registerCommand("encsrc", TMC4671_commands::encsrc, "Encoder source",CMDFLAG_GET | CMDFLAG_SET | CMDFLAG_INFOSTRING);
2753 registerCommand("tmcHwType", TMC4671_commands::tmcHwType, "Version of TMC board",CMDFLAG_GET | CMDFLAG_SET | CMDFLAG_INFOSTRING);
2754 registerCommand("encalign", TMC4671_commands::encalign, "Align encoder",CMDFLAG_GET);
2755 registerCommand("poles", TMC4671_commands::poles, "Motor pole pairs",CMDFLAG_GET | CMDFLAG_SET);
2756 registerCommand("acttrq", TMC4671_commands::acttrq, "Measure torque and flux",CMDFLAG_GET);
2757 registerCommand("pwmlim", TMC4671_commands::pwmlim, "PWM limit",CMDFLAG_DEBUG | CMDFLAG_GET | CMDFLAG_SET);
2758 registerCommand("torqueP", TMC4671_commands::torqueP, "Torque P",CMDFLAG_GET | CMDFLAG_SET);
2759 registerCommand("torqueI", TMC4671_commands::torqueI, "Torque I",CMDFLAG_GET | CMDFLAG_SET);
2760 registerCommand("fluxP", TMC4671_commands::fluxP, "Flux P",CMDFLAG_GET | CMDFLAG_SET);
2761 registerCommand("fluxI", TMC4671_commands::fluxI, "Flux I",CMDFLAG_GET | CMDFLAG_SET);
2762 registerCommand("velocityP", TMC4671_commands::velocityP, "Velocity P",CMDFLAG_GET | CMDFLAG_SET);
2763 registerCommand("velocityI", TMC4671_commands::velocityI, "Velocity I",CMDFLAG_GET | CMDFLAG_SET);
2764 registerCommand("posP", TMC4671_commands::posP, "Pos P",CMDFLAG_GET | CMDFLAG_SET);
2765 registerCommand("posI", TMC4671_commands::posI, "Pos I",CMDFLAG_GET | CMDFLAG_SET);
2766 registerCommand("tmctype", TMC4671_commands::tmctype, "Version of TMC chip",CMDFLAG_GET);
2767 registerCommand("pidPrec", TMC4671_commands::pidPrec, "PID precision bit0=I bit1=P. 0=Q8.8 1= Q4.12",CMDFLAG_GET | CMDFLAG_SET);
2768 registerCommand("phiesrc", TMC4671_commands::phiesrc, "PhiE source",CMDFLAG_DEBUG | CMDFLAG_GET | CMDFLAG_SET);
2769 registerCommand("fluxoffset", TMC4671_commands::fluxoffset, "Offset flux scale for field weakening",CMDFLAG_GET | CMDFLAG_SET);
2770 registerCommand("seqpi", TMC4671_commands::seqpi, "Sequential PI",CMDFLAG_GET | CMDFLAG_SET);
2771 registerCommand("iScale", TMC4671_commands::tmcIscale, "Counts per A",CMDFLAG_STR_ONLY);
2772 registerCommand("encdir", TMC4671_commands::encdir, "Encoder dir",CMDFLAG_DEBUG | CMDFLAG_GET | CMDFLAG_SET);
2773 registerCommand("abnpol", TMC4671_commands::encpol, "Encoder polarity",CMDFLAG_GET | CMDFLAG_SET);
2774 registerCommand("temp", TMC4671_commands::temp, "Temperature in C * 100",CMDFLAG_GET);
2775 registerCommand("reg", TMC4671_commands::reg, "Read or write a TMC register at adr",CMDFLAG_DEBUG | CMDFLAG_GETADR | CMDFLAG_SETADR);
2776 registerCommand("svpwm", TMC4671_commands::svpwm, "Space-vector PWM",CMDFLAG_GET | CMDFLAG_SET);
2777 registerCommand("autohome", TMC4671_commands::findIndex, "Find abn index",CMDFLAG_GET);
2778 registerCommand("abnindex", TMC4671_commands::abnindexenabled, "Enable ABN index",CMDFLAG_GET | CMDFLAG_SET);
2779 registerCommand("calibrate", TMC4671_commands::fullCalibration, "Full calibration",CMDFLAG_GET);
2780 registerCommand("calibrated", TMC4671_commands::calibrated, "Calibration valid",CMDFLAG_GET);
2781 registerCommand("state", TMC4671_commands::getState, "Get state",CMDFLAG_GET);
2782 registerCommand("combineEncoder", TMC4671_commands::combineEncoder, "Use TMC for movement. External encoder for position",CMDFLAG_GET | CMDFLAG_SET);
2783 registerCommand("invertForce", TMC4671_commands::invertForce, "Invert incoming forces",CMDFLAG_GET | CMDFLAG_SET);
2784 registerCommand("vm", TMC4671_commands::vmTmc, "VM in mV",CMDFLAG_GET);
2785 registerCommand("extphie", TMC4671_commands::extphie, "external phie",CMDFLAG_GET);
2786 registerCommand("trqbq_mode", TMC4671_commands::torqueFilter_mode, "Torque filter mode: none;lowpass;notch;peak",CMDFLAG_GET | CMDFLAG_SET | CMDFLAG_INFOSTRING);
2787 registerCommand("trqbq_f", TMC4671_commands::torqueFilter_f, "Torque filter freq 1000 max. 0 to disable. (Stored f/2)",CMDFLAG_GET | CMDFLAG_SET);
2788 registerCommand("trqbq_q", TMC4671_commands::torqueFilter_q, "Torque filter q*100",CMDFLAG_GET | CMDFLAG_SET);
2789 registerCommand("pidautotune", TMC4671_commands::pidautotune, "Start PID autoruning",CMDFLAG_GET);
2790 registerCommand("fluxbrake", TMC4671_commands::fluxbrake, "Prefer energy dissipation in motor",CMDFLAG_GET | CMDFLAG_SET);
2791 registerCommand("pwmfreq", TMC4671_commands::pwmfreq, "Get/set pwm frequency",CMDFLAG_GET | CMDFLAG_SET | CMDFLAG_DEBUG);
2792}
2793
2794
2795CommandStatus TMC4671::command(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
2797 switch(static_cast<TMC4671_commands>(cmd.cmdId)){
2799 status = handleGetSet(cmd, replies, this->conf.combineEncoder);
2800 if(!this->conf.combineEncoder){
2801 this->conf.invertForce = false; // Force off
2802 }
2803
2804 break;
2805
2808 break;
2809
2811 handleGetSet(cmd, replies, conf.invertForce);
2812 break;
2813
2815 replies.emplace_back((uint32_t)getState());
2816 break;
2817
2819 calibrationFailCount = 1; // allow 1 fail
2821 // TODO start full calibration and save in flash
2822 break;
2823
2825 replies.emplace_back(!recalibrationRequired && adcCalibrated);
2826 break;
2827
2829 if(cmd.type == CMDtype::get){
2830 replies.emplace_back((uint8_t)this->conf.motconf.motor_type);
2831 }else if(cmd.type == CMDtype::set && (uint8_t)cmd.type <= (uint8_t)MotorType::BLDC){
2832 this->setMotorType((MotorType)cmd.val, this->conf.motconf.pole_pairs);
2833 }else{
2834 std::string rplstr = "";
2835 TMC4671HardwareTypeConf::SupportedModes_s* confflags = &conf.hwconf.flags;
2836 if(confflags->mot_none) rplstr += "NONE=0,";
2837 if(confflags->mot_dc) rplstr += "DC=1,";
2838 if(confflags->mot_stepper) rplstr += "Stepper 2Ph=2,";
2839 if(confflags->mot_bldc) rplstr += "BLDC 3Ph=3";
2840 replies.emplace_back(rplstr);
2841 }
2842 break;
2843
2845 if(cmd.type == CMDtype::get){
2846 replies.emplace_back((uint8_t)this->conf.motconf.enctype);
2847 }else if(cmd.type == CMDtype::set){
2849 }else{
2850 std::string rplstr = "";
2851 TMC4671HardwareTypeConf::SupportedModes_s* confflags = &conf.hwconf.flags;
2852 if(confflags->enc_none) rplstr += "NONE=0,";
2853 if(confflags->enc_abn) rplstr += "ABN=1,";
2854 if(confflags->enc_sincos) rplstr += "SinCos=2,";
2855 if(confflags->enc_uvw) rplstr += "UVW=3,";
2856 if(confflags->enc_hall) rplstr += "HALL=4,";
2857 if(confflags->enc_ext && externalEncoderAllowed()) rplstr += "External=5";
2858 replies.emplace_back(rplstr);
2859 }
2860 break;
2861
2863 if(cmd.type == CMDtype::get){
2864 replies.push_back((uint8_t)conf.hwconf.hwVersion);
2865 }else if(cmd.type == CMDtype::set){
2866 if(canChangeHwType)
2867 setHwType((uint8_t)(cmd.val & 0x1F));
2868 }else{
2869 // List known hardware versions
2871 }
2872 break;
2873
2875 if(cmd.type == CMDtype::get){
2876 encoderAligned = false;
2877 this->setEncoderType(this->conf.motconf.enctype);
2878 manualEncAlign = true;
2880 }else{
2881 return CommandStatus::ERR;
2882 }
2883 break;
2884
2886 if(cmd.type == CMDtype::get){
2887 replies.emplace_back(this->conf.motconf.pole_pairs);
2888 }else if(cmd.type == CMDtype::set){
2889 this->setMotorType(this->conf.motconf.motor_type,cmd.val);
2890 }
2891 break;
2892
2894 if(cmd.type == CMDtype::get){
2895 std::pair<int32_t,int32_t> current = getActualTorqueFlux();
2896 replies.emplace_back(current.second,current.first);
2897 }
2898 break;
2899
2901 if(cmd.type == CMDtype::get){
2902 replies.emplace_back(this->curLimits.pid_uq_ud);
2903 }else if(cmd.type == CMDtype::set){
2904 this->setUqUdLimit(cmd.val);
2905 }
2906 break;
2907
2909 handleGetSet(cmd, replies, this->curPids.torqueP);
2910 if(cmd.type == CMDtype::set)
2912 break;
2913
2915 handleGetSet(cmd, replies, this->curPids.torqueI);
2916 if(cmd.type == CMDtype::set)
2918 break;
2919
2921 handleGetSet(cmd, replies, this->curPids.fluxP);
2922 if(cmd.type == CMDtype::set)
2924 break;
2925
2927 handleGetSet(cmd, replies, this->curPids.fluxI);
2928 if(cmd.type == CMDtype::set)
2930 break;
2931
2933 handleGetSet(cmd, replies, this->curPids.velocityP);
2934 if(cmd.type == CMDtype::set)
2936 break;
2937
2939 handleGetSet(cmd, replies, this->curPids.velocityI);
2940 if(cmd.type == CMDtype::set)
2942 break;
2943
2945 handleGetSet(cmd, replies, this->curPids.positionP);
2946 if(cmd.type == CMDtype::set)
2948 break;
2949
2951 handleGetSet(cmd, replies, this->curPids.positionI);
2952 if(cmd.type == CMDtype::set)
2954 break;
2955
2957 handleGetSet(cmd, replies, this->abnconf.useIndex);
2958 if(cmd.type == CMDtype::set)
2960 break;
2961
2963 {
2964 std::pair<uint32_t,std::string> ver = getTmcType();
2965 replies.emplace_back(ver.second,ver.first);
2966 break;
2967 }
2968
2970 replies.emplace_back(getTmcVM());
2971 break;
2972
2974 if(cmd.type == CMDtype::get){
2975 replies.emplace_back(this->pidPrecision.current_I | (this->pidPrecision.current_P << 1));
2976 }else if(cmd.type == CMDtype::set){
2977 this->pidPrecision.current_I = cmd.val & 0x1;
2978 this->pidPrecision.current_P = (cmd.val >> 1) & 0x1;
2980 }
2981 break;
2983 if(cmd.type == CMDtype::get){
2984 replies.emplace_back((uint8_t)this->getPhiEtype());
2985 }else if(cmd.type == CMDtype::set){
2986 this->setPhiEtype((PhiE)cmd.val);
2987 }else{
2988 replies.emplace_back("ext=1,openloop=2,abn=3,hall=5,aenc=6,aencE=7");
2989 }
2990 break;
2992 handleGetSet(cmd, replies, maxOffsetFlux);
2993 break;
2995 if(cmd.type == CMDtype::get){
2996 replies.emplace_back(this->curPids.sequentialPI);
2997 }else if(cmd.type == CMDtype::set){
2998 this->setSequentialPI(cmd.val != 0);
2999 }
3000 break;
3002 if(cmd.type == CMDtype::get){
3003 replies.emplace_back(std::to_string(this->conf.hwconf.currentScaler)); // TODO float as value?
3004 }
3005 break;
3007 if(cmd.type == CMDtype::get){
3008 replies.emplace_back(this->abnconf.rdir);
3009 }else if(cmd.type == CMDtype::set){
3010 this->abnconf.rdir = cmd.val != 0;
3011 this->setup_ABN_Enc(this->abnconf);
3012 }
3013 break;
3014
3016 if(cmd.type == CMDtype::get){
3017 replies.emplace_back(this->abnconf.npol);
3018 }else if(cmd.type == CMDtype::set){
3019 this->abnconf.npol = cmd.val != 0;
3020 this->abnconf.apol = cmd.val != 0;
3021 this->abnconf.bpol = cmd.val != 0;
3022 this->setup_ABN_Enc(this->abnconf);
3023 }
3024 break;
3026 if(cmd.type == CMDtype::get){
3027 replies.emplace_back((int32_t)(this->getTemp()*100.0));
3028 }
3029 break;
3031 if(cmd.type == CMDtype::getat){
3032 replies.emplace_back(readReg(cmd.val));
3033 }else if(cmd.type == CMDtype::setat){
3034 writeReg(cmd.adr,cmd.val);
3035 }else{
3036 return CommandStatus::ERR;
3037 }
3038 break;
3039
3042 break;
3043
3045 {
3046 if(cmd.type == CMDtype::set){
3047 setSvPwm(cmd.val != 0);
3048 }else if(cmd.type == CMDtype::get){
3049 replies.emplace_back(conf.motconf.svpwm);
3050 }
3051 break;
3052 }
3054 {
3055
3056 replies.emplace_back(getPhiEfromExternalEncoder());
3057
3058 break;
3059 }
3061 if(cmd.type == CMDtype::get){
3062 replies.emplace_back((uint8_t)this->torqueFilterConf.mode);
3063 }else if(cmd.type == CMDtype::set && (uint8_t)cmd.val < 4){
3064 torqueFilterConf.mode = (TMCbiquadpreset)(cmd.val);
3066 }else{
3067 replies.emplace_back("OFF=0,Lowpass=1,Notch=2,Peak=3");
3068 }
3069 break;
3071 {
3072 if(cmd.type == CMDtype::set){
3073 torqueFilterConf.params.freq = clip(cmd.val,1,0x1fff);
3075 }else if(cmd.type == CMDtype::get){
3076 replies.emplace_back(torqueFilterConf.params.freq);
3077 }
3078 break;
3079 }
3080
3082 if(cmd.type == CMDtype::set){
3083 torqueFilterConf.params.q = clip(cmd.val,0,127);
3085 }else if(cmd.type == CMDtype::get){
3086 replies.emplace_back(torqueFilterConf.params.q);
3087 }
3088 break;
3092
3094 handleGetSet(cmd, replies, conf.enableFluxDissipation);
3095 break;
3096
3098 if(cmd.type == CMDtype::set){
3099 setPwmFreq(cmd.val);
3100 }else if(cmd.type == CMDtype::get){
3101 replies.emplace_back(getPwmFreq());
3102 }
3103 break;
3104
3105 default:
3107 }
3108
3109 return status;
3110
3111
3112}
3113
3114#ifdef TIM_TMC
3115 void TMC4671::timerElapsed(TIM_HandleTypeDef* htim){
3116 if(htim != this->externalEncoderTimer){
3117 return;
3118 }
3119 // Read encoder and send to tmc
3120 if(usingExternalEncoder() && externalEncoderAllowed() && this->conf.motconf.phiEsource == PhiE::extEncoder && extEncUpdater != nullptr){
3121 //setPhiE_ext(getPhiEfromExternalEncoder());
3122 // Signal phiE update
3123 extEncUpdater->updateFromIsr(); // Use task so that the update is not being done inside an ISR
3124 }
3125 }
3126#endif
3127
3129#ifdef TIM_TMC
3130 if(extEncUpdater == nullptr) // Create updater thread
3131 extEncUpdater = std::make_unique<TMC_ExternalEncoderUpdateThread>(this);
3132 // Setup timer
3134 this->externalEncoderTimer->Instance->ARR = TIM_TMC_ARR; // 200 = 5khz = 5 tmc cycles, 250 = 4khz, 240 = 6 tmc cycles
3135 this->externalEncoderTimer->Instance->PSC = ((TIM_TMC_BCLK)/1000000) +1; // 1µs ticks
3136 this->externalEncoderTimer->Instance->CR1 = 1;
3137 HAL_TIM_Base_Start_IT(this->externalEncoderTimer);
3138#endif
3139}
3140
3147
3149 while(true){
3150 this->WaitForNotification();
3151 if(tmc->usingExternalEncoder() && !tmc->spiPort.isTaken()){
3152 tmc->writeRegAsync(0x1C, (tmc->getPhiEfromExternalEncoder())); // Write phiE_ext
3153 }
3154 }
3155}
3156
3158 if(tmc->initialized)
3159 this->NotifyFromISR();
3160}
3161
3162void TMC4671::errorCallback(const Error &error, bool cleared){
3163 if(!cleared && error.code == ErrorCode::brakeResistorFailure){
3164 // shut down and block.
3165 emergencyStop(false);
3167 }
3168}
3169#endif
CommandStatus
EncoderType
Definition Encoder.h:27
@ incremental
Definition Encoder.h:27
@ incrementalIndex
Definition Encoder.h:27
@ brakeResistorFailure
@ adcCalibrationError
@ encoderAlignmentFailed
MotionMode
Definition TMC4671.h:71
EncoderType_TMC
Definition TMC4671.h:75
MotorType
Definition TMC4671.h:69
@ STEPPER
Definition TMC4671.h:69
FFMode
Definition TMC4671.h:72
@ none
Definition TMC4671.h:72
VelSelection
Definition TMC4671.h:74
TMCbiquadpreset
Definition TMC4671.h:325
TMC_GpioMode
Definition TMC4671.h:67
TIM_HandleTypeDef TIM_TMC
TMC_PwmMode
Definition TMC4671.h:63
TMC_ControlState
Definition TMC4671.h:61
PhiE
Definition TMC4671.h:70
@ aenc
Definition TMC4671.h:70
@ abn
Definition TMC4671.h:70
@ extEncoder
Definition TMC4671.h:70
@ hall
Definition TMC4671.h:70
@ ext
Definition TMC4671.h:70
@ openloop
Definition TMC4671.h:70
PosSelection
Definition TMC4671.h:73
@ PhiE_openloop
Definition TMC4671.h:73
static CommandStatus handleGetFuncSetFunc(const ParsedCommand &cmd, std::vector< CommandReply > &replies, TVal(cls1::*getfunc)(), void(cls2::*setfunc)(TVal), cls *obj)
void registerCommand(const char *cmd, const ID cmdid, const char *help=nullptr, uint32_t flags=0)
virtual void setCommandsEnabled(bool enable)
static CommandStatus handleGetSet(const ParsedCommand &cmd, std::vector< CommandReply > &replies, TVal &value)
void broadcastCommandReply(CommandReply reply, uint32_t cmdId, CMDtype type)
CommandHandler(const char *clsname, uint16_t clsid, uint8_t instance=0)
Encoder()
Definition Encoder.cpp:18
static void clearError(const Error &error)
static void addError(const Error &error)
ErrorCode code
std::shared_ptr< Encoder > drvEncoder
Definition MotorDriver.h:46
SPIPort & spiPort
Definition SPI.h:125
SPIDevice(SPIPort &port, OutputPin csPin)
Definition SPI.cpp:333
void assertChipSelect()
Definition SPI.cpp:375
void clearChipSelect()
Definition SPI.cpp:379
SPIConfig spiConfig
Definition SPI.h:126
Definition SPI.h:44
void giveSemaphore()
Definition SPI.cpp:199
TMC4671Biquad_t params
Definition TMC4671.h:360
void writeReg(uint8_t reg, uint32_t dat)
Definition TMC4671.cpp:2521
static ClassIdentifier info
Definition TMC4671.h:42
int16_t bangInitPower
Definition TMC4671.h:496
void beginSpiTransfer(SPIPort *port)
Definition TMC4671.cpp:2556
void setFluxTorque(int16_t flux, int16_t torque)
Definition TMC4671.cpp:2064
void calibrateEncoder()
Definition TMC4671.cpp:651
void saveFlash() override
Definition TMC4671.cpp:107
void setBBM(uint8_t bbml, uint8_t bbmh)
Definition TMC4671.cpp:2404
int16_t controlFluxDissipate()
Definition TMC4671.cpp:1718
int32_t getTargetPos()
Definition TMC4671.cpp:908
int16_t externalEncoderPhieOffset
Definition TMC4671.h:665
PhiE getPhiEtype()
Definition TMC4671.cpp:1603
bool pidAutoTune()
Definition TMC4671.cpp:671
bool adcSettingsStored
Definition TMC4671.h:654
TMC_ControlState getState()
Definition TMC4671.cpp:781
TMC4671Limits curLimits
Definition TMC4671.h:551
int16_t getFlux()
Definition TMC4671.cpp:2061
void setExternalEncoderAllowed(bool allow)
Definition TMC4671.cpp:2003
bool externalEncoderAllowed()
Definition TMC4671.cpp:2016
TMC4671PIDConf getPids()
Definition TMC4671.cpp:2108
bool allowExternalEncoder
Definition TMC4671.h:666
bool autohome()
Definition TMC4671.cpp:767
bool encHallRestored
Definition TMC4671.h:660
void statusCheck()
Definition TMC4671.cpp:2596
void startMotor()
Definition TMC4671.cpp:1669
const Error estopError
Definition TMC4671.h:636
void setLimits(TMC4671Limits limits)
Definition TMC4671.cpp:2145
void runOpenLoop(uint16_t ud, uint16_t uq, int32_t speed, int32_t accel, bool torqueMode=false)
Definition TMC4671.cpp:1633
bool hasIntegratedEncoder() override
Definition TMC4671.cpp:1866
volatile bool encoderIndexHitFlag
Definition TMC4671.h:656
TMC_ControlState state
Definition TMC4671.h:638
uint32_t initTime
Definition TMC4671.h:699
void setupFeedForwardVelocity(int32_t gain, int32_t constant)
Definition TMC4671.cpp:1983
CommandStatus command(const ParsedCommand &cmd, std::vector< CommandReply > &replies)
Definition TMC4671.cpp:2795
uint32_t getCpr()
Definition TMC4671.cpp:1919
uint8_t calibrationFailCount
Definition TMC4671.h:663
bool fullCalibrationInProgress
Definition TMC4671.h:658
void setEncoderIndexFlagEnabled(bool enabled, bool zeroEncoder=false)
Definition TMC4671.cpp:882
void initializeWithPower()
Definition TMC4671.cpp:388
static std::span< const TMC4671HardwareTypeConf > tmc4671_hw_configs
Definition TMC4671.h:629
void setPos(int32_t pos) override
Definition TMC4671.cpp:1874
void bangInitEnc(int16_t power)
Definition TMC4671.cpp:962
bool reachedPosition(uint16_t tolerance)
Definition TMC4671.cpp:797
TMC4671_commands
Definition TMC4671.h:381
void setPids(TMC4671PIDConf pids)
Definition TMC4671.cpp:2099
MotionMode lastMotionMode
Definition TMC4671.h:642
const float fluxDissipationLimit
Definition TMC4671.h:499
TMC4671ABNConf abnconf
Definition TMC4671.h:561
TMC_ControlState requestedState
Definition TMC4671.h:640
bool usingExternalEncoder()
Definition TMC4671.h:569
void setUdUq(int16_t ud, int16_t uq)
Definition TMC4671.cpp:1654
StatusFlags statusMask
Definition TMC4671.h:597
void changeState(TMC_ControlState newState, bool force=false)
Definition TMC4671.cpp:785
int16_t idleFlux
Definition TMC4671.h:493
const Error lowVoltageError
Definition TMC4671.h:634
void replyHardwareVersions(const std::span< const TMC4671HardwareTypeConf > &versions, std::vector< CommandReply > &replies)
Definition TMC4671.cpp:2738
void setVelSel(VelSelection vsel, uint8_t mode=0)
Definition TMC4671.cpp:1772
void setEncoderType(EncoderType_TMC type)
Definition TMC4671.cpp:1520
uint16_t maxOffsetFlux
Definition TMC4671.h:494
TMC4671PIDConf curPids
Definition TMC4671.h:549
TIM_HandleTypeDef * externalEncoderTimer
Definition TMC4671.h:711
bool allowSlowSPI
Definition TMC4671.h:606
TMC4671BiquadFilters curFilters
Definition TMC4671.h:705
MotionMode getMotionMode()
Definition TMC4671.cpp:1622
bool ES_TMCdetected
Definition TMC4671.h:647
TMC_ControlState laststate
Definition TMC4671.h:639
void setBrakeLimits(uint16_t low, uint16_t high)
Definition TMC4671.cpp:2286
TMC4671PidPrecision pidPrecision
Definition TMC4671.h:559
bool recalibrationRequired
Definition TMC4671.h:669
uint16_t encodeEncHallMisc()
Definition TMC4671.cpp:2650
void setPhiE_ext(int16_t phiE)
Definition TMC4671.cpp:935
int32_t getTargetVelocity()
Definition TMC4671.cpp:924
void calibFailCb()
Definition TMC4671.cpp:1425
void timerElapsed(TIM_HandleTypeDef *htim)
Definition TMC4671.cpp:3115
bool emergency
Definition TMC4671.h:489
void setStatusFlags(uint32_t flags)
Definition TMC4671.cpp:2585
void setFluxTorqueFF(int16_t flux, int16_t torque)
Definition TMC4671.cpp:2075
bool canChangeHwType
Definition TMC4671.h:661
void setBiquadVel(const TMC4671Biquad &filter)
Definition TMC4671.cpp:2213
void restoreEncHallMisc(uint16_t val)
Definition TMC4671.cpp:2676
TMC4671MainConfig conf
Definition TMC4671.h:413
void setUpExtEncTimer()
Definition TMC4671.cpp:3128
static uint16_t encodeMotToInt(TMC4671MotConf mconf)
Definition TMC4671.cpp:2642
virtual ~TMC4671()
Definition TMC4671.cpp:81
void setTorque(int16_t torque)
Definition TMC4671.cpp:2045
bool pingDriver()
Definition TMC4671.cpp:226
bool calibrateAdcOffset(uint16_t time=500)
Definition TMC4671.cpp:1364
int32_t getPosAbs() override
Definition TMC4671.cpp:1903
int32_t getTmcVM()
Definition TMC4671.cpp:234
void setStatusMask(StatusFlags mask)
Definition TMC4671.cpp:2577
void zeroAbnUsingPhiM(bool offsetPhiE=false)
Definition TMC4671.cpp:807
bool isSetUp()
Definition TMC4671.cpp:201
void encoderIndexHit()
Definition TMC4671.cpp:2624
int16_t getPhiE()
Definition TMC4671.cpp:951
void setSequentialPI(bool sequential)
Definition TMC4671.cpp:1998
TMC4671AENCConf aencconf
Definition TMC4671.h:563
TMC4671HALLConf hallconf
Definition TMC4671.h:562
MotionMode curMotionMode
Definition TMC4671.h:641
const float fluxFilterFreq
Definition TMC4671.h:706
const Error indexNotHitError
Definition TMC4671.h:633
void setup_AENC(TMC4671AENCConf encconf)
Definition TMC4671.cpp:1318
Encoder * getEncoder() override
Definition TMC4671.cpp:1848
void setGpioPins(uint8_t pins)
Definition TMC4671.cpp:1816
int32_t getActualFlux()
Definition TMC4671.cpp:2490
int16_t getTorque()
Definition TMC4671.cpp:2051
bool encoderAligned
Definition TMC4671.h:649
void setMotionMode(MotionMode mode, bool force=false)
Definition TMC4671.cpp:1611
uint32_t lastStatTime
Definition TMC4671.h:674
void setTargetPos(int32_t pos)
Definition TMC4671.cpp:901
void setMotorType(MotorType motor, uint16_t poles)
Definition TMC4671.cpp:2024
int32_t getPos() override
Definition TMC4671.cpp:1897
void rampFlux(uint16_t target, uint16_t time_ms)
Definition TMC4671.cpp:2085
bool checkAdc()
Definition TMC4671.cpp:377
uint8_t spi_buf[5]
Definition TMC4671.h:676
void setPwm(uint8_t val, uint16_t maxcnt, uint8_t bbmL, uint8_t bbmH)
Definition TMC4671.cpp:2411
bool motorReady()
Definition TMC4671.cpp:426
bool checkEncoder()
Definition TMC4671.cpp:1172
void setGpioMode(TMC_GpioMode mode)
Definition TMC4671.cpp:1782
void endSpiTransfer(SPIPort *port)
Definition TMC4671.cpp:2559
void errorCallback(const Error &error, bool cleared)
Definition TMC4671.cpp:3162
bool adcCalibrated
Definition TMC4671.h:653
uint8_t enc_retry
Definition TMC4671.h:671
void calibrateAenc()
Definition TMC4671.cpp:1051
bool motorEnabledRequested
Definition TMC4671.h:655
bool manualEncAlign
Definition TMC4671.h:700
uint8_t enc_retry_max
Definition TMC4671.h:672
void setTorqueFilter(TMC4671Biquad_conf &conf)
Definition TMC4671.cpp:2255
void emergencyStop(bool reset)
Definition TMC4671.cpp:1688
uint8_t getGpioPins()
Definition TMC4671.cpp:1808
void turn(int16_t power)
Definition TMC4671.cpp:1732
float getTemp()
Definition TMC4671.cpp:352
std::pair< int32_t, int32_t > getActualTorqueFlux()
Definition TMC4671.cpp:2480
int16_t getPhiE_Enc()
Definition TMC4671.cpp:1155
void setup_HALL(TMC4671HALLConf hallconf)
Definition TMC4671.cpp:1335
TMC_StartupType startupType
Definition TMC4671.h:645
void setTmcPos(int32_t pos)
Definition TMC4671.cpp:1892
uint32_t getEncCpr()
Definition TMC4671.cpp:1581
void setFFMode(FFMode mode)
Definition TMC4671.cpp:1990
void setTargetVelocity(int32_t vel)
Definition TMC4671.cpp:917
void setupFeedForwardTorque(int32_t gain, int32_t constant)
Definition TMC4671.cpp:1977
bool hasPower()
Definition TMC4671.cpp:195
void registerCommands()
Definition TMC4671.cpp:2747
void setPhiEtype(PhiE type)
Definition TMC4671.cpp:1593
void estimateExtEnc()
Definition TMC4671.cpp:2349
TMC4671(SPIPort &spiport, OutputPin cspin, uint8_t address=1)
Definition TMC4671.cpp:49
void setOpenLoopSpeedAccel(int32_t speed, uint32_t accel)
Definition TMC4671.cpp:1627
TMC4671Limits getLimits()
Definition TMC4671.cpp:2156
void restoreFlash() override
Definition TMC4671.cpp:145
void updateReg(uint8_t reg, uint32_t dat, uint32_t mask, uint8_t shift)
Definition TMC4671.cpp:2549
void setup_ABN_Enc(TMC4671ABNConf encconf)
Definition TMC4671.cpp:1294
void setAdcOffset(uint32_t adc_I0_offset, uint32_t adc_I1_offset)
Definition TMC4671.cpp:1961
void setPwmMaxCnt(uint16_t maxcnt)
Definition TMC4671.cpp:2444
bool estopTriggered
Definition TMC4671.h:490
void setCpr(uint32_t cpr)
Definition TMC4671.cpp:1930
void stopMotor()
Definition TMC4671.cpp:1658
const Error communicationError
Definition TMC4671.h:635
void setBiquadTorque(const TMC4671Biquad &filter)
Definition TMC4671.cpp:2234
bool powerInitialized
Definition TMC4671.h:652
void setBiquadFlux(const TMC4671Biquad &filter)
Definition TMC4671.cpp:2171
uint32_t posToEnc(uint32_t pos)
Definition TMC4671.cpp:1948
void Run()
Definition TMC4671.cpp:430
StatusFlags readFlags(bool maskedOnly=true)
Definition TMC4671.cpp:2568
void setUqUdLimit(uint16_t limit)
Definition TMC4671.cpp:2121
std::pair< uint32_t, std::string > getTmcType()
Definition TMC4671.cpp:1825
float getPwmFreq()
Definition TMC4671.cpp:2435
void setAddress(uint8_t address)
Definition TMC4671.cpp:93
void exti(uint16_t GPIO_Pin)
Definition TMC4671.cpp:2618
void initAdc(uint16_t mdecA, uint16_t mdecB, uint32_t mclkA, uint32_t mclkB)
Definition TMC4671.cpp:2463
void setHwType(uint8_t type)
Definition TMC4671.cpp:2713
TMC4671Biquad_conf torqueFilterConf
Definition TMC4671.h:704
void setPosSel(PosSelection psel)
Definition TMC4671.cpp:1763
void setPwmFreq(float freq)
Definition TMC4671.cpp:2455
bool allowStateChange
Definition TMC4671.h:668
void writeRegAsync(uint8_t reg, uint32_t dat)
Definition TMC4671.cpp:2533
int16_t getPhiEfromExternalEncoder()
Definition TMC4671.cpp:939
std::unique_ptr< TMC_ExternalEncoderUpdateThread > extEncUpdater
Definition TMC4671.h:712
void setSvPwm(bool enable)
Definition TMC4671.cpp:2422
void estimateABNparams()
Definition TMC4671.cpp:2296
bool initialize()
Definition TMC4671.cpp:247
bool flagCheckInProgress
Definition TMC4671.h:595
bool initialized
Definition TMC4671.h:651
TMC4671FlashAddrs flashAddrs
Definition TMC4671.h:601
const ClassIdentifier getInfo()
Definition TMC4671.cpp:87
void setFlux(int16_t flux)
Definition TMC4671.cpp:2055
void setPidPrecision(TMC4671PidPrecision setting)
Definition TMC4671.cpp:2132
EncoderType getEncoderType() override
Definition TMC4671.cpp:1952
MotionMode nextMotionMode
Definition TMC4671.h:643
int32_t getVelocity()
Definition TMC4671.cpp:927
uint32_t readReg(uint8_t reg)
Definition TMC4671.cpp:2507
int32_t getActualTorque()
Definition TMC4671.cpp:2499
void setBiquadPos(const TMC4671Biquad &filter)
Definition TMC4671.cpp:2192
void setAdcScale(uint32_t adc_I0_scale, uint32_t adc_I1_scale)
Definition TMC4671.cpp:1969
StatusFlags statusFlags
Definition TMC4671.h:596
bool findEncoderIndex(int32_t speed=10, uint16_t power=2500, bool offsetPhiM=false, bool zeroCount=false)
Definition TMC4671.cpp:828
void setEncoder(std::shared_ptr< Encoder > &encoder) override
Definition TMC4671.cpp:1856
uint32_t encToPos(uint32_t enc)
Definition TMC4671.cpp:1945
void saveAdcParams()
Definition TMC4671.cpp:135
void encoderInit()
Definition TMC4671.cpp:1434
void setPositionExt(int32_t pos)
Definition TMC4671.cpp:931
static TMC4671MotConf decodeMotFromInt(uint16_t val)
Definition TMC4671.cpp:2633
void setTorqueLimit(uint16_t limit)
Definition TMC4671.cpp:2126
OutputPin enablePin
Definition TMC4671.h:632
static ClassIdentifier info
Definition TMC4671.h:18
static bool isCreatable()
Definition TMC4671.cpp:24
static bool isCreatable()
Definition TMC4671.cpp:35
static ClassIdentifier info
Definition TMC4671.h:29
uint32_t WaitForNotification(TickType_t Timeout=portMAX_DELAY)
Definition thread.hpp:246
void Delay(const TickType_t Delay)
Definition thread.hpp:352
Thread(const std::string Name, uint16_t StackDepth, UBaseType_t Priority)
Definition cthread.cpp:56
SPIPort motor_spi
T clip(T v, C l, C h)
Definition cppmain.h:58
static bool inIsr()
Definition cppmain.h:41
bool Flash_Write(uint16_t adr, uint16_t dat)
bool Flash_Read(uint16_t adr, uint16_t *buf, bool checkempty=true)
void pulseClipLed()
void blinkClipLed(uint16_t period, uint16_t blinks)
void pulseErrLed()
static void * memcpy(void *dst, const void *src, size_t n)
Definition ringbuffer.c:8
int16_t phiEoffset
Definition TMC4671.h:278
uint32_t cpr
Definition TMC4671.h:271
bool latch_on_N
Definition TMC4671.h:277
int16_t phiMoffset
Definition TMC4671.h:279
int16_t AENC0_scale
Definition TMC4671.h:293
int16_t phiMoffset
Definition TMC4671.h:290
int16_t nThreshold
Definition TMC4671.h:300
uint16_t AENC0_offset
Definition TMC4671.h:292
int16_t phiEoffset
Definition TMC4671.h:289
int16_t AENC2_scale
Definition TMC4671.h:297
uint32_t cpr
Definition TMC4671.h:286
uint16_t AENC1_offset
Definition TMC4671.h:294
int16_t phiAoffset
Definition TMC4671.h:287
uint16_t AENC2_offset
Definition TMC4671.h:296
int16_t nMask
Definition TMC4671.h:299
int16_t AENC1_scale
Definition TMC4671.h:295
ThermistorSettings thermistorSettings
Definition TMC4671.h:105
uint32_t pid_vel_lim
Definition TMC4671.h:240
uint16_t pid_torque_flux
Definition TMC4671.h:238
uint16_t pid_torque_flux_ddt
Definition TMC4671.h:236
uint32_t pid_acc_lim
Definition TMC4671.h:239
int32_t pid_pos_low
Definition TMC4671.h:241
int32_t pid_pos_high
Definition TMC4671.h:242
uint16_t pid_uq_ud
Definition TMC4671.h:237
MotorType motor_type
Definition TMC4671.h:81
uint16_t pole_pairs
Definition TMC4671.h:84
EncoderType_TMC enctype
Definition TMC4671.h:82
bool sequentialPI
Definition TMC4671.h:232
uint16_t positionP
Definition TMC4671.h:231
uint16_t fluxP
Definition TMC4671.h:225
uint16_t velocityI
Definition TMC4671.h:228
uint16_t positionI
Definition TMC4671.h:230
uint16_t fluxI
Definition TMC4671.h:224
uint16_t velocityP
Definition TMC4671.h:229
uint16_t torqueP
Definition TMC4671.h:227
uint16_t torqueI
Definition TMC4671.h:226
uint32_t asInt
Definition TMC4671.h:197
volatile uint8_t stage
Definition usbh.c:265
int32_t getIntV()
int32_t getExtV()
void setVSenseMult(float vSenseMultiplier)