Open FFBoard
Open source force feedback firmware
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 "stm32f4xx_hal_spi.h"
13#include <math.h>
14#include <assert.h>
15#include "ErrorHandler.h"
16#include "cpp_target_config.h"
17#define MAX_TMC_DRIVERS 3
18
20 .name = "TMC4671 (CS 1)",
21 .id=CLSID_MOT_TMC0, // 1
22};
23
24
27}
28
29
31 .name = "TMC4671 (CS 2)" ,
32 .id=CLSID_MOT_TMC1,
33};
34
35
38}
39
40
41
42
44 .name = "TMC4671" ,
45 .id=CLSID_MOT_TMC0,
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);
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(10e6).first; // 10MHz
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
75
76 this->restoreFlash();
78}
79
80
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
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);
129
130}
131
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;
163 this->abnconf.posOffsetFromIndex = (int16_t)encofs;
164
165 Flash_Read(flashAddrs.offsetFlux, (uint16_t*)&this->maxOffsetFlux);
166
167 // Restore ADC settings
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 }
184 uint16_t filterval;
185 if(Flash_Read(flashAddrs.torqueFilter, &filterval)){
186 torqueFilterConf.params.freq = filterval & 0x1fff;
187 torqueFilterConf.mode = static_cast<TMCbiquadpreset>((filterval >> 13) & 0x7);
188 }
189
190}
191
193 int32_t intV = getIntV();
194 return (intV > 10000) && (getExtV() > 10000) && (intV < 78000);
195}
196
197// Checks if important parameters are set to valid values
199
201 return false;
202 }
203
204 // Encoder
205 if(this->conf.motconf.phiEsource == PhiE::abn && abnconf.cpr == 0){
206 return false;
207 }
208 if(this->conf.motconf.phiEsource == PhiE::abn || this->conf.motconf.phiEsource == PhiE::aenc){
209 if(!encoderAligned){
210 return false;
211 }
212 }
213 if(this->conf.motconf.phiEsource == PhiE::ext && drvEncoder->getEncoderType() == EncoderType::NONE && !encoderAligned){
214 return false;
215 }
216
217 return true;
218}
219
224 writeReg(1, 0);
225 return(readReg(0) == 0x34363731);
226}
227
232 writeReg(0x03, 1); // adc raw data to VM/agpiA
233 uint32_t agpiA_VM = readReg(0x02);
234 agpiA_VM = (agpiA_VM & 0xFFFF) - 0x7FFF - conf.hwconf.adcOffset;
235
236 return ((float)agpiA_VM * conf.hwconf.vmScaler) * 1000;
237}
238
239
245// active = true;
246// if(state == TMC_ControlState::uninitialized){
247// state = TMC_ControlState::Init_wait;
248// }
249 // Check if a TMC4671 is active and replies correctly
250 if(!pingDriver()){
252 return false;
253 }
254
255 writeReg(1, 1);
256 if(readReg(0) == 0x00010000 && allowSlowSPI){
257 /* Slow down SPI if old TMC engineering sample is detected
258 * The first version has a high chance of glitches of the MSB
259 * when high spi speeds are used.
260 * This can cause problems for some operations.
261 */
262 pulseClipLed();
263
264 this->spiConfig.peripheral.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
266 ES_TMCdetected = true;
267 }
268
269 if(!ES_TMCdetected){
271 }
272
273 // Detect if tmc was previously uninitialized
277 }else{
279 }
280 }
281
282 // Write main constants
283
284 writeReg(0x64, 0); // No flux/torque
285 setPwm(0,conf.pwmcnt,conf.bbmL,conf.bbmH); // Set FOC @ 25khz but turn off pwm for now
288 setup_HALL(hallconf); // Enables hall filter and masking
289
294 setBiquadFlux(TMC4671Biquad(Biquad(BiquadType::lowpass, fluxFilterFreq / getPwmFreq(), 0.7,0.0), true)); // Create flux filter
295
296 // Initial adc calibration and check without PWM if power off to get basic offsets. PWM is off!
297 if(!hasPower()){
298 if(!calibrateAdcOffset(150)){
299 changeState(TMC_ControlState::HardError); // ADC or shunt amp is broken!
301 return false;
302 }
303 }
304 // brake res failsafe.
305// /*
306// * Single ended input raw value
307// * 0V = 0x7fff
308// * 4.7k / (360k+4.7k) Divider on old board.
309// * 1.5k / (71.5k+1.5k) 16.121 counts 60V new. 100V VM => 2V
310// * 13106 counts/V input.
311// */
312 setBrakeLimits(this->conf.hwconf.brakeLimLow,this->conf.hwconf.brakeLimHigh); // update limit from previously loaded constants or defaults
313
314 // Status mask
315 if(ES_TMCdetected){
316 setStatusMask(0); // ES Version status output is broken
317 }else{
318 /*
319 * Enable adc clipping and pll errors
320 */
321 statusMask.asInt = 0;
325 }
326
327 setPids(curPids); // Write basic pids
328
329// if(hasPower()){
330// enablePin.set();
331// setPwm(TMC_PwmMode::PWM_FOC);
332// calibrateAdcOffset(400); // Calibrate ADC again with power
333// motorEnabledRequested = true;
334// }
335 //setEncoderType(conf.motconf.enctype);
336
337 // Update flags
338 readFlags(false); // Read all flags
339
340 initialized = true;
341 initTime = HAL_GetTick();
342 return initialized;
343}
344
350 if(!this->conf.hwconf.temperatureEnabled){
351 return 0;
352 }
354
355 writeReg(0x03, 2);
356 int32_t adcval = ((readReg(0x02)) & 0xffff) - 0x7fff; // Center offset
357 adcval -= hwconf->adcOffset;
358 if(adcval <= 0){
359 return 0.0;
360 }
361 float r = hwconf->thermistor_R2 * (((float)43252 / (float)adcval)); //43252 equivalent ADC count if it was 3.3V and not 2.5V
362
363 // Beta
364 r = (1.0 / 298.15) + log(r / hwconf->thermistor_R) / hwconf->thermistor_Beta;
365 r = 1.0 / r;
366 r -= 273.15;
367 return r;
368
369}
370
375 setFluxTorque(0, 0);
376 int32_t total = 0;
377 for(uint8_t i = 0;i<50;i++){
378 std::pair<int32_t,int32_t> ft = getActualTorqueFlux();
379 total += (ft.first+ft.second);
380 Delay(2);
381 }
382 return(abs(total / 50) < 100); // Check if average has a low bias
383}
384
387 return;
388 }
389 powerInitialized = true;
390 // Load ADC settings
392 adcSettingsStored = true; // Previous adc settings restored
394 }
395
397 adcCalibrated = true;
398 }else{
399 if(!calibrateAdcOffset(300)){
400 powerInitialized = false;
401 return; // Abort
402 }
403 }
404
405 // got power long enough. proceed to set up encoder
406 // if encoder not set up
407 enablePin.set();
408 setPwm(TMC_PwmMode::PWM_FOC); // enable foc
409 if(!encoderAligned){
411 }else{
412 //last state
413 if(!emergency){
414 allowStateChange = true;
418 }
419 }
420
421}
422
425}
426
428 // Main state machine
429 while(1){
430
433 }
434
435 // check if we are in a privileged state otherwise use requested state as new state
438 }
439
440 switch(this->state){
441
443 allowStateChange = false;
444 // check communication and write constants
445 if(!pingDriver() || emergency){ // driver not available or emergency was set before startup
446 initialized = false; // Assume driver is not initialized if we can not detect it
447 Delay(250);
448 break;
449 }
450 // Driver available. Write constants and go to next step
451 if(!initialized){
452 initialize();
453 }
455 break;
456
458 {
459 allowStateChange = false;
460 pulseClipLed(); // blink led
461 static uint8_t powerCheckCounter = 0;
462 // if powered check ADCs and go to encoder calibration
463 if(!hasPower() || emergency){
464 powerCheckCounter = 0;
465 Delay(250);
466 break;
467 }
468 if(++powerCheckCounter > 5 && !powerInitialized){
470 }
472 allowStateChange = true;
473 }
474 Delay(100);
475 break;
476 }
477
479 {
481 /*
482 * Wait for power (OK)
483 * Calibrate ADC offsets (OK)
484 * Measure motor response
485 * depending on encoder do encoder parameter estimation
486 * align and store phiE for single phase AENC or indexed ABN enc
487 *
488 * If at any point external movement is detected abort
489 */
490 // Wait for Power
491 while(!hasPower()){
492 Delay(100);
493 }
496 // Calibrate ADC
497 enablePin.set();
498 setPwm(TMC_PwmMode::PWM_FOC); // enable foc to calibrate adc
499 Delay(50);
500 if(calibrateAdcOffset(500)){
502 }else{
503 calibFailCb();
504 break;
505 }
506
507 // Encoder
510 recalibrationRequired = false;
513 break;
514 }
516 {
517 allowStateChange = false;
518 // Wait for Power
519 while(!hasPower()){
520 Delay(100);
521 }
522 pidAutoTune();
523 allowStateChange = true;
524 changeState(laststate,false);
525 break;
526 }
527
529 autohome();
531
532 break;
533
535 {
536 // Check status, Temps, Everything alright?
537 uint32_t tick = HAL_GetTick();
538 if(tick - lastStatTime > 2000){ // Every 2s
539 lastStatTime = tick;
540 statusCheck();
541 // Get enable input. If tmc does not reply the result will read 0 or 0xffffffff (not possible normally)
542 uint32_t pins = readReg(0x76);
543 bool tmc_en = ((pins >> 15) & 0x01) && pins != 0xffffffff;
544 if(!tmc_en && motorEnabledRequested){ // Hardware emergency.
545 this->estopTriggered = true;
546 this->emergencyStop(false);
548 //changeState(TMC_ControlState::HardError);
549 }
550
551 // Temperature sense
553 float temp = getTemp();
556 pulseErrLed();
557 }
558 }
559
560 }
561 Delay(200);
562 }
563 break;
564
566 Delay(100);
567 if(estopTriggered){
568 uint32_t pins = readReg(0x76);
569 bool tmc_en = ((pins >> 15) & 0x01) && pins != 0xffffffff;
570 if(tmc_en){
571 // Emergency stop reset
573 this->estopTriggered = false; // TODO resume correctly
575 }
576 }
577 break;
578
581 encoderInit();
582 break;
583
585 if(powerInitialized && hasPower() && drvEncoder != nullptr)
586 encoderInit();
587 break;
588
590
591 break; // Broken
592
594 this->stopMotor();
596 break;
597
598 case TMC_ControlState::EncoderFinished: // Startup sequence done
599 //setEncoderIndexFlagEnabled(false); // TODO
600// curFilters.flux.params.enable = true;
601// setBiquadFlux(curFilters.flux); // Enable flux filter
602 encoderAligned = true;
604 startMotor();
606 }else{
607 stopMotor();
608 laststate = TMC_ControlState::Running; // Go to running when starting again
609 }
610
613 Flash_Write(flashAddrs.encA,encodeEncHallMisc()); // Save encoder settings
614 }
615
616
617 break;
618
619 default:
620
621 break;
622 }
623
624
625 // Optional update methods for safety
626
627 if(!hasPower() && state != TMC_ControlState::waitPower && initialized && powerInitialized){ // low voltage or overvoltage
628
631 setMotionMode(MotionMode::stop,true); // Disable tmc
633 allowStateChange = false;
634 }
635
636 if(flagCheckInProgress){ // cause some delay until reenabling the status interrupt checking
638 flagCheckInProgress = false;
639 }
640 Delay(10);
641
642 if(emergency && !motorReady()){
643 this->Suspend(); // we can not safely run. wait until resumed by estop
644 }
645 } // End while
646}
647
651 // Report changes
657 }
659
660
661}
662
675 PhiE lastphie = getPhiEtype();
676 MotionMode lastmode = getMotionMode();
678 setPhiEtype(PhiE::ext); // Fixed phase
680 setFluxTorque(0, 0);
681 TMC4671PIDConf newpids = curPids;
682 int16_t targetflux = std::min<int16_t>(this->curLimits.pid_torque_flux,bangInitPower); // Respect limits
683 int16_t targetflux_p = targetflux * 0.75;
684
685 uint16_t fluxI = 0,fluxP = 100; // Startvalues
686 writeReg(0x54, fluxI | (fluxP << 16));
687 int32_t flux = 0;
688 setFluxTorque(targetflux, 0); // Start flux step
689 while(fluxP < 20000){
690 writeReg(0x54, fluxI | (fluxP << 16)); // Update P
691 Delay(50); // Wait a bit. not critical
692 flux = getActualFlux();
693 if(flux > targetflux_p){
694 break;
695 }else if(flux > targetflux * 0.5){
696 // Reduce steps when we are close
697 fluxP+=10;
698 }else{
699 fluxP+=100;
700 }
701 }
702 setFluxTorque(0, 0);
703 Delay(100); // Let the current settle down
704
705 // Tune I. This is more difficult because we need to take overshoot into account
706 uint32_t measuretime = 50; // ms to wait per measurement
707 uint16_t step_i = 64;
708 fluxI = 100;
709 flux = 0;
710 while(fluxI < 20000){
711 writeReg(0x54, fluxI | (fluxP << 16));
712 uint32_t tick = HAL_GetTick();//micros();
713 int32_t peakflux = 0;
714 setFluxTorque(targetflux, 0);
715
716 while(HAL_GetTick() - tick < measuretime){ // Measure current for this pulse
717 flux = getActualFlux();
718 peakflux = std::max<int32_t>(peakflux, flux);
719 }
720 setFluxTorque(0, 0);
721 uint8_t timeout = 100; // Let the current settle down
722 while(timeout-- && flux > 10){
723 Delay(1);
724 flux = getActualFlux();
725 }
726
727 if(peakflux > (targetflux + ( targetflux * 0.03))) // Overshoot target by 3%
728 {
729 fluxI -= step_i; // Revert last step
730 break;
731 }
732 if(peakflux < targetflux*0.95){ // Do larger steps if we don't even reach near the target within the time.
733 step_i = 100;
734 }else{
735 step_i = 10;
736 }
737 fluxI += step_i;
738
739 }
742
743 if(fluxP && fluxP < 20000 && fluxI && fluxI < 20000){
744 newpids.fluxP = fluxP;
745 newpids.torqueP = fluxP;
746 newpids.fluxI = fluxI;
747 newpids.torqueI = fluxI;
748 }else{
750 setPhiEtype(lastphie);
751 setMotionMode(lastmode,true);
752 return false;
753 }
754
755 setPids(newpids); // Apply new values
757 setPhiEtype(lastphie);
758 setMotionMode(lastmode,true);
759 return true;
760}
761
763 // Moves motor to index
764 if(findEncoderIndex(abnconf.posOffsetFromIndex < 0 ? 10 : -10,bangInitPower/2,false,false)){
765 // Load position offset
766 if(abnconf.useIndex)
768 return true;
769 }
770 return false;
771}
772
773/*
774 * Returns the current state of the driver controller
775 */
777 return this->state;
778}
779
780inline void TMC4671::changeState(TMC_ControlState newState,bool force){
781 if(newState != this->state){
782 this->laststate = this->state; // save last state if new state wants to jump back
783 }
784 if(!force){
785 this->requestedState = newState;
786 }else{
787 state = newState;
788 }
789
790}
791
792bool TMC4671::reachedPosition(uint16_t tolerance){
793 int32_t actualPos = readReg(0x6B);
794 int32_t targetPos = readReg(0x68);
795 if( abs(targetPos - actualPos) < tolerance){
796 return true;
797 }else{
798 return false;
799 }
800}
801
802void TMC4671::zeroAbnUsingPhiM(bool offsetPhiE){
803 int32_t npos = (int32_t)readReg(0x28); // raw encoder counts at index hit
804 int32_t npos_M = (npos * 0xffff) / abnconf.cpr; // Scaled encoder angle at index
805 abnconf.phiMoffset = -npos_M;
806 if(offsetPhiE){
808 // change index to zero phiM
809 uint32_t phiEphiM = readReg(0x29);
810 int16_t phiE = ((phiEphiM >> 16) & 0xffff); // Write back phiE offset
811 int16_t phiM = phiEphiM & 0xffff;
812 //updateReg(0x29, abnconf.phiMoffset, 0xffff, 0);
813 writeReg(0x29,(phiE << 16) | phiM);
814 }else{
815 updateReg(0x29, abnconf.phiMoffset, 0xffff, 0);
816 }
817 setTmcPos(getPosAbs()); // Set position to absolute position = ~zero
818}
819
823bool TMC4671::findEncoderIndex(int32_t speed, uint16_t power,bool offsetPhiM,bool zeroCount){
824
826 return false; // Only valid for ABN encoders
827 }
828
829 PhiE lastphie = getPhiEtype();
830 MotionMode lastmode = getMotionMode();
833 setFluxTorque(0, 0);
834// setPhiE_ext(getPhiE());
835// setPhiEtype(PhiE::openloop);
836
837// abnconf.clear_on_N = true;
838// setup_ABN_Enc(abnconf);
839
840 // Arm encoder signal
841 setEncoderIndexFlagEnabled(true,zeroCount);
842 // Rotate
843
844 //uint32_t mposStart = readReg(0x2A);
845 int32_t timeout = 1000; // 10s
846 rampFlux(power, 500);
847 runOpenLoop(power, 0, speed, 10, true);
848 while(!encoderIndexHitFlag && timeout-- > 0){
849 Delay(10);
850 }
851 //int32_t speed = 10;
852 rampFlux(0, 100);
853 runOpenLoop(0, 0, 0, 10, true);
855 pulseErrLed();
857 }
858
859 // 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)
860 if(offsetPhiM){
861 zeroAbnUsingPhiM(false);
862 }
863
864// abnconf.clear_on_N = false;
865// setup_ABN_Enc(abnconf);
868
869 setMotionMode(lastmode,true);
870 setPhiEtype(lastphie);
871 return encoderIndexHitFlag;
872}
873
877void TMC4671::setEncoderIndexFlagEnabled(bool enabled,bool zeroEncoder){
878 //zeroEncoderOnIndexHit = zeroEncoder;
879
880 updateReg(0x25, zeroEncoder ? 1 : 0, 0x1, 9); // Enable encoder clearing
881 if(zeroEncoder){
882 writeReg(0x28,0); // Preload 0 into n register
883 }
884
885 if(enabled)
886 encoderIndexHitFlag = false;
887 setStatusFlags(0); // Reset flags
889 this->statusMask.flags.ENC_N = this->conf.motconf.enctype == EncoderType_TMC::abn && enabled;
890 setStatusMask(statusMask); // Enable flag output for encoder
891}
892
896void TMC4671::setTargetPos(int32_t pos){
900 }
901 writeReg(0x68,pos);
902}
904
905 return readReg(0x68);
906}
907
908
916 }
917 writeReg(0x66,vel);
918}
920 return readReg(0x66);
921}
923 return readReg(0x6A);
924}
925
926void TMC4671::setPositionExt(int32_t pos){
927 writeReg(0x1E, pos);
928}
929
930void TMC4671::setPhiE_ext(int16_t phiE){
931 writeReg(0x1C, phiE);
932}
933
935 int64_t phiE_t = (int64_t)drvEncoder->getPosAbs() * 0xffff;
936 if(this->conf.encoderReversed){
937 phiE_t = -phiE_t;
938 }
939 int32_t phiE = (phiE_t / (int64_t)drvEncoder->getCpr());
940 phiE = (phiE * conf.motconf.pole_pairs) & 0xffff; // scale to pole pairs
941 //int16_t phiE = (drvEncoder->getPosAbs_f() * (float)0xffff) * conf.motconf.pole_pairs + externalEncoderPhieOffset;
942 return(phiE+externalEncoderPhieOffset);
943}
944
945// PhiE is read only
947 return readReg(0x53);
948}
949
950
951
957void TMC4671::bangInitEnc(int16_t power){
958 if(!hasPower() || (this->conf.motconf.motor_type != MotorType::STEPPER && this->conf.motconf.motor_type != MotorType::BLDC)){ // If not stepper or bldc return
959 return;
960 }
961 blinkClipLed(50, 0);
962 PhiE lastphie = getPhiEtype();
963 MotionMode lastmode = getMotionMode();
964 setFluxTorque(0, 0);
965
966 uint8_t phiEoffsetReg = 0;
968 phiEoffsetReg = 0x29;
972 writeReg(0x41,0); //Zero encoder
973 writeReg(0x47,0); //Zero encoder
974 phiEoffsetReg = 0x45;
975 }else if (usingExternalEncoder()){
977 }else{
978 return; // Not relevant
979 }
980
981 //setTmcPos(0);
982
983 //setMotionMode(MotionMode::uqudext);
984
985 //Delay(100);
986 int16_t phiEpos = getPhiE();// readReg(phiEreg)>>16; // starts at current encoder position
987 updateReg(phiEoffsetReg, 0, 0xffff, 16); // Set phiE offset to zero
988 setPhiE_ext(phiEpos);
990 // Ramp up flux
991 rampFlux(power, 1000);
992 int16_t phiE_enc = getPhiE_Enc();
993
994 Delay(50);
995 int16_t phiE_abn_old = 0;
996 int16_t c = 0;
997 uint16_t still = 0;
998 while(still < 30 && c++ < 1000){
999 // Wait for motor to stop moving
1000 if(abs(phiE_enc - phiE_abn_old) < 100){
1001 still++;
1002 }else{
1003 still = 0;
1004 }
1005 phiE_abn_old = phiE_enc;
1006
1007 phiE_enc = getPhiE_Enc();
1008
1009 //phiE_enc=readReg(phiEreg)>>16;
1010 Delay(10);
1011 }
1012 rampFlux(0, 100);
1013
1014 //Write offset
1015 //int16_t phiE_abn = readReg(0x2A)>>16;
1016 int16_t phiEoffset = phiEpos-phiE_enc;
1017
1018 if(phiEoffset == 0){ // 0 invalid
1019 phiEoffset = 1;
1020 }
1021 if (usingExternalEncoder()){
1022 externalEncoderPhieOffset = phiEoffset;
1023 }else{
1024 updateReg(phiEoffsetReg, phiEoffset, 0xffff, 16);
1025 }
1026
1028 abnconf.phiEoffset = phiEoffset;
1030 aencconf.phiEoffset = phiEoffset;
1031 }
1032
1033
1034 setPhiE_ext(0);
1035 setPhiEtype(lastphie);
1036 setMotionMode(lastmode,true);
1037 //setTmcPos(pos+getPos());
1038 //setTmcPos(0);
1039
1040 blinkClipLed(0, 0);
1041}
1042
1047
1048 // Rotate and measure min/max
1049 blinkClipLed(250, 0);
1050 PhiE lastphie = getPhiEtype();
1051 MotionMode lastmode = getMotionMode();
1052 //int32_t pos = getPos();
1053 PosSelection possel = this->conf.motconf.pos_sel;
1055 setTmcPos(0);
1056 // Ramp up flux
1057 setFluxTorque(0, 0);
1058 writeReg(0x23,0); // set phie openloop 0
1061
1062 if(this->conf.motconf.motor_type == MotorType::STEPPER || this->conf.motconf.motor_type == MotorType::BLDC){
1063 rampFlux(bangInitPower, 250);
1064 }
1065 uint32_t minVal_0 = 0xffff, minVal_1 = 0xffff, minVal_2 = 0xffff;
1066 uint32_t maxVal_0 = 0, maxVal_1 = 0, maxVal_2 = 0;
1067 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));
1068 uint32_t speed = std::max<uint32_t>(1,20/std::max<uint32_t>(1,this->aencconf.cpr/10));
1069
1070 if(this->conf.motconf.motor_type != MotorType::STEPPER && this->conf.motconf.motor_type != MotorType::BLDC){
1071 speed*=10; // dc motors turn at a random speed. reduce the rotation time a bit by increasing openloop speed
1072 }
1073
1074 runOpenLoop(bangInitPower, 0, speed, 100,true);
1075
1076 uint8_t stage = 0;
1077 int32_t poles = conf.motconf.pole_pairs;
1078 int32_t initialDirPos = 0;
1079 while(stage != 3){
1080 Delay(2);
1081 if(getPos() > maxpos*poles && stage == 0){
1082 runOpenLoop(bangInitPower, 0, -speed, 100,true);
1083 stage = 1;
1084 }else if(getPos() < minpos*poles && stage == 1){
1085 // Scale might still be wrong... maxVal-minVal is too high. In theory its 0xffff range and scaler /256. Leave some room to prevent clipping
1086 aencconf.AENC0_offset = ((maxVal_0 + minVal_0) / 2);
1087 aencconf.AENC0_scale = 0xF6FF00 / (maxVal_0 - minVal_0);
1089 aencconf.AENC1_offset = ((maxVal_1 + minVal_1) / 2);
1090 aencconf.AENC1_scale = 0xF6FF00 / (maxVal_1 - minVal_1);
1091 }
1092
1093 aencconf.AENC2_offset = ((maxVal_2 + minVal_2) / 2);
1094 aencconf.AENC2_scale = 0xF6FF00 / (maxVal_2 - minVal_2);
1095 aencconf.rdir = false;
1097 rampFlux(0, 100);
1098 runOpenLoop(0, 0, 0, 1000,true);
1099 Delay(250);
1100 // Zero aenc
1101 writeReg(0x41, 0);
1102 initialDirPos = readReg(0x41);
1103 runOpenLoop(bangInitPower, 0, speed, 100,true);
1104 stage = 2;
1105 }else if(getPos() > 0 && stage == 2){
1106 stage = 3;
1107 rampFlux(0, 100);
1108 runOpenLoop(0, 0, 0, 1000,true);
1109 }
1110
1111 writeReg(0x03,2);
1112 uint32_t aencUX = readReg(0x02)>>16;
1113 writeReg(0x03,3);
1114 uint32_t aencWY_VN = readReg(0x02) ;
1115 uint32_t aencWY = aencWY_VN >> 16;
1116 uint32_t aencVN = aencWY_VN & 0xffff;
1117
1118 minVal_0 = std::min(minVal_0,aencUX);
1119 minVal_1 = std::min(minVal_1,aencVN);
1120 minVal_2 = std::min(minVal_2,aencWY);
1121
1122 maxVal_0 = std::max(maxVal_0,aencUX);
1123 maxVal_1 = std::max(maxVal_1,aencVN);
1124 maxVal_2 = std::max(maxVal_2,aencWY);
1125 }
1126 // Scale is not actually important. but offset must be perfect
1127 aencconf.AENC0_offset = ((maxVal_0 + minVal_0) / 2);
1128 aencconf.AENC0_scale = 0xF6FF00 / (maxVal_0 - minVal_0);
1130 aencconf.AENC1_offset = ((maxVal_1 + minVal_1) / 2);
1131 aencconf.AENC1_scale = 0xF6FF00 / (maxVal_1 - minVal_1);
1132 }
1133 aencconf.AENC2_offset = ((maxVal_2 + minVal_2) / 2);
1134 aencconf.AENC2_scale = 0xF6FF00 / (maxVal_2 - minVal_2);
1135 int32_t newDirPos = readReg(0x41);
1136 aencconf.rdir = (initialDirPos - newDirPos) > 0;
1138 // Restore settings
1139 setPhiEtype(lastphie);
1140 setMotionMode(lastmode,true);
1141 setPosSel(possel);
1142 setTmcPos(0);
1143
1144 blinkClipLed(0, 0);
1145}
1146
1152 return (int16_t)(readReg(0x2A)>>16);
1154 return (int16_t)(readReg(0x46)>>16);
1156 return (int16_t)(readReg(0x39)>>16);
1157 }else if(usingExternalEncoder()){
1159 }else{
1160 return getPhiE();
1161 }
1162}
1163
1168 if(this->conf.motconf.motor_type != MotorType::STEPPER && this->conf.motconf.motor_type != MotorType::BLDC &&
1170 { // If not stepper or bldc return
1171 return true;
1172 }
1173 blinkClipLed(150, 0);
1174
1175 const uint16_t maxcount = 50; // Allowed reversals
1176 const uint16_t maxfail = 10; // Allowed fails
1177 const int16_t startAngle = getPhiE_Enc(); // Start angle offsets all angles later so there is no jump if angle is already properly aligned
1178 const int16_t targetAngle = 0x3FFF;
1179
1180 bool result = true;
1181 PhiE lastphie = getPhiEtype();
1182 MotionMode lastmode = getMotionMode();
1183 setFluxTorque(0, 0);
1185
1186 setPhiE_ext(startAngle);
1187 // Ramp up flux
1188 rampFlux(2*bangInitPower/3, 250);
1189
1190 //Forward
1191 int16_t phiE_enc = 0;
1192 uint16_t failcount = 0;
1193 int16_t revCount = 0;
1194 for(int16_t angle = 0;angle<targetAngle;angle+=0x00ff){
1195 uint16_t c = 0;
1196 setPhiE_ext(angle+startAngle);
1197 Delay(5);
1198 phiE_enc = getPhiE_Enc() - startAngle;
1199 int16_t err = abs(phiE_enc - angle);
1200 int16_t nErr = abs(phiE_enc + angle);
1201 // Wait more until encoder settles a bit
1202 while(err > 2000 && nErr > 2000 && c++ < 50){
1203 phiE_enc = getPhiE_Enc() - startAngle;
1204 err = abs(phiE_enc - angle);
1205 nErr = abs(angle - phiE_enc);
1206 Delay(10);
1207 }
1208 if(err > nErr){
1209 revCount++;
1210 }
1211 if(c >= maxcount){
1212 failcount++;
1213 if(failcount > maxfail){
1214 result = false;
1215 break;
1216 }
1217 }
1218 }
1219 /* If we are still at the start angle the encoder did not move at all.
1220 * Possible issues:
1221 * Encoder connection wrong
1222 * Wrong encoder selection
1223 * No motor movement
1224 * No encoder power
1225 */
1226 if(startAngle == getPhiE_Enc()){
1229 result = false;
1230 }
1231
1232 // Backward
1233
1234 if(result){ // Only if not already failed
1235 for(int16_t angle = targetAngle;angle>0;angle -= 0x00ff){
1236 uint16_t c = 0;
1237 setPhiE_ext(angle+startAngle);
1238 Delay(5);
1239 phiE_enc = getPhiE_Enc() - startAngle;
1240 int16_t err = abs(phiE_enc - angle);
1241 int16_t nErr = abs(phiE_enc + angle);
1242 // Wait more
1243 while(err > 2500 && nErr > 2500 && c++ < 50){
1244 phiE_enc = getPhiE_Enc() - startAngle;
1245 err = abs(phiE_enc - angle);
1246 nErr = abs(angle - phiE_enc);
1247 Delay(10);
1248 }
1249 if(err > nErr){
1250 revCount++;
1251 }
1252 if(c >= maxcount){
1253 failcount++;
1254 if(failcount > maxfail){
1255 result = false;
1256 break;
1257 }
1258 }
1259 }
1260 }
1261
1262 // TODO check if we want that
1263 if(revCount > maxcount){ // Encoder seems reversed
1264 // reverse encoder
1266 this->abnconf.rdir = !this->abnconf.rdir;
1268 }else if(this->conf.motconf.enctype == EncoderType_TMC::sincos || this->conf.motconf.enctype == EncoderType_TMC::uvw){
1269 this->aencconf.rdir = !this->aencconf.rdir;
1271 }else if(this->conf.motconf.enctype == EncoderType_TMC::ext){
1273 }
1274 ErrorHandler::addError(Error(ErrorCode::encoderReversed,ErrorType::warning,"Encoder direction reversed during check"));
1275 }
1276
1277 rampFlux(0, 100);
1278 setPhiE_ext(0);
1279 setPhiEtype(lastphie);
1280 setMotionMode(lastmode,true);
1281
1282 if(result){
1283 encoderAligned = true;
1284 }
1285 blinkClipLed(0, 0);
1286 return result;
1287}
1288
1290 this->abnconf = encconf;
1291 this->conf.encoderReversed = encconf.rdir;
1292 uint32_t abnmode =
1293 (encconf.apol |
1294 (encconf.bpol << 1) |
1295 (encconf.npol << 2) |
1296 (encconf.ab_as_n << 3) |
1297 (encconf.latch_on_N << 8) |
1298 (encconf.rdir << 12));
1299
1300 writeReg(0x25, abnmode);
1301 //int32_t pos = getPos();
1302 writeReg(0x26, encconf.cpr);
1303 writeReg(0x29, ((uint16_t)encconf.phiEoffset << 16) | (uint16_t)encconf.phiMoffset);
1304 //setTmcPos(pos);
1305 //writeReg(0x27,0); //Zero encoder
1306 //conf.motconf.phiEsource = PhiE::abn;
1307 if(encconf.useIndex){
1308 encoderIndexHitFlag = false; // Reset flag
1309 }
1310
1311
1312}
1314 this->conf.encoderReversed = encconf.rdir;
1315 // offsets
1316 writeReg(0x0D,encconf.AENC0_offset | ((uint16_t)encconf.AENC0_scale << 16));
1317 writeReg(0x0E,encconf.AENC1_offset | ((uint16_t)encconf.AENC1_scale << 16));
1318 writeReg(0x0F,encconf.AENC2_offset | ((uint16_t)encconf.AENC2_scale << 16));
1319
1320 writeReg(0x40,encconf.cpr);
1321 writeReg(0x3e,(uint16_t)encconf.phiAoffset);
1322 writeReg(0x45,(uint16_t)encconf.phiEoffset | ((uint16_t)encconf.phiMoffset << 16));
1323 writeReg(0x3c,(uint16_t)encconf.nThreshold | ((uint16_t)encconf.nMask << 16));
1324
1325 uint32_t mode = encconf.uvwmode & 0x1;
1326 mode |= (encconf.rdir & 0x1) << 12;
1327 writeReg(0x3b, mode);
1328
1329}
1331 this->hallconf = hallconf;
1332
1333 uint32_t hallmode =
1335 hallconf.filter << 4 |
1336 hallconf.interpolation << 8 |
1337 hallconf.direction << 12 |
1338 (hallconf.blank & 0xfff) << 16;
1339 writeReg(0x33, hallmode);
1340 // Positions
1341 uint32_t posA = (uint16_t)hallconf.pos0 | (uint16_t)hallconf.pos60 << 16;
1342 writeReg(0x34, posA);
1343 uint32_t posB = (uint16_t)hallconf.pos120 | (uint16_t)hallconf.pos180 << 16;
1344 writeReg(0x35, posB);
1345 uint32_t posC = (uint16_t)hallconf.pos240 | (uint16_t)hallconf.pos300 << 16;
1346 writeReg(0x36, posC);
1347
1348 uint32_t phiOffsets = (uint16_t)hallconf.phiMoffset | (uint16_t)hallconf.phiEoffset << 16;
1349 writeReg(0x37, phiOffsets);
1350 writeReg(0x38, hallconf.dPhiMax);
1351
1352 //conf.motconf.phiEsource = PhiE::hall;
1353}
1354
1355
1360
1361 uint16_t measuretime_idle = time;
1362 uint32_t measurements_idle = 0;
1363 uint64_t totalA=0;
1364 uint64_t totalB=0;
1365 bool allowTemp = conf.hwconf.temperatureEnabled;
1366 conf.hwconf.temperatureEnabled = false; // Temp check interrupts adc
1367 writeReg(0x03, 0); // Read raw adc
1368 PhiE lastphie = getPhiEtype();
1369 MotionMode lastmode = getMotionMode();
1371 Delay(100); // Wait a bit before sampling
1372 uint16_t lastrawA=conf.adc_I0_offset, lastrawB=conf.adc_I1_offset;
1373
1374 //pulseClipLed(); // Turn on led
1375 // Disable drivers and measure many samples of zero current
1376 //enablePin.reset();
1377 uint32_t tick = HAL_GetTick();
1378 while(HAL_GetTick() - tick < measuretime_idle){ // Measure idle
1379 writeReg(0x03, 0); // Read raw adc
1380 uint32_t adcraw = readReg(0x02);
1381 uint16_t rawA = adcraw & 0xffff;
1382 uint16_t rawB = (adcraw >> 16) & 0xffff;
1383 // Signflip filter for SPI bug
1384 if(abs(lastrawA-rawA) < 10000 && abs(lastrawB-rawB) < 10000){
1385 totalA += rawA;
1386 totalB += rawB;
1387 measurements_idle++;
1388 lastrawA = rawA;
1389 lastrawB = rawB;
1390 }
1391// uint32_t lastMicros = micros();
1392// while(micros()-lastMicros < 100){} // Wait 100µs at least
1393 }
1394 //enablePin.set();
1395 int32_t offsetAidle = totalA / (measurements_idle);
1396 int32_t offsetBidle = totalB / (measurements_idle);
1397
1398 // Check if offsets are in a valid range
1399 if(totalA < 100 || totalB < 100 || ((abs(offsetAidle - 0x7fff) > TMC_ADCOFFSETFAIL) || (abs(offsetBidle - 0x7fff) > TMC_ADCOFFSETFAIL)) ){
1401// blinkErrLed(100, 0); // Blink forever
1402// setPwm(TMC_PwmMode::off); //Disable pwm
1403// this->changeState(TMC_ControlState::HardError);
1404 adcCalibrated = false;
1405 conf.hwconf.temperatureEnabled = allowTemp;
1406 return false; // An adc or shunt amp is likely broken. do not proceed.
1407 }
1408 conf.adc_I0_offset = offsetAidle;
1409 conf.adc_I1_offset = offsetBidle;
1411 // ADC Offsets should now be close to perfect
1412
1413 setPhiEtype(lastphie);
1414 setMotionMode(lastmode,true);
1415 adcCalibrated = true;
1416 conf.hwconf.temperatureEnabled = allowTemp;
1417 return true;
1418}
1419
1421 if(calibrationFailCount-- != 0){
1423 }else{
1424 Error err = Error(ErrorCode::tmcCalibFail,ErrorType::critical,"TMC calibration failed");
1427 }
1428}
1430
1431 if(!powerInitialized || !hasPower()){
1434 return;
1435 }
1436
1437 // Initializes encoder
1439 setPosSel(PosSelection::PhiM_abn); // Mechanical Angle
1440 setVelSel(VelSelection::PhiM_abn); // Mechanical Angle (RPM)
1441 //setup_ABN_Enc(abnconf);
1442 if(!encHallRestored){
1443 estimateABNparams(); // If not saved try to estimate parameters
1444 recalibrationRequired = true;
1445 }
1447 setPosSel(PosSelection::PhiM_aenc); // Mechanical Angle
1448 setVelSel(VelSelection::PhiM_aenc); // Mechanical Angle (RPM)
1449 //setup_AENC(aencconf);
1450 calibrateAenc();
1451 }
1452
1453 // find index
1454
1455 if(conf.motconf.enctype == EncoderType_TMC::abn && abnconf.useIndex && !encoderIndexHitFlag){ // TODO changing direction might invalidate phiE offset because of index pulse width
1456 findEncoderIndex(abnconf.posOffsetFromIndex < 0 ? 10 : -10,bangInitPower/2,true,true); // Go to index and zero encoder
1457 setPhiEtype(PhiE::openloop); // Openloop used in last step. Use for aligning too
1458 }else{
1461 }
1462
1463 // Align encoder
1464 // TODO handle absolute external encoders
1466
1467 // Check encoder
1468 if(!checkEncoder()){
1469 if(++enc_retry > enc_retry_max){
1470 encoderAligned = false;
1473 stopMotor();
1474 allowStateChange = false;
1476 }
1477
1478 if(manualEncAlign){
1479 manualEncAlign = false;
1481 }
1482 return;
1483 }
1484 encoderAligned = true;
1485
1486
1487
1489 setTmcPos(getPosAbs() - abnconf.posOffsetFromIndex); // Load stored position
1490
1491 if(manualEncAlign){
1492 manualEncAlign = false;
1494 }
1496
1501 }else if(usingExternalEncoder()){
1502// setPosSel(PosSelection::PhiE_ext);
1503// setVelSel(VelSelection::PhiE_ext); // Mechanical Angle (RPM)
1505 }
1506
1507}
1508
1514 // If no external timer is set external encoder is not valid
1516 type = EncoderType_TMC::NONE;
1517 }
1518 this->conf.motconf.enctype = type;
1519 this->statusMask.flags.AENC_N = 0;
1520 this->statusMask.flags.ENC_N = 0;
1521 //encoderIndexHitFlag = false;
1523 encoderAligned = false;
1524
1527
1528 if(type == EncoderType_TMC::abn){
1529 encoderAligned = false;
1530 // Not initialized if cpr not set
1531 if(this->abnconf.cpr == 0){
1532 return;
1533 }
1535
1537
1538 // SinCos encoder
1539 }else if(type == EncoderType_TMC::sincos){
1540 encoderAligned = false;
1542 this->aencconf.uvwmode = false; // sincos mode
1544
1545 // Analog UVW encoder
1546 }else if(type == EncoderType_TMC::uvw){
1547 encoderAligned = false;
1549 this->aencconf.uvwmode = true; // uvw mode
1551
1552 }else if(type == EncoderType_TMC::hall){ // Hall sensor. Just trust it
1556 encoderAligned = true;
1559
1560 }else if(type == EncoderType_TMC::ext && drvEncoder && drvEncoder->getEncoderType() != EncoderType::NONE){
1561 // TODO check different encoder type
1562 encoderAligned = false;
1564 //changeState(TMC_ControlState::Shutdown);
1566 }else{
1568 encoderAligned = true;
1569 }
1570
1571}
1572
1575 if(type == EncoderType_TMC::abn || type == EncoderType_TMC::NONE){
1576 return abnconf.cpr;
1577 }else if(type == EncoderType_TMC::sincos || type == EncoderType_TMC::uvw){
1578 return aencconf.cpr;
1579 }
1580 else{
1581 return getCpr();
1582 }
1583}
1584
1586 conf.motconf.phiEsource = type;
1587
1588 // External encoder is phiE ext but enables constant phiE updates too
1589 if(type == PhiE::extEncoder){
1590 type = PhiE::ext;
1591 }
1592
1593 writeReg(0x52, (uint8_t)type & 0xff);
1594}
1596 PhiE phie = PhiE(readReg(0x52) & 0x7);
1598 return PhiE::extEncoder;
1599 }
1600 return phie;
1601}
1602
1603void TMC4671::setMotionMode(MotionMode mode, bool force){
1604 if(!force){
1605 nextMotionMode = mode;
1606 return;
1607 }
1608 if(mode != curMotionMode){
1610 }
1611 curMotionMode = mode;
1612 updateReg(0x63, (uint8_t)mode, 0xff, 0);
1613}
1615 curMotionMode = MotionMode(readReg(0x63) & 0xff);
1616 return curMotionMode;
1617}
1618
1619void TMC4671::setOpenLoopSpeedAccel(int32_t speed,uint32_t accel){
1620 writeReg(0x21, speed);
1621 writeReg(0x20, accel);
1622}
1623
1624
1625void TMC4671::runOpenLoop(uint16_t ud,uint16_t uq,int32_t speed,int32_t accel,bool torqueMode){
1626 if(this->conf.motconf.motor_type == MotorType::DC){
1627 uq = ud+uq; // dc motor has no flux. add to torque
1628 }
1629 startMotor();
1630 if(torqueMode){
1631 if(this->conf.motconf.motor_type == MotorType::DC){
1632 uq = ud+uq; // dc motor has no flux. add to torque
1633 }
1634 setFluxTorque(ud, uq);
1635 }else{
1637 setUdUq(ud,uq);
1638 }
1639 int16_t oldPhiE = getPhiE();
1641 writeReg(0x23,oldPhiE); // Start running at last phiE value
1642
1643 setOpenLoopSpeedAccel(speed, accel);
1644}
1645
1646void TMC4671::setUdUq(int16_t ud,int16_t uq){
1647 writeReg(0x24, ud | (uq << 16));
1648}
1649
1651 // Stop driver if running
1652
1653// enablePin.reset();
1654 motorEnabledRequested = false;
1657 setPwm(TMC_PwmMode::off); // disable foc
1659 }
1660}
1662 motorEnabledRequested = true;
1663
1666 }
1667 // Start driver if powered and emergency flag reset
1668 if(hasPower() && !emergency){
1669 setPwm(TMC_PwmMode::PWM_FOC); // enable foc
1670 enablePin.set();
1672
1673 }
1674 else{
1676 }
1677
1678}
1679
1680void TMC4671::emergencyStop(bool reset){
1681 if(!reset){
1682// setPwm(TMC_PwmMode::HSlow_LShigh); // Short low side for instant stop
1683 emergency = true;
1684 enablePin.reset(); // Release enable pin to disable the whole driver
1685 motorEnabledRequested = false;
1686 this->stopMotor();
1687
1688 }else{
1689// enablePin.set();
1690// writeReg(0x64, 0); // Set flux and torque 0 directly. Make sure motor does not jump
1691// setPwm(TMC_PwmMode::PWM_FOC);
1692 emergency = false;
1693 motorEnabledRequested = true;
1694 //this->changeState(TMC_ControlState::waitPower, true); // Reinit
1695 this->startMotor();
1696 if(!motorReady()){
1697 if(inIsr()){
1698 ResumeFromISR();
1699 }else{
1700 Resume();
1701 }
1702 }
1703 }
1704}
1705
1711
1712 int32_t vDiff = getIntV() - getExtV();
1713 if(vDiff > fluxDissipationLimit){
1714 // Reaches limit at +5v if scaler is 1
1715 return(clip<int32_t,int32_t>(vDiff * conf.hwconf.fluxDissipationScaler * curLimits.pid_torque_flux * 0.0002,0,curLimits.pid_torque_flux));
1716 }
1717 return 0;
1718}
1719
1724void TMC4671::turn(int16_t power){
1725 if(!(this->motorReady() && motorEnabledRequested))
1726 return;
1727 int32_t flux = 0;
1728
1729 // Flux offset for field weakening
1730
1731 flux = idleFlux-clip<int32_t,int16_t>(abs(power),0,maxOffsetFlux);
1733 power = -power; // Encoder does not match
1734 }
1735
1736 /*
1737 * If flux dissipation is on prefer this over the resistor.
1738 * Warning: The axis only calls this function when active and if torque changed.
1739 * It may not update during sustained force and still cause overvoltage conditions.
1740 * TODO periodically check and update if driver is on but no torque update is sent
1741 */
1743 int16_t dissipationFlux = controlFluxDissipate();
1744 if(dissipationFlux != 0){
1745 flux = dissipationFlux;
1746 }
1747 }
1748
1749 setFluxTorque(flux, power);
1750}
1751
1756 writeReg(0x51, (uint8_t)psel);
1757 this->conf.motconf.pos_sel = psel;
1758}
1759
1764void TMC4671::setVelSel(VelSelection vsel,uint8_t mode){
1765 uint32_t vselMode = ((uint8_t)vsel & 0xff) | ((mode & 0xff) << 8);
1766 writeReg(0x50, vselMode);
1767 this->conf.motconf.vel_sel = vsel;
1768}
1769
1775 uint8_t modeReg = 0;
1776 switch(mode){
1777 default:
1779 modeReg = 0; break;
1781 modeReg = 0b1100111; break;
1783 modeReg = 0b0000111; break;
1785 modeReg = 0b0000001; break;
1787 modeReg = 0b0010001; break;
1789 modeReg = 0b0001001; break;
1791 modeReg = 0b0011001; break;
1792 }
1793
1794 updateReg(0x7B, modeReg,0xff,0);
1795}
1796
1801 return readReg(0x7B) >> 24;
1802}
1803
1808void TMC4671::setGpioPins(uint8_t pins){
1809 uint32_t reg = pins << 16;
1810 updateReg(0x7B, reg,0xff,16);
1811}
1812
1813
1817std::pair<uint32_t,std::string> TMC4671::getTmcType(){
1818
1819 std::string reply = "";
1820 writeReg(1, 0);
1821 uint32_t nameInt = readReg(0);
1822 if(nameInt == 0 || nameInt == 0xffffffff){
1823 reply = "No driver connected";
1824 return std::pair<uint32_t,std::string>(0,reply);
1825 }
1826
1827 nameInt = __REV(nameInt);
1828 char* name = reinterpret_cast<char*>(&nameInt);
1829 std::string namestring = std::string(name,sizeof(nameInt));
1830
1831 writeReg(1, 1);
1832 uint32_t versionInt = readReg(0);
1833
1834 std::string versionstring = std::to_string((versionInt >> 16) && 0xffff) + "." + std::to_string((versionInt) && 0xffff);
1835
1836 reply += "TMC" + namestring + " v" + versionstring;
1837 return std::pair<uint32_t,std::string>(versionInt,reply);
1838}
1839
1842 return MotorDriver::drvEncoder.get();
1843 }else{
1844 return static_cast<Encoder*>(this);
1845 }
1846}
1847
1848void TMC4671::setEncoder(std::shared_ptr<Encoder>& encoder){
1849 MotorDriver::drvEncoder = encoder;
1851 // TODO Calibrate and align external encoder
1853 }
1854}
1855
1857 // Use internal encoder if not external encoder is selected
1859}
1860
1864void TMC4671::setPos(int32_t pos){
1866
1867 int32_t tmcpos = readReg(0x6B); // Current Position
1868 int32_t offset = (tmcpos - pos) % 0xffff; // Difference between current position and target
1869
1870// setup_ABN_Enc(abnconf);
1873 }else{
1874 setTmcPos(pos);
1875 }
1876
1877}
1878
1882void TMC4671::setTmcPos(int32_t pos){
1883
1884 writeReg(0x6B, pos);
1885}
1886
1888
1889 int32_t pos = (int32_t)readReg(0x6B);
1890 return pos;
1891}
1892
1894 int16_t pos;
1896 pos = (int16_t)readReg(0x2A) & 0xffff; // read phiM
1897 }else if(this->conf.motconf.enctype == EncoderType_TMC::hall){
1898 pos = (int16_t)readReg(0x3A); // read phiM
1899 }else if(this->conf.motconf.enctype == EncoderType_TMC::sincos || this->conf.motconf.enctype == EncoderType_TMC::uvw){
1900 pos = (int16_t)readReg(0x46) & 0xffff; // read phiM
1901 }else{
1902 pos = getPos(); // read phiM
1903 }
1904
1905 return pos;
1906}
1907
1908
1910// if(this->conf.motconf.phiEsource == PhiE::abn){
1911// return abnconf.cpr;
1912// }else{
1914 return drvEncoder->getCpr();
1915 }
1916 return 0xffff;
1917// }
1918
1919}
1920void TMC4671::setCpr(uint32_t cpr){
1921 if(cpr == 0)
1922 cpr = 1;
1923
1924
1925 this->abnconf.cpr = cpr;
1926 this->aencconf.cpr = cpr;
1927 writeReg(0x26, abnconf.cpr); //ABN
1928 writeReg(0x40, aencconf.cpr); //AENC
1929
1930}
1931
1935uint32_t TMC4671::encToPos(uint32_t enc){
1936 return enc*(0xffff / abnconf.cpr); //*(conf.motconf.pole_pairs)
1937}
1938uint32_t TMC4671::posToEnc(uint32_t pos){
1939 return pos/((0xffff / abnconf.cpr)) % abnconf.cpr; //(conf.motconf.pole_pairs)
1940}
1941
1945 }
1947}
1948
1949
1950
1951void TMC4671::setAdcOffset(uint32_t adc_I0_offset,uint32_t adc_I1_offset){
1952 conf.adc_I0_offset = adc_I0_offset;
1953 conf.adc_I1_offset = adc_I1_offset;
1954
1955 updateReg(0x09, adc_I0_offset, 0xffff, 0);
1956 updateReg(0x08, adc_I1_offset, 0xffff, 0);
1957}
1958
1959void TMC4671::setAdcScale(uint32_t adc_I0_scale,uint32_t adc_I1_scale){
1960 conf.adc_I0_scale = adc_I0_scale;
1961 conf.adc_I1_scale = adc_I1_scale;
1962
1963 updateReg(0x09, adc_I0_scale, 0xffff, 16);
1964 updateReg(0x08, adc_I1_scale, 0xffff, 16);
1965}
1966
1967void TMC4671::setupFeedForwardTorque(int32_t gain, int32_t constant){
1968 writeReg(0x4E, 42);
1969 writeReg(0x4D, gain);
1970 writeReg(0x4E, 43);
1971 writeReg(0x4D, constant);
1972}
1973void TMC4671::setupFeedForwardVelocity(int32_t gain, int32_t constant){
1974 writeReg(0x4E, 40);
1975 writeReg(0x4D, gain);
1976 writeReg(0x4E, 41);
1977 writeReg(0x4D, constant);
1978}
1979
1981 updateReg(0x63, (uint8_t)mode, 0xff, 16);
1982 if(mode!=FFMode::none){
1983
1984 setSequentialPI(true);
1985 }
1986}
1987
1988void TMC4671::setSequentialPI(bool sequential){
1989 curPids.sequentialPI = sequential;
1990 updateReg(0x63, sequential ? 1 : 0, 0x1, 31);
1991}
1992
1994#ifndef TIM_TMC
1995 allowExternalEncoder = false;
1996#else
1997 bool lastAllowed = allowExternalEncoder;
1998 allowExternalEncoder = allow;
1999 // External encoder was previously used but now not allowed anymore. Change to none type encoder
2000 if(!allow && lastAllowed && conf.motconf.enctype == EncoderType_TMC::ext){
2001 setEncoderType(EncoderType_TMC::NONE); // Reinit encoder
2002 }
2003#endif
2004}
2005
2007#ifndef TIM_TMC
2008 return false;
2009#else
2010 return allowExternalEncoder;
2011#endif
2012}
2013
2014void TMC4671::setMotorType(MotorType motor,uint16_t poles){
2015 if(motor == MotorType::DC){
2016 poles = 1;
2017 }
2018 conf.motconf.motor_type = motor;
2019 conf.motconf.pole_pairs = poles;
2020 uint32_t mtype = poles | ( ((uint8_t)motor&0xff) << 16);
2021// if(motor != MotorType::STEPPER){
2022// maxOffsetFlux = 0; // Offsetflux only helpful for steppers. Has no effect otherwise
2023// }
2024 writeReg(0x1B, mtype);
2025 if(motor == MotorType::BLDC && !ES_TMCdetected){
2026 setSvPwm(conf.motconf.svpwm); // Higher speed for BLDC motors. Not available in engineering samples
2027 }
2028}
2029
2030void TMC4671::setTorque(int16_t torque){
2033 }
2034 updateReg(0x64,torque,0xffff,16);
2035}
2037 return readReg(0x64) >> 16;
2038}
2039
2040void TMC4671::setFlux(int16_t flux){
2043 }
2044 updateReg(0x64,flux,0xffff,0);
2045}
2047 return readReg(0x64) && 0xffff;
2048}
2049void TMC4671::setFluxTorque(int16_t flux, int16_t torque){
2052 }
2053 writeReg(0x64, (flux & 0xffff) | (torque << 16));
2054}
2055
2056void TMC4671::setFluxTorqueFF(int16_t flux, int16_t torque){
2059 }
2060 writeReg(0x65, (flux & 0xffff) | (torque << 16));
2061}
2062
2066void TMC4671::rampFlux(uint16_t target,uint16_t time_ms){
2067 uint16_t startFlux = readReg(0x64) & 0xffff;
2068 int32_t stepsize = (target - startFlux) / std::max<uint16_t>(1, time_ms/2);
2069 if(stepsize == 0){
2070 stepsize = startFlux < target ? 1 : -1;
2071 }
2072 uint16_t flux = startFlux;
2073 while(abs(target - flux) >= abs(stepsize)){
2074 flux+=stepsize;
2075 setFluxTorque(std::max<int32_t>(0,flux), 0);
2076 Delay(2);
2077 }
2078}
2079
2081 curPids = pids;
2082 writeReg(0x54, pids.fluxI | (pids.fluxP << 16));
2083 writeReg(0x56, pids.torqueI | (pids.torqueP << 16));
2084 writeReg(0x58, pids.velocityI | (pids.velocityP << 16));
2085 writeReg(0x5A, pids.positionI | (pids.positionP << 16));
2087}
2088
2090 uint32_t f = readReg(0x54);
2091 uint32_t t = readReg(0x56);
2092 uint32_t v = readReg(0x58);
2093 uint32_t p = readReg(0x5A);
2094 // Update pid storage
2095 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)};
2096 return curPids;
2097}
2098
2102void TMC4671::setUqUdLimit(uint16_t limit){
2103 this->curLimits.pid_uq_ud = limit;
2104 writeReg(0x5D, limit);
2105}
2106
2107void TMC4671::setTorqueLimit(uint16_t limit){
2108 this->curLimits.pid_torque_flux = limit;
2109 bangInitPower = (float)limit*0.75;
2110 writeReg(0x5E, limit);
2111}
2112
2114
2115 this->pidPrecision = setting;
2116 uint16_t dat = setting.current_I;
2117 dat |= setting.current_P << 1;
2118 dat |= setting.velocity_I << 2;
2119 dat |= setting.velocity_P << 3;
2120 dat |= setting.position_I << 4;
2121 dat |= setting.position_P << 5;
2122 writeReg(0x4E, 62); // set config register address
2123 writeReg(0x4D, dat);
2124}
2125
2127 this->curLimits = limits;
2128 writeReg(0x5C, limits.pid_torque_flux_ddt);
2129 writeReg(0x5D, limits.pid_uq_ud);
2130 writeReg(0x5E, limits.pid_torque_flux);
2131 writeReg(0x5F, limits.pid_acc_lim);
2132 writeReg(0x60, limits.pid_vel_lim);
2133 writeReg(0x61, limits.pid_pos_low);
2134 writeReg(0x62, limits.pid_pos_high);
2135}
2136
2145 return curLimits;
2146}
2147
2153 const TMC4671Biquad_t& bq = filter.params;
2154 curFilters.flux = filter;
2155 writeReg(0x4E, 25);
2156 writeReg(0x4D, bq.a1);
2157 writeReg(0x4E, 26);
2158 writeReg(0x4D, bq.a2);
2159 writeReg(0x4E, 28);
2160 writeReg(0x4D, bq.b0);
2161 writeReg(0x4E, 29);
2162 writeReg(0x4D, bq.b1);
2163 writeReg(0x4E, 30);
2164 writeReg(0x4D, bq.b2);
2165 writeReg(0x4E, 31);
2166 writeReg(0x4D, bq.enable & 0x1);
2167}
2168
2174 const TMC4671Biquad_t& bq = filter.params;
2175 curFilters.pos = filter;
2176 writeReg(0x4E, 1);
2177 writeReg(0x4D, bq.a1);
2178 writeReg(0x4E, 2);
2179 writeReg(0x4D, bq.a2);
2180 writeReg(0x4E, 4);
2181 writeReg(0x4D, bq.b0);
2182 writeReg(0x4E, 5);
2183 writeReg(0x4D, bq.b1);
2184 writeReg(0x4E, 6);
2185 writeReg(0x4D, bq.b2);
2186 writeReg(0x4E, 7);
2187 writeReg(0x4D, bq.enable & 0x1);
2188}
2189
2195 const TMC4671Biquad_t& bq = filter.params;
2196 curFilters.vel = filter;
2197 writeReg(0x4E, 9);
2198 writeReg(0x4D, bq.a1);
2199 writeReg(0x4E, 10);
2200 writeReg(0x4D, bq.a2);
2201 writeReg(0x4E, 12);
2202 writeReg(0x4D, bq.b0);
2203 writeReg(0x4E, 13);
2204 writeReg(0x4D, bq.b1);
2205 writeReg(0x4E, 14);
2206 writeReg(0x4D, bq.b2);
2207 writeReg(0x4E, 15);
2208 writeReg(0x4D, bq.enable & 0x1);
2209}
2210
2216 const TMC4671Biquad_t& bq = filter.params;
2217 curFilters.torque = filter;
2218 writeReg(0x4E, 17);
2219 writeReg(0x4D, bq.a1);
2220 writeReg(0x4E, 18);
2221 writeReg(0x4D, bq.a2);
2222 writeReg(0x4E, 20);
2223 writeReg(0x4D, bq.b0);
2224 writeReg(0x4E, 21);
2225 writeReg(0x4D, bq.b1);
2226 writeReg(0x4E, 22);
2227 writeReg(0x4D, bq.b2);
2228 writeReg(0x4E, 23);
2229 writeReg(0x4D, bq.enable & 0x1);
2230}
2231
2232
2237// this->torqueFilter = params;
2238// setBiquadTorque(makeLpTmcFilter(params,enable));
2239//
2240 // Presets: off, Lowpass, notch, peak
2241 this->torqueFilterConf = conf;
2242 TMC4671Biquad filter;
2243 switch(conf.mode){
2244 default:
2246 filter = TMC4671Biquad(false);
2247 break;
2249 filter = TMC4671Biquad(Biquad(BiquadType::lowpass, (float)conf.params.freq / getPwmFreq(), (float)conf.params.q/100.0,0.0), true);
2250 break;
2252 filter = TMC4671Biquad(Biquad(BiquadType::notch, (float)conf.params.freq / getPwmFreq(), (float)conf.params.q/10.0,0.0), true);
2253 break;
2255 filter = TMC4671Biquad(Biquad(BiquadType::peak, (float)conf.params.freq / getPwmFreq(), (float)conf.params.q/10.0,conf.gain), true);
2256 break;
2257 }
2258 setBiquadTorque(filter);
2259}
2260
2261
2267void TMC4671::setBrakeLimits(uint16_t low,uint16_t high){
2268 uint32_t val = low | (high << 16);
2269 writeReg(0x75,val);
2270}
2271
2278 blinkClipLed(100, 0);
2279 int32_t pos = getPos();
2280 setTmcPos(0);
2281 PhiE lastphie = getPhiEtype();
2282 MotionMode lastmode = getMotionMode();
2283 updateReg(0x25, 0,0x1000,12); // Set dir normal
2284 setPhiE_ext(0);
2286 setFluxTorque(0, 0);
2288 rampFlux(bangInitPower, 1000);
2289
2290 int16_t phiE_abn = readReg(0x2A)>>16;
2291 int16_t phiE_abn_old = 0;
2292 int16_t rcount=0,c = 0; // Count how often direction was in reverse
2293 uint16_t highcount = 0; // Count high state of n pulse for polarity estimation
2294
2295 // Rotate a bit
2296 for(int16_t p = 0;p<0x0fff;p+=0x2f){
2297 setPhiE_ext(p);
2298 Delay(10);
2299 c++;
2300 phiE_abn_old = phiE_abn;
2301 phiE_abn = readReg(0x2A)>>16;
2302 // Count how often the new position was lower than the previous indicating a reversed encoder or motor direction
2303 if(phiE_abn < phiE_abn_old){
2304 rcount++;
2305 }
2306 if((readReg(0x76) & 0x04) >> 2){
2307 highcount++;
2308 }
2309 }
2310 setTmcPos(pos+getPos());
2311
2312 rampFlux(0, 100);
2313 setPhiEtype(lastphie);
2314 setMotionMode(lastmode,true);
2315
2316 bool npol = highcount > c/2;
2317 abnconf.rdir = rcount > c/2;
2318 if(npol != abnconf.npol) // Invert dir if polarity was reversed TODO correct? likely wrong at the moment
2320
2321 abnconf.apol = npol;
2322 abnconf.bpol = npol;
2323 abnconf.npol = npol;
2324 blinkClipLed(0, 0);
2325}
2326
2331 blinkClipLed(100, 0);
2332
2333 PhiE lastphie = getPhiEtype();
2334 MotionMode lastmode = getMotionMode();
2335 int16_t oldPhiE = getPhiE();
2336 setPhiE_ext(oldPhiE);
2338 setFluxTorque(0, 0);
2340 rampFlux(bangInitPower, 1000);
2341 int16_t phiE_enc = getPhiEfromExternalEncoder();
2342 int16_t phiE_enc_old = 0;
2343 int16_t rcount=0,c = 0; // Count how often direction was in reverse
2344
2345 // Rotate a bit
2346 for(int16_t p = 0;p<0x0fff;p+=0x2f){
2347 setPhiE_ext(p+oldPhiE);
2348 Delay(10);
2349 c++;
2350 phiE_enc_old = phiE_enc;
2351 phiE_enc = getPhiEfromExternalEncoder();
2352 // Count how often the new position was lower than the previous indicating a reversed encoder or motor direction
2353 if(phiE_enc < phiE_enc_old){
2354 rcount++;
2355 }
2356 }
2357
2358 rampFlux(0, 100);
2359 setPhiEtype(lastphie);
2360 setMotionMode(lastmode,true);
2361
2362 if(rcount > c/2)
2364
2365 blinkClipLed(0, 0);
2366}
2367
2368
2369
2382 updateReg(0x1A,(uint8_t)val,0xff,0);
2383}
2384
2385void TMC4671::setBBM(uint8_t bbmL,uint8_t bbmH){
2386 this->conf.bbmH = bbmH;
2387 this->conf.bbmL = bbmL;
2388 uint32_t bbmr = bbmL | (bbmH << 8);
2389 writeReg(0x19, bbmr);
2390}
2391
2392void TMC4671::setPwm(uint8_t val,uint16_t maxcnt,uint8_t bbmL,uint8_t bbmH){
2393 setPwmMaxCnt(maxcnt);
2394 setPwm((TMC_PwmMode)val);
2395 setBBM(bbmL, bbmH);
2396 writeReg(0x17,0); //Polarity
2397}
2398
2403void TMC4671::setSvPwm(bool enable){
2404 conf.motconf.svpwm = enable;
2406 enable = false; // Only valid for 3 phase motors with isolated star point
2407 }
2408
2409 updateReg(0x1A,enable,0x01,8);
2410}
2411
2417 return (4.0 * this->conf.hwconf.clockfreq) / (this->conf.pwmcnt +1);
2418}
2419
2425void TMC4671::setPwmMaxCnt(uint16_t maxcnt){
2426 maxcnt = clip(maxcnt, 255, 4095);
2427 this->conf.pwmcnt = maxcnt;
2428 writeReg(0x18, maxcnt);
2429}
2430
2436void TMC4671::setPwmFreq(float freq){
2437 if(freq <= 0)
2438 return;
2439 uint16_t maxcnt = ((4.0 * this->conf.hwconf.clockfreq) / freq) -1;
2440 setPwmMaxCnt(maxcnt);
2441}
2442
2443
2444void TMC4671::initAdc(uint16_t mdecA, uint16_t mdecB,uint32_t mclkA,uint32_t mclkB){
2445 uint32_t dat = mdecA | (mdecB << 16);
2446 writeReg(0x07, dat);
2447
2448 writeReg(0x05, mclkA);
2449 writeReg(0x06, mclkB);
2450 // Enable/Disable adcs
2451 updateReg(0x04, mclkA == 0 ? 0 : 1, 0x1, 4);
2452 updateReg(0x04, mclkB == 0 ? 0 : 1, 0x1, 20);
2453
2454 writeReg(0x0A,0x18000100); // ADC Selection
2455}
2456
2461std::pair<int32_t,int32_t> TMC4671::getActualTorqueFlux(){
2462 uint32_t tfluxa = readReg(0x69);
2463 int16_t af = (tfluxa & 0xffff);
2464 int16_t at = (tfluxa >> 16);
2465 return std::pair<int16_t,int16_t>(af,at);
2466}
2467
2472 uint32_t tfluxa = readReg(0x69);
2473 int16_t af = (tfluxa & 0xffff);
2474 return af;
2475}
2476
2481 uint32_t tfluxa = readReg(0x69);
2482 int16_t at = (tfluxa >> 16);
2483 return at;
2484}
2485
2486
2487//__attribute__((optimize("-Ofast")))
2488uint32_t TMC4671::readReg(uint8_t reg){
2490 uint8_t req[5] = {(uint8_t)(0x7F & reg),0,0,0,0};
2491 uint8_t tbuf[5];
2492 // 500ns delay after sending first byte
2493 spiPort.transmitReceive(req, tbuf, 5,this, SPITIMEOUT);
2494 uint32_t ret;
2495 memcpy(&ret,tbuf+1,4);
2496 ret = __REV(ret);
2497
2498 return ret;
2499}
2500
2501//__attribute__((optimize("-Ofast")))
2502void TMC4671::writeReg(uint8_t reg,uint32_t dat){
2503
2504 // wait until ready
2506 spi_buf[0] = (uint8_t)(0x80 | reg);
2507 dat =__REV(dat);
2508 memcpy(spi_buf+1,&dat,4);
2509
2510 // -----
2511 spiPort.transmit(spi_buf, 5, this, SPITIMEOUT);
2512}
2513
2514void TMC4671::writeRegAsync(uint8_t reg,uint32_t dat){
2515
2516 // wait until ready
2518 spi_buf[0] = (uint8_t)(0x80 | reg);
2519 dat =__REV(dat);
2520 memcpy(spi_buf+1,&dat,4);
2521
2522 // -----
2523#ifdef TMC4671_ALLOW_DMA
2524 spiPort.transmit_DMA(this->spi_buf, 5, this);
2525#else
2526 spiPort.transmit_IT(this->spi_buf, 5, this);
2527#endif
2528}
2529
2530void TMC4671::updateReg(uint8_t reg,uint32_t dat,uint32_t mask,uint8_t shift){
2531
2532 uint32_t t = readReg(reg) & ~(mask << shift);
2533 t |= ((dat & mask) << shift);
2534 writeReg(reg, t);
2535}
2536
2539}
2542 port->giveSemaphore();
2543}
2544
2550 uint32_t flags = readReg(0x7C);
2551 if(maskedOnly){
2552 flags = flags & this->statusMask.asInt;
2553 }
2554 this->statusFlags.asInt = flags; // Only set flags that are marked to trigger a notification
2555 return statusFlags;
2556}
2557
2559 writeReg(0x7D, mask.asInt);
2560}
2561
2562void TMC4671::setStatusMask(uint32_t mask){
2563 writeReg(0x7D, mask);
2564}
2565
2566void TMC4671::setStatusFlags(uint32_t flags){
2567 writeReg(0x7C, flags);
2568}
2569
2571 writeReg(0x7C, flags.asInt);
2572}
2573
2578 flagCheckInProgress = true;
2579 statusFlags = readFlags(); // Update current flags
2580
2581 // encoder index flag was set since last check. Check if the flag matching the current encoder is set
2582 if( (statusFlags.flags.ENC_N && this->conf.motconf.enctype == EncoderType_TMC::abn) || (statusFlags.flags.AENC_N && this->conf.motconf.enctype == EncoderType_TMC::sincos) ){
2584 }
2585
2587 // Critical error. PLL not locked
2588 // Creating error object not allowed. Function is called from flag isr! ignore for now.
2589 //ErrorHandler::addError(Error(ErrorCode::tmcPLLunlocked, ErrorType::critical, "TMC PLL not locked"));
2590 }
2591
2592
2593 setStatusFlags(0); // Reset flags
2594 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
2595 flagCheckInProgress = false;
2596 }
2597}
2598
2599void TMC4671::exti(uint16_t GPIO_Pin){
2600 if(GPIO_Pin == FLAG_Pin && !flagCheckInProgress){ // Flag pin went high and flag check is currently not in progress (prevents interrupt flooding)
2601 statusCheck(); // In isr!
2602 }
2603}
2604
2606 //pulseClipLed();
2607// if(zeroEncoderOnIndexHit){
2608// writeReg(0x27, 0);
2609// }
2610 setEncoderIndexFlagEnabled(false,false); // Found the index. disable flag
2611 encoderIndexHitFlag = true;
2612}
2613
2615 // 0-2: MotType 3-5: Encoder source 6-15: Poles
2616 TMC4671MotConf mot;
2617 mot.motor_type = MotorType(val & 0x3);
2618 mot.svpwm = !(val & 0x4);
2619 mot.enctype = EncoderType_TMC( (val >> 3) & 0x7);
2620 mot.pole_pairs = val >> 6;
2621 return mot;
2622}
2624 uint16_t val = (uint8_t)mconf.motor_type & 0x3;
2625 val |= !mconf.svpwm ? 0x4 : 0;
2626 val |= ((uint8_t)mconf.enctype & 0x7) << 3;
2627 val |= (mconf.pole_pairs & 0x3FF) << 6;
2628 return val;
2629}
2630
2632 uint16_t val = 0;
2633 val |= (this->abnconf.npol) & 0x01;
2634 val |= (this->conf.encoderReversed & 0x01) << 1; // Direction
2635
2636
2637 val |= (this->abnconf.ab_as_n & 0x01) << 2;
2638 val |= (this->pidPrecision.current_I) << 3;
2639 val |= (this->pidPrecision.current_P) << 4;
2640
2641 val |= (this->abnconf.useIndex) << 5;
2642
2643 val |= (this->conf.combineEncoder) << 6;
2644 val |= (this->conf.invertForce) << 7;
2645
2646 val |= ((this->conf.enableFluxDissipation & 0x01) << 8);
2647 val |= (this->hallconf.interpolation & 0x01) << 9;
2648
2649 val |= (this->curPids.sequentialPI & 0x01) << 10;
2650
2651 //11,12,13,14,15 hw version
2652 val |= ((uint8_t)this->conf.hwconf.hwVersion & 0x1F) << 11;
2653
2654 return val;
2655}
2656
2658
2659 this->abnconf.apol = (val) & 0x01;
2660
2661 this->abnconf.bpol = this->abnconf.apol;
2662 this->abnconf.npol = this->abnconf.apol;
2663
2664 this->conf.encoderReversed = (val>>1) & 0x01;// Direction
2665 this->abnconf.rdir = this->conf.encoderReversed;
2666 this->aencconf.rdir = this->conf.encoderReversed;
2667 this->hallconf.direction = this->conf.encoderReversed;
2668
2669 this->abnconf.ab_as_n = (val>>2) & 0x01;
2670 this->pidPrecision.current_I = (val>>3) & 0x01;
2673 this->pidPrecision.current_P = (val>>4) & 0x01;
2676
2677 this->abnconf.useIndex = (val>>5) & 0x01;
2678 this->conf.combineEncoder = (val>>6) & 0x01;
2679 this->conf.invertForce = ((val>>7) & 0x01) && this->conf.combineEncoder;
2680
2681 this->conf.enableFluxDissipation = ((val>>8) & 0x01);
2682 this->hallconf.interpolation = (val>>9) & 0x01;
2683 this->curPids.sequentialPI = (val>>10) & 0x01;
2684
2685 setHwType((TMC_HW_Ver)((val >> 11) & 0x1F));
2686
2687}
2688
2693 //TMC4671HardwareTypeConf newHwConf;
2694 switch(type){
2696 {
2697 TMC4671HardwareTypeConf newHwConf = {
2699 .adcOffset = 0,
2700 .thermistor_R2 = 1500,
2701 .thermistor_R = 10000,
2702 .thermistor_Beta = 4300,
2703 .temperatureEnabled = true,
2704 .temp_limit = 90,
2705 .currentScaler = 2.5 / (0x7fff * 0.066), // sensor 66mV/A
2706 .brakeLimLow = 50700,
2707 .brakeLimHigh = 50900,
2708 .vmScaler = (2.5 / 0x7fff) * ((1.5+71.5)/1.5),
2709 .vSenseMult = VOLTAGE_MULT_DEFAULT,
2710 .bbm = 50 // DMTH8003SPS need longer deadtime
2711 };
2712 this->conf.hwconf = newHwConf;
2713 break;
2714 }
2716 {
2717 TMC4671HardwareTypeConf newHwConf = {
2719 .adcOffset = 0,
2720 .thermistor_R2 = 1500,
2721 .thermistor_R = 10000,
2722 .thermistor_Beta = 4300,
2723 .temperatureEnabled = true,
2724 .temp_limit = 90,
2725 .currentScaler = 2.5 / (0x7fff * 0.1), // w. TMCS1100A2 sensor 100mV/A
2726 .brakeLimLow = 50700,
2727 .brakeLimHigh = 50900,
2728 .vmScaler = (2.5 / 0x7fff) * ((1.5+71.5)/1.5),
2729 .vSenseMult = VOLTAGE_MULT_DEFAULT,
2730 .bbm = 40
2731 };
2732 this->conf.hwconf = newHwConf;
2733 break;
2734 }
2736 {
2737 // TODO possibly lower PWM limit because of lower valid sensor range
2738 TMC4671HardwareTypeConf newHwConf = {
2740 .adcOffset = 0,
2741 .thermistor_R2 = 1500,
2742 .thermistor_R = 10000,
2743 .thermistor_Beta = 4300,
2744 .temperatureEnabled = true,
2745 .temp_limit = 90,
2746 .currentScaler = 2.5 / (0x7fff * 0.04), // w. LEM 20 sensor 40mV/A
2747 .brakeLimLow = 50700,
2748 .brakeLimHigh = 50900,
2749 .vmScaler = (2.5 / 0x7fff) * ((1.5+71.5)/1.5),
2750 .vSenseMult = VOLTAGE_MULT_DEFAULT,
2751 .bbm = 20
2752 };
2753 this->conf.hwconf = newHwConf;
2754 break;
2755 }
2756 case TMC_HW_Ver::v1_2_2:
2757 {
2758 // TODO possibly lower PWM limit because of lower valid sensor range
2759 TMC4671HardwareTypeConf newHwConf = {
2761 .adcOffset = 0,
2762 .thermistor_R2 = 1500,
2763 .thermistor_R = 10000,
2764 .thermistor_Beta = 4300,
2765 .temperatureEnabled = true,
2766 .temp_limit = 90,
2767 .currentScaler = 2.5 / (0x7fff * 0.08), // w. LEM 10 sensor 80mV/A
2768 .brakeLimLow = 50700,
2769 .brakeLimHigh = 50900,
2770 .vmScaler = (2.5 / 0x7fff) * ((1.5+71.5)/1.5),
2771 .vSenseMult = VOLTAGE_MULT_DEFAULT,
2772 .bbm = 20
2773 };
2774 this->conf.hwconf = newHwConf;
2775 break;
2776 }
2777
2778 case TMC_HW_Ver::v1_2:
2779 {
2780 TMC4671HardwareTypeConf newHwConf = {
2782 .adcOffset = 1000,
2783 .thermistor_R2 = 1500,
2784 .thermistor_R = 22000,
2785 .thermistor_Beta = 4300,
2786 .temperatureEnabled = true,
2787 .temp_limit = 90,
2788 .currentScaler = 2.5 / (0x7fff * 60.0 * 0.0015), // w. 60x 1.5mOhm sensor
2789 .brakeLimLow = 50700,
2790 .brakeLimHigh = 50900,
2791 .vmScaler = (2.5 / 0x7fff) * ((1.5+71.5)/1.5),
2792 .vSenseMult = VOLTAGE_MULT_DEFAULT,
2793 .bbm = 20
2794 };
2795 this->conf.hwconf = newHwConf;
2796 // Activates around 60V as last resort failsave. Check offsets from tmc leakage. ~ 1.426V
2797 break;
2798 }
2799
2800
2801 case TMC_HW_Ver::v1_0:
2802 {
2803 TMC4671HardwareTypeConf newHwConf = {
2805 .adcOffset = 1000,
2806 .thermistor_R2 = 0,
2807 .thermistor_R = 0,
2808 .thermistor_Beta = 0,
2809 .temperatureEnabled = false,
2810 .temp_limit = 90,
2811 .currentScaler = 2.5 / (0x7fff * 60.0 * 0.0015), // w. 60x 1.5mOhm sensor
2812 .brakeLimLow = 52400,
2813 .brakeLimHigh = 52800,
2814 .vmScaler = (2.5 / 0x7fff) * ((1.5+71.5)/1.5),
2815 .vSenseMult = VOLTAGE_MULT_DEFAULT,
2816 .bbm = 20
2817 };
2818 this->conf.hwconf = newHwConf;
2819
2820 break;
2821 }
2822
2823 case TMC_HW_Ver::NONE:
2824 {
2825 default:
2826 TMC4671HardwareTypeConf newHwConf;
2827 newHwConf.temperatureEnabled = false;
2828 newHwConf.hwVersion = TMC_HW_Ver::NONE;
2829 newHwConf.currentScaler = 0;
2830 this->conf.hwconf = newHwConf;
2831 setBrakeLimits(0,0); // Disables internal brake resistor activation. DANGER!
2832 break;
2833 }
2834 }
2835 setVSenseMult(this->conf.hwconf.vSenseMult); // Update vsense multiplier
2836 //setupBrakePin(vdiffAct, vdiffDeact, vMax); // TODO if required
2837 setBrakeLimits(this->conf.hwconf.brakeLimLow,this->conf.hwconf.brakeLimHigh);
2838 setBBM(this->conf.hwconf.bbm,this->conf.hwconf.bbm);
2839
2840}
2841
2844
2845 registerCommand("cpr", TMC4671_commands::cpr, "CPR in TMC",CMDFLAG_GET | CMDFLAG_SET);
2846 registerCommand("mtype", TMC4671_commands::mtype, "Motor type",CMDFLAG_GET | CMDFLAG_SET | CMDFLAG_INFOSTRING);
2847 registerCommand("encsrc", TMC4671_commands::encsrc, "Encoder source",CMDFLAG_GET | CMDFLAG_SET | CMDFLAG_INFOSTRING);
2848 registerCommand("tmcHwType", TMC4671_commands::tmcHwType, "Version of TMC board",CMDFLAG_GET | CMDFLAG_SET | CMDFLAG_INFOSTRING);
2849 registerCommand("encalign", TMC4671_commands::encalign, "Align encoder",CMDFLAG_GET);
2850 registerCommand("poles", TMC4671_commands::poles, "Motor pole pairs",CMDFLAG_GET | CMDFLAG_SET);
2851 registerCommand("acttrq", TMC4671_commands::acttrq, "Measure torque and flux",CMDFLAG_GET);
2852 registerCommand("pwmlim", TMC4671_commands::pwmlim, "PWM limit",CMDFLAG_DEBUG | CMDFLAG_GET | CMDFLAG_SET);
2853 registerCommand("torqueP", TMC4671_commands::torqueP, "Torque P",CMDFLAG_GET | CMDFLAG_SET);
2854 registerCommand("torqueI", TMC4671_commands::torqueI, "Torque I",CMDFLAG_GET | CMDFLAG_SET);
2855 registerCommand("fluxP", TMC4671_commands::fluxP, "Flux P",CMDFLAG_GET | CMDFLAG_SET);
2856 registerCommand("fluxI", TMC4671_commands::fluxI, "Flux I",CMDFLAG_GET | CMDFLAG_SET);
2857 registerCommand("velocityP", TMC4671_commands::velocityP, "Velocity P",CMDFLAG_GET | CMDFLAG_SET);
2858 registerCommand("velocityI", TMC4671_commands::velocityI, "Velocity I",CMDFLAG_GET | CMDFLAG_SET);
2859 registerCommand("posP", TMC4671_commands::posP, "Pos P",CMDFLAG_GET | CMDFLAG_SET);
2860 registerCommand("posI", TMC4671_commands::posI, "Pos I",CMDFLAG_GET | CMDFLAG_SET);
2861 registerCommand("tmctype", TMC4671_commands::tmctype, "Version of TMC chip",CMDFLAG_GET);
2862 registerCommand("pidPrec", TMC4671_commands::pidPrec, "PID precision bit0=I bit1=P. 0=Q8.8 1= Q4.12",CMDFLAG_GET | CMDFLAG_SET);
2863 registerCommand("phiesrc", TMC4671_commands::phiesrc, "PhiE source",CMDFLAG_DEBUG | CMDFLAG_GET | CMDFLAG_SET);
2864 registerCommand("fluxoffset", TMC4671_commands::fluxoffset, "Offset flux scale for field weakening",CMDFLAG_GET | CMDFLAG_SET);
2865 registerCommand("seqpi", TMC4671_commands::seqpi, "Sequential PI",CMDFLAG_GET | CMDFLAG_SET);
2866 registerCommand("iScale", TMC4671_commands::tmcIscale, "Counts per A",CMDFLAG_STR_ONLY);
2867 registerCommand("encdir", TMC4671_commands::encdir, "Encoder dir",CMDFLAG_DEBUG | CMDFLAG_GET | CMDFLAG_SET);
2868 registerCommand("abnpol", TMC4671_commands::encpol, "Encoder polarity",CMDFLAG_GET | CMDFLAG_SET);
2869 registerCommand("temp", TMC4671_commands::temp, "Temperature in C * 100",CMDFLAG_GET);
2870 registerCommand("reg", TMC4671_commands::reg, "Read or write a TMC register at adr",CMDFLAG_DEBUG | CMDFLAG_GETADR | CMDFLAG_SETADR);
2871 registerCommand("svpwm", TMC4671_commands::svpwm, "Space-vector PWM",CMDFLAG_GET | CMDFLAG_SET);
2872 registerCommand("autohome", TMC4671_commands::findIndex, "Find abn index",CMDFLAG_GET);
2873 registerCommand("abnindex", TMC4671_commands::abnindexenabled, "Enable ABN index",CMDFLAG_GET | CMDFLAG_SET);
2874 registerCommand("calibrate", TMC4671_commands::fullCalibration, "Full calibration",CMDFLAG_GET);
2875 registerCommand("calibrated", TMC4671_commands::calibrated, "Calibration valid",CMDFLAG_GET);
2876 registerCommand("state", TMC4671_commands::getState, "Get state",CMDFLAG_GET);
2877 registerCommand("combineEncoder", TMC4671_commands::combineEncoder, "Use TMC for movement. External encoder for position",CMDFLAG_GET | CMDFLAG_SET);
2878 registerCommand("invertForce", TMC4671_commands::invertForce, "Invert incoming forces",CMDFLAG_GET | CMDFLAG_SET);
2879 registerCommand("vm", TMC4671_commands::vmTmc, "VM in mV",CMDFLAG_GET);
2880 registerCommand("extphie", TMC4671_commands::extphie, "external phie",CMDFLAG_GET);
2881 registerCommand("trqbq_mode", TMC4671_commands::torqueFilter_mode, "Torque filter mode: none;lowpass;notch;peak",CMDFLAG_GET | CMDFLAG_SET | CMDFLAG_INFOSTRING);
2882 registerCommand("trqbq_f", TMC4671_commands::torqueFilter_f, "Torque filter freq 1000 max. 0 to disable. (Stored f/2)",CMDFLAG_GET | CMDFLAG_SET);
2883 registerCommand("trqbq_q", TMC4671_commands::torqueFilter_q, "Torque filter q*100",CMDFLAG_GET | CMDFLAG_SET);
2884 registerCommand("pidautotune", TMC4671_commands::pidautotune, "Start PID autoruning",CMDFLAG_GET);
2885 registerCommand("fluxbrake", TMC4671_commands::fluxbrake, "Prefer energy dissipation in motor",CMDFLAG_GET | CMDFLAG_SET);
2886 registerCommand("pwmfreq", TMC4671_commands::pwmfreq, "Get/set pwm frequency",CMDFLAG_GET | CMDFLAG_SET | CMDFLAG_DEBUG);
2887}
2888
2889
2890CommandStatus TMC4671::command(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
2892 switch(static_cast<TMC4671_commands>(cmd.cmdId)){
2894 status = handleGetSet(cmd, replies, this->conf.combineEncoder);
2895 if(!this->conf.combineEncoder){
2896 this->conf.invertForce = false; // Force off
2897 }
2898
2899 break;
2900
2903 break;
2904
2906 handleGetSet(cmd, replies, conf.invertForce);
2907 break;
2908
2910 replies.emplace_back((uint32_t)getState());
2911 break;
2912
2914 calibrationFailCount = 1; // allow 1 fail
2916 // TODO start full calibration and save in flash
2917 break;
2918
2920 replies.emplace_back(!recalibrationRequired && adcCalibrated);
2921 break;
2922
2924 if(cmd.type == CMDtype::get){
2925 replies.emplace_back((uint8_t)this->conf.motconf.motor_type);
2926 }else if(cmd.type == CMDtype::set && (uint8_t)cmd.type < (uint8_t)MotorType::ERR){
2927 this->setMotorType((MotorType)cmd.val, this->conf.motconf.pole_pairs);
2928 }else{
2929 replies.emplace_back("NONE=0,DC=1,2Ph Stepper=2,3Ph BLDC=3");
2930 }
2931 break;
2932
2934 if(cmd.type == CMDtype::get){
2935 replies.emplace_back((uint8_t)this->conf.motconf.enctype);
2936 }else if(cmd.type == CMDtype::set){
2938 }else{
2940 replies.emplace_back("NONE=0,ABN=1,SinCos=2,Analog UVW=3,Hall=4,External=5");
2941 else
2942 replies.emplace_back("NONE=0,ABN=1,SinCos=2,Analog UVW=3,Hall=4");
2943
2944 }
2945 break;
2946
2948 if(cmd.type == CMDtype::get){
2949 replies.push_back((uint8_t)conf.hwconf.hwVersion);
2950 }else if(cmd.type == CMDtype::set){
2952 setHwType((TMC_HW_Ver)(cmd.val & 0x1F));
2953 }else{
2954 // List known hardware versions
2955 for(auto v : tmcHwVersionNames){
2956 if(conf.canChangeHwType || v.first == conf.hwconf.hwVersion){
2957 replies.emplace_back( std::to_string((uint8_t)v.first) + ":" + v.second,(uint8_t)v.first);
2958 }
2959
2960 }
2961 }
2962 break;
2963
2965 if(cmd.type == CMDtype::get){
2966 encoderAligned = false;
2967 this->setEncoderType(this->conf.motconf.enctype);
2968 manualEncAlign = true;
2970 }else{
2971 return CommandStatus::ERR;
2972 }
2973 break;
2974
2976 if(cmd.type == CMDtype::get){
2977 replies.emplace_back(this->conf.motconf.pole_pairs);
2978 }else if(cmd.type == CMDtype::set){
2979 this->setMotorType(this->conf.motconf.motor_type,cmd.val);
2980 }
2981 break;
2982
2984 if(cmd.type == CMDtype::get){
2985 std::pair<int32_t,int32_t> current = getActualTorqueFlux();
2986 replies.emplace_back(current.second,current.first);
2987 }
2988 break;
2989
2991 if(cmd.type == CMDtype::get){
2992 replies.emplace_back(this->curLimits.pid_uq_ud);
2993 }else if(cmd.type == CMDtype::set){
2994 this->setUqUdLimit(cmd.val);
2995 }
2996 break;
2997
2999 handleGetSet(cmd, replies, this->curPids.torqueP);
3000 if(cmd.type == CMDtype::set)
3002 break;
3003
3005 handleGetSet(cmd, replies, this->curPids.torqueI);
3006 if(cmd.type == CMDtype::set)
3008 break;
3009
3011 handleGetSet(cmd, replies, this->curPids.fluxP);
3012 if(cmd.type == CMDtype::set)
3014 break;
3015
3017 handleGetSet(cmd, replies, this->curPids.fluxI);
3018 if(cmd.type == CMDtype::set)
3020 break;
3021
3023 handleGetSet(cmd, replies, this->curPids.velocityP);
3024 if(cmd.type == CMDtype::set)
3026 break;
3027
3029 handleGetSet(cmd, replies, this->curPids.velocityI);
3030 if(cmd.type == CMDtype::set)
3032 break;
3033
3035 handleGetSet(cmd, replies, this->curPids.positionP);
3036 if(cmd.type == CMDtype::set)
3038 break;
3039
3041 handleGetSet(cmd, replies, this->curPids.positionI);
3042 if(cmd.type == CMDtype::set)
3044 break;
3045
3047 handleGetSet(cmd, replies, this->abnconf.useIndex);
3048 if(cmd.type == CMDtype::set)
3050 break;
3051
3053 {
3054 std::pair<uint32_t,std::string> ver = getTmcType();
3055 replies.emplace_back(ver.second,ver.first);
3056 break;
3057 }
3058
3060 replies.emplace_back(getTmcVM());
3061 break;
3062
3064 if(cmd.type == CMDtype::get){
3065 replies.emplace_back(this->pidPrecision.current_I | (this->pidPrecision.current_P << 1));
3066 }else if(cmd.type == CMDtype::set){
3067 this->pidPrecision.current_I = cmd.val & 0x1;
3068 this->pidPrecision.current_P = (cmd.val >> 1) & 0x1;
3070 }
3071 break;
3073 if(cmd.type == CMDtype::get){
3074 replies.emplace_back((uint8_t)this->getPhiEtype());
3075 }else if(cmd.type == CMDtype::set){
3076 this->setPhiEtype((PhiE)cmd.val);
3077 }else{
3078 replies.emplace_back("ext=1,openloop=2,abn=3,hall=5,aenc=6,aencE=7");
3079 }
3080 break;
3082 handleGetSet(cmd, replies, maxOffsetFlux);
3083 break;
3085 if(cmd.type == CMDtype::get){
3086 replies.emplace_back(this->curPids.sequentialPI);
3087 }else if(cmd.type == CMDtype::set){
3088 this->setSequentialPI(cmd.val != 0);
3089 }
3090 break;
3092 if(cmd.type == CMDtype::get){
3093 replies.emplace_back(std::to_string(this->conf.hwconf.currentScaler)); // TODO float as value?
3094 }
3095 break;
3097 if(cmd.type == CMDtype::get){
3098 replies.emplace_back(this->abnconf.rdir);
3099 }else if(cmd.type == CMDtype::set){
3100 this->abnconf.rdir = cmd.val != 0;
3101 this->setup_ABN_Enc(this->abnconf);
3102 }
3103 break;
3104
3106 if(cmd.type == CMDtype::get){
3107 replies.emplace_back(this->abnconf.npol);
3108 }else if(cmd.type == CMDtype::set){
3109 this->abnconf.npol = cmd.val != 0;
3110 this->abnconf.apol = cmd.val != 0;
3111 this->abnconf.bpol = cmd.val != 0;
3112 this->setup_ABN_Enc(this->abnconf);
3113 }
3114 break;
3116 if(cmd.type == CMDtype::get){
3117 replies.emplace_back((int32_t)(this->getTemp()*100.0));
3118 }
3119 break;
3121 if(cmd.type == CMDtype::getat){
3122 replies.emplace_back(readReg(cmd.val));
3123 }else if(cmd.type == CMDtype::setat){
3124 writeReg(cmd.adr,cmd.val);
3125 }else{
3126 return CommandStatus::ERR;
3127 }
3128 break;
3129
3132 break;
3133
3135 {
3136 if(cmd.type == CMDtype::set){
3137 setSvPwm(cmd.val != 0);
3138 }else if(cmd.type == CMDtype::get){
3139 replies.emplace_back(conf.motconf.svpwm);
3140 }
3141 break;
3142 }
3144 {
3145
3146 replies.emplace_back(getPhiEfromExternalEncoder());
3147
3148 break;
3149 }
3151 if(cmd.type == CMDtype::get){
3152 replies.emplace_back((uint8_t)this->torqueFilterConf.mode);
3153 }else if(cmd.type == CMDtype::set && (uint8_t)cmd.val < 4){
3156 }else{
3157 replies.emplace_back("OFF=0,Lowpass=1,Notch=2,Peak=3");
3158 }
3159 break;
3161 {
3162 if(cmd.type == CMDtype::set){
3163 torqueFilterConf.params.freq = clip(cmd.val,1,0x1fff);
3165 }else if(cmd.type == CMDtype::get){
3166 replies.emplace_back(torqueFilterConf.params.freq);
3167 }
3168 break;
3169 }
3170
3172 if(cmd.type == CMDtype::set){
3173 torqueFilterConf.params.q = clip(cmd.val,0,127);
3175 }else if(cmd.type == CMDtype::get){
3176 replies.emplace_back(torqueFilterConf.params.q);
3177 }
3178 break;
3182
3185 break;
3186
3188 if(cmd.type == CMDtype::set){
3189 setPwmFreq(cmd.val);
3190 }else if(cmd.type == CMDtype::get){
3191 replies.emplace_back(getPwmFreq());
3192 }
3193 break;
3194
3195 default:
3197 }
3198
3199 return status;
3200
3201
3202}
3203
3204#ifdef TIM_TMC
3205 void TMC4671::timerElapsed(TIM_HandleTypeDef* htim){
3206 if(htim != this->externalEncoderTimer){
3207 return;
3208 }
3209 // Read encoder and send to tmc
3211 //setPhiE_ext(getPhiEfromExternalEncoder());
3212 // Signal phiE update
3213 extEncUpdater->updateFromIsr(); // Use task so that the update is not being done inside an ISR
3214 }
3215 }
3216#endif
3217
3219#ifdef TIM_TMC
3220 if(extEncUpdater == nullptr) // Create updater thread
3221 extEncUpdater = std::make_unique<TMC_ExternalEncoderUpdateThread>(this);
3222 // Setup timer
3224 this->externalEncoderTimer->Instance->ARR = 200; // 200 = 5khz = 5 tmc cycles, 250 = 4khz, 240 = 6 tmc cycles
3225 this->externalEncoderTimer->Instance->PSC = (SystemCoreClock / 2000000)+1; // timer running at half clock speed. 1µs ticks
3226 this->externalEncoderTimer->Instance->CR1 = 1;
3227 HAL_TIM_Base_Start_IT(this->externalEncoderTimer);
3228#endif
3229}
3230
3235 this->Start();
3236}
3237
3239 while(true){
3240 this->WaitForNotification();
3241 if(tmc->usingExternalEncoder() && !tmc->spiPort.isTaken()){
3242 tmc->writeRegAsync(0x1C, (tmc->getPhiEfromExternalEncoder())); // Write phiE_ext
3243 }
3244 }
3245}
3246
3248 if(tmc->initialized)
3249 this->NotifyFromISR();
3250}
3251
3252void TMC4671::errorCallback(const Error &error, bool cleared){
3253 if(!cleared && error.code == ErrorCode::brakeResistorFailure){
3254 // shut down and block.
3255 emergencyStop(false);
3257 }
3258}
3259#endif
CommandStatus
EncoderType
Definition: Encoder.h:27
@ brakeResistorFailure
@ adcCalibrationError
@ encoderAlignmentFailed
TMC_HW_Ver
Definition: TMC4671.h:58
MotionMode
Definition: TMC4671.h:51
EncoderType_TMC
Definition: TMC4671.h:55
MotorType
Definition: TMC4671.h:49
FFMode
Definition: TMC4671.h:52
VelSelection
Definition: TMC4671.h:54
TMCbiquadpreset
Definition: TMC4671.h:269
TMC_GpioMode
Definition: TMC4671.h:47
TIM_HandleTypeDef TIM_TMC
TMC_PwmMode
Definition: TMC4671.h:43
const std::vector< std::pair< TMC_HW_Ver, std::string > > tmcHwVersionNames
Definition: TMC4671.h:60
TMC_ControlState
Definition: TMC4671.h:41
PhiE
Definition: TMC4671.h:50
@ extEncoder
@ openloop
PosSelection
Definition: TMC4671.h:53
Definition: Filters.h:31
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)
uint32_t cpr
Definition: Encoder.h:53
static void clearError(const Error &error)
static void addError(const Error &error)
ErrorCode code
Definition: ErrorHandler.h:65
std::shared_ptr< Encoder > drvEncoder
Definition: MotorDriver.h:46
void set() const
Definition: GPIOPin.h:38
void reset() const
Definition: GPIOPin.h:42
Definition: SPI.h:100
SPIPort & spiPort
Definition: SPI.h:124
void assertChipSelect()
Definition: SPI.cpp:373
void clearChipSelect()
Definition: SPI.cpp:377
SPIConfig spiConfig
Definition: SPI.h:125
Definition: SPI.h:43
void transmitReceive(const uint8_t *txbuf, uint8_t *rxbuf, uint16_t size, SPIDevice *device, uint16_t timeout)
Definition: SPI.cpp:176
void transmit_IT(const uint8_t *buf, uint16_t size, SPIDevice *device)
Definition: SPI.cpp:128
bool isPinFree(OutputPin pin)
Definition: SPI.cpp:51
void takeSemaphore()
Definition: SPI.cpp:186
std::pair< uint32_t, float > getClosestPrescaler(float clock)
Definition: SPI.cpp:291
SPI_HandleTypeDef * getPortHandle()
Definition: SPI.cpp:80
void transmit(const uint8_t *buf, uint16_t size, SPIDevice *device, uint16_t timeout)
Definition: SPI.cpp:158
void transmit_DMA(const uint8_t *buf, uint16_t size, SPIDevice *device)
Definition: SPI.cpp:89
OutputPin * getCsPin(uint16_t idx)
Definition: SPI.cpp:65
void configurePort(SPI_InitTypeDef *config)
Definition: SPI.cpp:72
void giveSemaphore()
Definition: SPI.cpp:199
TMC4671Biquad_t params
Definition: TMC4671.h:304
void writeReg(uint8_t reg, uint32_t dat)
Definition: TMC4671.cpp:2502
static ClassIdentifier info
Definition: TMC4671.h:339
int16_t bangInitPower
Definition: TMC4671.h:440
void beginSpiTransfer(SPIPort *port)
Definition: TMC4671.cpp:2537
void setFluxTorque(int16_t flux, int16_t torque)
Definition: TMC4671.cpp:2049
void calibrateEncoder()
Definition: TMC4671.cpp:648
void saveFlash() override
Definition: TMC4671.cpp:107
void setBBM(uint8_t bbml, uint8_t bbmh)
Definition: TMC4671.cpp:2385
int16_t controlFluxDissipate()
Definition: TMC4671.cpp:1710
int32_t getTargetPos()
Definition: TMC4671.cpp:903
int16_t externalEncoderPhieOffset
Definition: TMC4671.h:606
PhiE getPhiEtype()
Definition: TMC4671.cpp:1595
bool pidAutoTune()
Definition: TMC4671.cpp:666
bool adcSettingsStored
Definition: TMC4671.h:596
TMC_ControlState getState()
Definition: TMC4671.cpp:776
TMC4671Limits curLimits
Definition: TMC4671.h:495
int16_t getFlux()
Definition: TMC4671.cpp:2046
void setExternalEncoderAllowed(bool allow)
Definition: TMC4671.cpp:1993
bool externalEncoderAllowed()
Definition: TMC4671.cpp:2006
TMC4671PIDConf getPids()
Definition: TMC4671.cpp:2089
bool allowExternalEncoder
Definition: TMC4671.h:607
bool autohome()
Definition: TMC4671.cpp:762
bool encHallRestored
Definition: TMC4671.h:602
void statusCheck()
Definition: TMC4671.cpp:2577
void startMotor()
Definition: TMC4671.cpp:1661
const Error estopError
Definition: TMC4671.h:578
void setLimits(TMC4671Limits limits)
Definition: TMC4671.cpp:2126
void runOpenLoop(uint16_t ud, uint16_t uq, int32_t speed, int32_t accel, bool torqueMode=false)
Definition: TMC4671.cpp:1625
bool hasIntegratedEncoder() override
Definition: TMC4671.cpp:1856
volatile bool encoderIndexHitFlag
Definition: TMC4671.h:598
TMC_ControlState state
Definition: TMC4671.h:580
uint32_t initTime
Definition: TMC4671.h:638
void setupFeedForwardVelocity(int32_t gain, int32_t constant)
Definition: TMC4671.cpp:1973
CommandStatus command(const ParsedCommand &cmd, std::vector< CommandReply > &replies)
Definition: TMC4671.cpp:2890
uint32_t getCpr()
Definition: TMC4671.cpp:1909
uint8_t calibrationFailCount
Definition: TMC4671.h:604
bool fullCalibrationInProgress
Definition: TMC4671.h:600
void setEncoderIndexFlagEnabled(bool enabled, bool zeroEncoder=false)
Definition: TMC4671.cpp:877
void initializeWithPower()
Definition: TMC4671.cpp:385
void setPos(int32_t pos) override
Definition: TMC4671.cpp:1864
void bangInitEnc(int16_t power)
Definition: TMC4671.cpp:957
bool reachedPosition(uint16_t tolerance)
Definition: TMC4671.cpp:792
TMC4671_commands
Definition: TMC4671.h:325
void setPids(TMC4671PIDConf pids)
Definition: TMC4671.cpp:2080
MotionMode lastMotionMode
Definition: TMC4671.h:584
const float fluxDissipationLimit
Definition: TMC4671.h:443
TMC4671ABNConf abnconf
Definition: TMC4671.h:505
TMC_ControlState requestedState
Definition: TMC4671.h:582
bool usingExternalEncoder()
Definition: TMC4671.h:513
void setUdUq(int16_t ud, int16_t uq)
Definition: TMC4671.cpp:1646
StatusFlags statusMask
Definition: TMC4671.h:541
void changeState(TMC_ControlState newState, bool force=false)
Definition: TMC4671.cpp:780
int16_t idleFlux
Definition: TMC4671.h:437
const Error lowVoltageError
Definition: TMC4671.h:576
void setVelSel(VelSelection vsel, uint8_t mode=0)
Definition: TMC4671.cpp:1764
void setEncoderType(EncoderType_TMC type)
Definition: TMC4671.cpp:1513
uint16_t maxOffsetFlux
Definition: TMC4671.h:438
TMC4671PIDConf curPids
Definition: TMC4671.h:493
TIM_HandleTypeDef * externalEncoderTimer
Definition: TMC4671.h:650
bool allowSlowSPI
Definition: TMC4671.h:550
TMC4671BiquadFilters curFilters
Definition: TMC4671.h:644
MotionMode getMotionMode()
Definition: TMC4671.cpp:1614
bool ES_TMCdetected
Definition: TMC4671.h:589
TMC_ControlState laststate
Definition: TMC4671.h:581
void setBrakeLimits(uint16_t low, uint16_t high)
Definition: TMC4671.cpp:2267
TMC4671PidPrecision pidPrecision
Definition: TMC4671.h:503
bool recalibrationRequired
Definition: TMC4671.h:610
uint16_t encodeEncHallMisc()
Definition: TMC4671.cpp:2631
void setPhiE_ext(int16_t phiE)
Definition: TMC4671.cpp:930
int32_t getTargetVelocity()
Definition: TMC4671.cpp:919
void calibFailCb()
Definition: TMC4671.cpp:1420
void timerElapsed(TIM_HandleTypeDef *htim)
Definition: TMC4671.cpp:3205
bool emergency
Definition: TMC4671.h:433
void setStatusFlags(uint32_t flags)
Definition: TMC4671.cpp:2566
void setFluxTorqueFF(int16_t flux, int16_t torque)
Definition: TMC4671.cpp:2056
void setBiquadVel(const TMC4671Biquad &filter)
Definition: TMC4671.cpp:2194
void restoreEncHallMisc(uint16_t val)
Definition: TMC4671.cpp:2657
TMC4671MainConfig conf
Definition: TMC4671.h:357
void setUpExtEncTimer()
Definition: TMC4671.cpp:3218
static uint16_t encodeMotToInt(TMC4671MotConf mconf)
Definition: TMC4671.cpp:2623
virtual ~TMC4671()
Definition: TMC4671.cpp:81
void setTorque(int16_t torque)
Definition: TMC4671.cpp:2030
bool pingDriver()
Definition: TMC4671.cpp:223
bool calibrateAdcOffset(uint16_t time=500)
Definition: TMC4671.cpp:1359
int32_t getPosAbs() override
Definition: TMC4671.cpp:1893
int32_t getTmcVM()
Definition: TMC4671.cpp:231
void setStatusMask(StatusFlags mask)
Definition: TMC4671.cpp:2558
void zeroAbnUsingPhiM(bool offsetPhiE=false)
Definition: TMC4671.cpp:802
bool isSetUp()
Definition: TMC4671.cpp:198
void encoderIndexHit()
Definition: TMC4671.cpp:2605
int16_t getPhiE()
Definition: TMC4671.cpp:946
void setSequentialPI(bool sequential)
Definition: TMC4671.cpp:1988
TMC4671AENCConf aencconf
Definition: TMC4671.h:507
TMC4671HALLConf hallconf
Definition: TMC4671.h:506
MotionMode curMotionMode
Definition: TMC4671.h:583
const float fluxFilterFreq
Definition: TMC4671.h:645
const Error indexNotHitError
Definition: TMC4671.h:575
void setup_AENC(TMC4671AENCConf encconf)
Definition: TMC4671.cpp:1313
Encoder * getEncoder() override
Definition: TMC4671.cpp:1840
void setGpioPins(uint8_t pins)
Definition: TMC4671.cpp:1808
int32_t getActualFlux()
Definition: TMC4671.cpp:2471
int16_t getTorque()
Definition: TMC4671.cpp:2036
bool encoderAligned
Definition: TMC4671.h:591
void setMotionMode(MotionMode mode, bool force=false)
Definition: TMC4671.cpp:1603
uint32_t lastStatTime
Definition: TMC4671.h:615
void setTargetPos(int32_t pos)
Definition: TMC4671.cpp:896
void setMotorType(MotorType motor, uint16_t poles)
Definition: TMC4671.cpp:2014
int32_t getPos() override
Definition: TMC4671.cpp:1887
void rampFlux(uint16_t target, uint16_t time_ms)
Definition: TMC4671.cpp:2066
bool checkAdc()
Definition: TMC4671.cpp:374
uint8_t spi_buf[5]
Definition: TMC4671.h:617
void setPwm(uint8_t val, uint16_t maxcnt, uint8_t bbmL, uint8_t bbmH)
Definition: TMC4671.cpp:2392
bool motorReady()
Definition: TMC4671.cpp:423
bool checkEncoder()
Definition: TMC4671.cpp:1167
void setGpioMode(TMC_GpioMode mode)
Definition: TMC4671.cpp:1774
void endSpiTransfer(SPIPort *port)
Definition: TMC4671.cpp:2540
void errorCallback(const Error &error, bool cleared)
Definition: TMC4671.cpp:3252
bool adcCalibrated
Definition: TMC4671.h:595
uint8_t enc_retry
Definition: TMC4671.h:612
void calibrateAenc()
Definition: TMC4671.cpp:1046
bool motorEnabledRequested
Definition: TMC4671.h:597
bool manualEncAlign
Definition: TMC4671.h:639
uint8_t enc_retry_max
Definition: TMC4671.h:613
void setHwType(TMC_HW_Ver type)
Definition: TMC4671.cpp:2692
void setTorqueFilter(TMC4671Biquad_conf &conf)
Definition: TMC4671.cpp:2236
void emergencyStop(bool reset)
Definition: TMC4671.cpp:1680
uint8_t getGpioPins()
Definition: TMC4671.cpp:1800
void turn(int16_t power)
Definition: TMC4671.cpp:1724
float getTemp()
Definition: TMC4671.cpp:349
std::pair< int32_t, int32_t > getActualTorqueFlux()
Definition: TMC4671.cpp:2461
int16_t getPhiE_Enc()
Definition: TMC4671.cpp:1150
void setup_HALL(TMC4671HALLConf hallconf)
Definition: TMC4671.cpp:1330
TMC_StartupType startupType
Definition: TMC4671.h:587
void setTmcPos(int32_t pos)
Definition: TMC4671.cpp:1882
uint32_t getEncCpr()
Definition: TMC4671.cpp:1573
void setFFMode(FFMode mode)
Definition: TMC4671.cpp:1980
void setTargetVelocity(int32_t vel)
Definition: TMC4671.cpp:912
void setupFeedForwardTorque(int32_t gain, int32_t constant)
Definition: TMC4671.cpp:1967
bool hasPower()
Definition: TMC4671.cpp:192
void registerCommands()
Definition: TMC4671.cpp:2842
void setPhiEtype(PhiE type)
Definition: TMC4671.cpp:1585
void estimateExtEnc()
Definition: TMC4671.cpp:2330
TMC4671(SPIPort &spiport, OutputPin cspin, uint8_t address=1)
Definition: TMC4671.cpp:49
void setOpenLoopSpeedAccel(int32_t speed, uint32_t accel)
Definition: TMC4671.cpp:1619
TMC4671Limits getLimits()
Definition: TMC4671.cpp:2137
void restoreFlash() override
Definition: TMC4671.cpp:145
void updateReg(uint8_t reg, uint32_t dat, uint32_t mask, uint8_t shift)
Definition: TMC4671.cpp:2530
void setup_ABN_Enc(TMC4671ABNConf encconf)
Definition: TMC4671.cpp:1289
void setAdcOffset(uint32_t adc_I0_offset, uint32_t adc_I1_offset)
Definition: TMC4671.cpp:1951
void setPwmMaxCnt(uint16_t maxcnt)
Definition: TMC4671.cpp:2425
bool estopTriggered
Definition: TMC4671.h:434
void setCpr(uint32_t cpr)
Definition: TMC4671.cpp:1920
void stopMotor()
Definition: TMC4671.cpp:1650
const Error communicationError
Definition: TMC4671.h:577
void setBiquadTorque(const TMC4671Biquad &filter)
Definition: TMC4671.cpp:2215
bool powerInitialized
Definition: TMC4671.h:594
void setBiquadFlux(const TMC4671Biquad &filter)
Definition: TMC4671.cpp:2152
uint32_t posToEnc(uint32_t pos)
Definition: TMC4671.cpp:1938
void Run()
Definition: TMC4671.cpp:427
StatusFlags readFlags(bool maskedOnly=true)
Definition: TMC4671.cpp:2549
void setUqUdLimit(uint16_t limit)
Definition: TMC4671.cpp:2102
std::pair< uint32_t, std::string > getTmcType()
Definition: TMC4671.cpp:1817
float getPwmFreq()
Definition: TMC4671.cpp:2416
void setAddress(uint8_t address)
Definition: TMC4671.cpp:93
void exti(uint16_t GPIO_Pin)
Definition: TMC4671.cpp:2599
void initAdc(uint16_t mdecA, uint16_t mdecB, uint32_t mclkA, uint32_t mclkB)
Definition: TMC4671.cpp:2444
TMC4671Biquad_conf torqueFilterConf
Definition: TMC4671.h:643
void setPosSel(PosSelection psel)
Definition: TMC4671.cpp:1755
void setPwmFreq(float freq)
Definition: TMC4671.cpp:2436
bool allowStateChange
Definition: TMC4671.h:609
void writeRegAsync(uint8_t reg, uint32_t dat)
Definition: TMC4671.cpp:2514
int16_t getPhiEfromExternalEncoder()
Definition: TMC4671.cpp:934
std::unique_ptr< TMC_ExternalEncoderUpdateThread > extEncUpdater
Definition: TMC4671.h:651
void setSvPwm(bool enable)
Definition: TMC4671.cpp:2403
void estimateABNparams()
Definition: TMC4671.cpp:2277
bool initialize()
Definition: TMC4671.cpp:244
bool flagCheckInProgress
Definition: TMC4671.h:539
bool initialized
Definition: TMC4671.h:593
TMC4671FlashAddrs flashAddrs
Definition: TMC4671.h:545
const ClassIdentifier getInfo()
Command handlers always have class infos. Works well with ChoosableClass.
Definition: TMC4671.cpp:87
void setFlux(int16_t flux)
Definition: TMC4671.cpp:2040
void setPidPrecision(TMC4671PidPrecision setting)
Definition: TMC4671.cpp:2113
EncoderType getEncoderType() override
Definition: TMC4671.cpp:1942
MotionMode nextMotionMode
Definition: TMC4671.h:585
int32_t getVelocity()
Definition: TMC4671.cpp:922
uint32_t readReg(uint8_t reg)
Definition: TMC4671.cpp:2488
int32_t getActualTorque()
Definition: TMC4671.cpp:2480
void setBiquadPos(const TMC4671Biquad &filter)
Definition: TMC4671.cpp:2173
void setAdcScale(uint32_t adc_I0_scale, uint32_t adc_I1_scale)
Definition: TMC4671.cpp:1959
StatusFlags statusFlags
Definition: TMC4671.h:540
bool findEncoderIndex(int32_t speed=10, uint16_t power=2500, bool offsetPhiM=false, bool zeroCount=false)
Definition: TMC4671.cpp:823
void setEncoder(std::shared_ptr< Encoder > &encoder) override
Definition: TMC4671.cpp:1848
uint32_t encToPos(uint32_t enc)
Definition: TMC4671.cpp:1935
void saveAdcParams()
Definition: TMC4671.cpp:135
void encoderInit()
Definition: TMC4671.cpp:1429
void setPositionExt(int32_t pos)
Definition: TMC4671.cpp:926
static TMC4671MotConf decodeMotFromInt(uint16_t val)
Definition: TMC4671.cpp:2614
void setTorqueLimit(uint16_t limit)
Definition: TMC4671.cpp:2107
OutputPin enablePin
Definition: TMC4671.h:574
static ClassIdentifier info
Definition: TMC4671.h:666
static bool isCreatable()
Definition: TMC4671.cpp:25
static bool isCreatable()
Definition: TMC4671.cpp:36
static ClassIdentifier info
Definition: TMC4671.h:675
uint32_t WaitForNotification(TickType_t Timeout=portMAX_DELAY)
Definition: thread.hpp:246
void Delay(const TickType_t Delay)
Definition: thread.hpp:352
SPIPort motor_spi
T clip(T v, C l, C h)
Definition: cppmain.h:58
static bool inIsr()
Definition: cppmain.h:41
u32 SystemCoreClock
bool Flash_Write(uint16_t adr, uint16_t dat)
bool Flash_Read(uint16_t adr, uint16_t *buf, bool checkempty=true)
void pulseClipLed()
Definition: ledEffects.cpp:49
void blinkClipLed(uint16_t period, uint16_t blinks)
Definition: ledEffects.cpp:61
void pulseErrLed()
Definition: ledEffects.cpp:44
static void * memcpy(void *dst, const void *src, size_t n)
Definition: ringbuffer.c:8
const char * name
uint32_t cmdId
SPI_InitTypeDef peripheral
Definition: SPI.h:38
bool cspol
CSPOL=true === active low.
Definition: SPI.h:37
int16_t phiEoffset
Definition: TMC4671.h:222
uint32_t cpr
Definition: TMC4671.h:215
bool ab_as_n
Definition: TMC4671.h:220
int16_t posOffsetFromIndex
Definition: TMC4671.h:224
bool latch_on_N
Definition: TMC4671.h:221
bool useIndex
Definition: TMC4671.h:225
int16_t phiMoffset
Definition: TMC4671.h:223
int16_t AENC0_scale
Definition: TMC4671.h:237
int16_t phiMoffset
Definition: TMC4671.h:234
int16_t nThreshold
Definition: TMC4671.h:244
uint16_t AENC0_offset
Definition: TMC4671.h:236
int16_t phiEoffset
Definition: TMC4671.h:233
int16_t AENC2_scale
Definition: TMC4671.h:241
uint32_t cpr
Definition: TMC4671.h:230
uint16_t AENC1_offset
Definition: TMC4671.h:238
int16_t phiAoffset
Definition: TMC4671.h:231
uint16_t AENC2_offset
Definition: TMC4671.h:240
int16_t nMask
Definition: TMC4671.h:243
int16_t AENC1_scale
Definition: TMC4671.h:239
TMCbiquadpreset mode
Definition: TMC4671.h:280
biquad_constant_t params
Definition: TMC4671.h:281
int32_t b2
Definition: TMC4671.h:276
int32_t b0
Definition: TMC4671.h:274
int32_t b1
Definition: TMC4671.h:275
int32_t a1
Definition: TMC4671.h:272
int32_t a2
Definition: TMC4671.h:273
TMC4671Biquad pos
Definition: TMC4671.h:311
TMC4671Biquad torque
Definition: TMC4671.h:309
TMC4671Biquad flux
Definition: TMC4671.h:310
TMC4671Biquad vel
Definition: TMC4671.h:312
uint16_t encA
Definition: TMC4671.h:201
uint16_t ADC_i0_ofs
Definition: TMC4671.h:207
uint16_t offsetFlux
Definition: TMC4671.h:202
uint16_t encOffset
Definition: TMC4671.h:209
uint16_t torqueFilter
Definition: TMC4671.h:211
uint16_t flux_p
Definition: TMC4671.h:205
uint16_t torque_p
Definition: TMC4671.h:203
uint16_t torque_i
Definition: TMC4671.h:204
uint16_t cpr
Definition: TMC4671.h:200
uint16_t flux_i
Definition: TMC4671.h:206
uint16_t ADC_i1_ofs
Definition: TMC4671.h:208
uint16_t mconf
Definition: TMC4671.h:199
int16_t phiEoffset
Definition: TMC4671.h:264
int16_t phiMoffset
Definition: TMC4671.h:265
int16_t pos120
Definition: TMC4671.h:260
uint16_t dPhiMax
Definition: TMC4671.h:266
int16_t pos0
Definition: TMC4671.h:258
int16_t pos60
Definition: TMC4671.h:259
uint16_t blank
Definition: TMC4671.h:257
bool direction
Definition: TMC4671.h:255
int16_t pos240
Definition: TMC4671.h:262
int16_t pos300
Definition: TMC4671.h:263
int16_t pos180
Definition: TMC4671.h:261
bool interpolation
Definition: TMC4671.h:254
uint16_t brakeLimLow
Definition: TMC4671.h:92
float fluxDissipationScaler
Definition: TMC4671.h:98
TMC_HW_Ver hwVersion
Definition: TMC4671.h:84
uint32_t pid_vel_lim
Definition: TMC4671.h:184
uint16_t pid_torque_flux
Definition: TMC4671.h:182
uint16_t pid_torque_flux_ddt
Definition: TMC4671.h:180
uint32_t pid_acc_lim
Definition: TMC4671.h:183
int32_t pid_pos_low
Definition: TMC4671.h:185
int32_t pid_pos_high
Definition: TMC4671.h:186
uint16_t pid_uq_ud
Definition: TMC4671.h:181
uint16_t adc_I1_offset
Definition: TMC4671.h:157
bool canChangeHwType
Definition: TMC4671.h:160
uint16_t pwmcnt
Definition: TMC4671.h:149
TMC4671MotConf motconf
Definition: TMC4671.h:148
uint32_t mclkB
Definition: TMC4671.h:155
uint8_t bbmH
Definition: TMC4671.h:151
uint8_t bbmL
Definition: TMC4671.h:150
uint16_t adc_I0_scale
Definition: TMC4671.h:158
TMC4671HardwareTypeConf hwconf
Definition: TMC4671.h:147
uint32_t mclkA
Definition: TMC4671.h:154
uint16_t mdecB
Definition: TMC4671.h:153
bool combineEncoder
Definition: TMC4671.h:162
uint16_t mdecA
Definition: TMC4671.h:152
uint16_t adc_I1_scale
Definition: TMC4671.h:159
uint16_t adc_I0_offset
Definition: TMC4671.h:156
bool enableFluxDissipation
Definition: TMC4671.h:164
bool encoderReversed
Definition: TMC4671.h:161
bool svpwm
Definition: TMC4671.h:77
MotorType motor_type
Definition: TMC4671.h:71
uint16_t pole_pairs
Definition: TMC4671.h:74
EncoderType_TMC enctype
Definition: TMC4671.h:72
PosSelection pos_sel
Definition: TMC4671.h:75
PhiE phiEsource
Definition: TMC4671.h:73
VelSelection vel_sel
Definition: TMC4671.h:76
bool sequentialPI
Definition: TMC4671.h:176
uint16_t positionP
Definition: TMC4671.h:175
uint16_t fluxP
Definition: TMC4671.h:169
uint16_t velocityI
Definition: TMC4671.h:172
uint16_t positionI
Definition: TMC4671.h:174
uint16_t fluxI
Definition: TMC4671.h:168
uint16_t velocityP
Definition: TMC4671.h:173
uint16_t torqueP
Definition: TMC4671.h:171
uint16_t torqueI
Definition: TMC4671.h:170
uint16_t freq
Definition: Filters.h:16
StatusFlags_s flags
Definition: TMC4671.h:141
uint32_t asInt
Definition: TMC4671.h:140
volatile uint8_t stage
Definition: usbh.c:265
int32_t getIntV()
int32_t getExtV()
void setVSenseMult(float vSenseMultiplier)