Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tmc5160.py incorrectly calculates CS value to where it is always 31 #6644

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

HonestBrothers
Copy link

TMC5160.py incorrectly implements CS values to where they are always 31.

The calculation of globalscaler in current Klipper code leaves out the CS values, and then calculates CS after globalscaler.

According to page 74 of the datasheet, Calculation of RMS Current, the end result of not specifying a CS value, automatically sets the CS to 31.

(CS+1)/32 = 1.

In the current code, globalscaler is calculated and then CS is back calculated using globalscaler, but the only value it can be set to is 31, which the globalscaler calculation has already determined by setting it to 1.

Analog Devices is less than forthcoming on how to calculate the CS value, as the equation used on page 74 has two unknowns and thus can not be calculated. However, the tuning spreadsheet TMC220x_TMC222x_Calculations.xlsx allows us to back calculate the CS value:

cs = int(100 * (current * math.sqrt(2)) * self.sense_resistor) - int(1 - 2 * (current * math.sqrt(2)))

Implementing this bug fix allows us to effectively set the CS value before globalscaler, and then set globalscaler based on the chosen CS value. Which is how I believe Analog Devices intended this driver to be tuned. This has the end result of CS being used to effectively scale Rsense, ie. when the driver is rated for more currrent than is being used, Rsense does not need to be changed and instead CS can scale the Rsense input.

The practical issue is that the way Klipper currrently calculates CS makes the motors hard to tune on high amp 5160 drivers, and high voltages practically impossible on some motors because the chopper parameters can not be correctly set. Current word around town is that 2804's don't do well above 24V and will result in VFAs if used at 48V.

I have implemented this fix on my own device and am using 2804's at 60V, which run at a cool 65C. Before implementing the motors were very noisy and melted my motor mounts. Now they are regular level of 1980's printer noisy.

The CS value is calculated automatically so it requires no user input. This fix should allow better motor tuning, the calc sheet to be used effectively, and certain motor, voltage, driver combos to be used where they could not before.

I apologize ahead of time for errors. I don't program often, just took a whirl at fixing this issue. Also sorry for reopening this, I made a hot mess of the last one.

Signed off by: Brandon Smith honestbrotherstv@gmail.com

@HonestBrothers
Copy link
Author

To clarify:

This uses the tuning spreadsheet to calculate CS values versus globalscaler.

pg. 74 of the datasheet shows that Irms is calculated by the tmc5160:

Irms = (globalscaler/256) * ((CS+1)/32) * (Vfs/Rsense) * (1/sqrt(2))

This leaves us with one equation and two unknowns, which results in an unsolvable equation. The current code in Klipper then ignores the CS value and solves the above equation for global scaler:

globalscaler = int((current * 256. * math.sqrt(2.) * self.sense_resistor / VREF) + .5)

Effective what this does, since multiplying by 1 results in the same number that we started with, is sets ((CS+1)/32) = 1. This means that CS is 31.

Irms = (globalscaler/256) * ((31+1)/32) * (Vfs/Rsense) * (1/sqrt(2))

Irms = (globalscaler/256) * 1 * (Vfs/Rsense) * (1/sqrt(2))

Klipper then back calculates the CS value. The problem with this is the way the driver implements this is it uses BOTH CS and Globalscaler in the same equation. So we can't back calculate because those maths don't math. One equation, two unknown functions are unsolvable, we would need two equations for this.

@KevinOConnor
Copy link
Collaborator

As far as I am aware, the existing code is correct. (That is, it will faithfully take a requested run_current and program the tmc registers to meet that run_current as best as it can.)

If your drivers are running too hot, you should request a lower run_current.

If you feel the Klipper code is not correct it is best to start by reporting the problem as described at https://www.klipper3d.org/Contact.html . In particular, make sure you are running an unmodified version of Klipper, set an appropriate run_current, run SET_TMC_CURRENT STEPPER=stepper_x, run DUMP_TMC STEPPER=stepper_x, provide the full unmodified klippy log file in a new post to Klipper Discourse, and identify in that post what you feel the tmc registers should have been set to.

-Kevin

@KevinOConnor KevinOConnor added the pending feedback Topic is pending feedback from submitter label Jul 13, 2024
@HonestBrothers
Copy link
Author

HonestBrothers commented Jul 14, 2024

As far as I am aware, the existing code is correct. (That is, it will faithfully take a requested run_current and program the tmc registers to meet that run_current as best as it can.)

This is correct, to a degree. The existing code calculates the correct current, but does not use CS to do it, only globalscaler. This is unintentional, though. The code attempts to calculate CS, but only finds that it's already set to 31, because by not including CS when calculating globalscaler, we are setting CS to 31. The current is therefore correctly calculated, although not as correctly as it would be if it were to use CS to program it also.

Setting the current is a non-issue, as it is correctly (to a degree) set.

Edit: irun, hold, cs_actual are always 31 in the existing code.

The issue is that CS is not correctly set and is needed by the driver to set the chopper parameters. Otherwise, you end up with a chopper that doesn’t work correctly, noisy, hot motors, ect.

If your drivers are running too hot, you should request a lower run_current.

My motors were running hot because the chopper settings can not be correctly set, per the datasheet. The drivers are fine.

The motors were running at 120C before I implemented the code I have submitted. Once the chopper parameters are correctly set by my code changes, they run at 65-70C.

If you feel the Klipper code is not correct it is best to start by reporting the problem as described at https://www.klipper3d.org/Contact.html . In particular, make sure you are running an unmodified version of Klipper, set an appropriate run_current, run SET_TMC_CURRENT STEPPER=stepper_x, run DUMP_TMC STEPPER=stepper_x, provide the full unmodified klippy log file in a new post to Klipper Discourse, and identify in that post what you feel the tmc registers should have been set to.

-Kevin

This has been raised as an issue before on Discourse and was overlooked.
https://klipper.discourse.group/t/tmc5160-cs-and-vsense/4913

Please see the video for the practical implications of always setting the CS value to 31.
https://youtube.com/shorts/uOrz7uiaxrg?feature=share

I can submit a log file when my print is finished, along with dump_tmc, with the original code, and with my code changes. CS gets set to 31 on the current code, my code changes it to 22 based on my settings.

-Brandon

@HonestBrothers
Copy link
Author

This is the output from the dump_tmc stepper=stepper_x on the existing code:

4:36 AM TSTEP: 000fffff tstep=1048575 4:36 AM PWM_AUTO: 0000001d pwm_ofs_auto=29 4:36 AM PWM_SCALE: 0000001d pwm_scale_sum=29 4:36 AM OTP_READ: 0000000d otp_fclktrim=13 4:36 AM MSCURACT: 00f7000c cur_a=12 cur_b=247 4:36 AM MSCNT: 00000008 mscnt=8 4:36 AM LOST_STEPS: 00000000 4:36 AM IOIN: 30000050 drv_enn=1 sd_mode=1 version=0x30 4:36 AM FACTORY_CONF: 0000000d factory_conf=13 4:36 AM DRV_STATUS: 801f0000 cs_actual=31 stst=1 4:36 AM GSTAT: 00000005 reset=1(Reset) uv_cp=1(Undervoltage!) 4:36 AM CHOPCONF: 345007f3 toff=3 hstrt=7 hend=15 tpfd=5 mres=4(16usteps) intpol=1 dedge=1 4:36 AM GCONF: 00000008 multistep_filt=1 4:36 AM ========== Queried registers ========== 4:36 AM TPOWERDOWN: 0000000a tpowerdown=10 4:36 AM PWMCONF: c40c001e pwm_ofs=30 pwm_autoscale=1 pwm_autograd=1 pwm_reg=4 pwm_lim=12 4:36 AM DRV_CONF: 00000400 bbmclks=4 4:36 AM COOLCONF: 00000000 4:36 AM THIGH: 00000000 4:36 AM TCOOLTHRS: 00000000 4:36 AM TPWMTHRS: 000fffff tpwmthrs=1048575 4:36 AM MSLUTSTART: 00f70000 start_sin90=247 4:36 AM MSLUTSEL: ffff8056 w0=2 w1=1 w2=1 w3=1 x1=128 x2=255 x3=255 4:36 AM MSLUT7: 00404222 mslut7=4211234 4:36 AM MSLUT6: 49295556 mslut6=1227445590 4:36 AM MSLUT5: b5bb777d mslut5=3048961917 4:36 AM MSLUT4: fbffffff mslut4=4227858431 4:36 AM MSLUT3: 10104222 mslut3=269500962 4:36 AM MSLUT2: 24492929 mslut2=608774441 4:36 AM MSLUT1: 4a9554aa mslut1=1251300522 4:36 AM MSLUT0: aaaab554 mslut0=2863314260 4:36 AM IHOLD_IRUN: 00061f1f ihold=31 irun=31 iholddelay=6 4:36 AM GLOBALSCALER: 00000061 globalscaler=97 4:36 AM ========== Write-only registers ========== 4:36 AM dump_tmc stepper=stepper_x

This is the output with the proposed code changes:
4:40 AM TSTEP: 000fffff tstep=1048575 4:40 AM PWM_AUTO: 0000001d pwm_ofs_auto=29 4:40 AM PWM_SCALE: 00000014 pwm_scale_sum=20 4:40 AM OTP_READ: 0000000d otp_fclktrim=13 4:40 AM MSCURACT: 00f7000c cur_a=12 cur_b=247 4:40 AM MSCNT: 00000008 mscnt=8 4:40 AM LOST_STEPS: 00000000 4:40 AM IOIN: 30000050 drv_enn=1 sd_mode=1 version=0x30 4:40 AM FACTORY_CONF: 0000000d factory_conf=13 4:40 AM DRV_STATUS: 80160000 cs_actual=22 stst=1 4:40 AM GSTAT: 00000005 reset=1(Reset) uv_cp=1(Undervoltage!) 4:40 AM CHOPCONF: 345007f3 toff=3 hstrt=7 hend=15 tpfd=5 mres=4(16usteps) intpol=1 dedge=1 4:40 AM GCONF: 00000008 multistep_filt=1 4:40 AM ========== Queried registers ========== 4:40 AM TPOWERDOWN: 0000000a tpowerdown=10 4:40 AM PWMCONF: c40c001e pwm_ofs=30 pwm_autoscale=1 pwm_autograd=1 pwm_reg=4 pwm_lim=12 4:40 AM DRV_CONF: 00000400 bbmclks=4 4:40 AM COOLCONF: 00000000 4:40 AM THIGH: 00000000 4:40 AM TCOOLTHRS: 00000000 4:40 AM TPWMTHRS: 000fffff tpwmthrs=1048575 4:40 AM MSLUTSTART: 00f70000 start_sin90=247 4:40 AM MSLUTSEL: ffff8056 w0=2 w1=1 w2=1 w3=1 x1=128 x2=255 x3=255 4:40 AM MSLUT7: 00404222 mslut7=4211234 4:40 AM MSLUT6: 49295556 mslut6=1227445590 4:40 AM MSLUT5: b5bb777d mslut5=3048961917 4:40 AM MSLUT4: fbffffff mslut4=4227858431 4:40 AM MSLUT3: 10104222 mslut3=269500962 4:40 AM MSLUT2: 24492929 mslut2=608774441 4:40 AM MSLUT1: 4a9554aa mslut1=1251300522 4:40 AM MSLUT0: aaaab554 mslut0=2863314260 4:40 AM IHOLD_IRUN: 00061616 ihold=22 irun=22 iholddelay=6 4:40 AM GLOBALSCALER: 00000087 globalscaler=135 4:40 AM ========== Write-only registers ========== 4:40 AM dump_tmc stepper=stepper_x

klippy_log_code_corrected.txt
klippy_log_current_code.txt

@dmbutyugin
Copy link
Collaborator

Interesting. Let me share my 2 cents on the matter.

Reading TMC5160 datasheet, section 9 (rev 1.18) 'Selecting Sense Resistors' suggests that both CS and GLOBALSCALER affect the maximum current, and they both are used to scale the TMC sine wave table. FWIW, they both appear to be a software coefficients, meaning that they do not affect the current measurements done by the driver in any way, and therefore they do not affect the accuracy of the current measurements. That accuracy is ultimately determined by the R_sense resistor and the reference voltage V_SRT. Since most of the TMC5160 drivers are designed to drive high-current motors, using them to drive lower currents (e.g. ~1A) results in the lower accuracy stepping, regardless of how you adjust CS and GLOBALSCALER individually.

Now to your point: it does not seem that there is a 'correct way' to calculate the CS and GLOBALSCALER params. That is, they together must be set such that I_RMS is equal to the configured current. It is possible that CS has influence on other chopper parameters. However, the tmc5160_calculations.xlsx provided by trinamic uses CS=31 as the default to calculate the chopper parameters. So if anything, CS=31 seems to be a more appropriate and compatible choice that is already implemented in Klipper. Meaning that an average user that uses the spreadsheet from trinamic should get the best results with CS=31 implemented by Klipper.

Now as to why you may be getting the results that you are getting. Having chopper parameters out of tune may result in noisy stepper operation and excessive heat dissipation, as per trinamic datasheet. I see that you adjusted chopper parameters from their default values supposedly to better suite your stepper configuration. However, it may be that the specs published by the stepper manufacturer (especially inductance) may deviate from the actual stepper parameters, thus fine-tuning the chopper parameters using manufacturer specs may not produce good results. And since it does not appear that you re-tuned the chopper parameters for the updated CS value for your new code, you may have accidentally produced better chopper configuration with a different CS value (in your modified code you get CS=22 AFAICT). I would re-tune chopper parameters using the TMC spreadsheet with an updated CS value and see if you get the same (bad) results as with CS=31. Then separately I see you have TBL=0, which is not recommended due to higher noise in the current measurements (use at least TBL=1).

@HonestBrothers
Copy link
Author

Hello Dmitry, thanks for your feedback.

If you take a look at the HystStart_MIN formula in cell C3 of the tuning spreadsheet, you'll see that the formula provided by trinamic is:

HystStart_MIN = MAX(0.5+(Coil_Current_Drop)2248*(Current_Scale+1)/I_coil_Peak/32-8,-2)

This indicates that the CS value is directly used to calculate the hysteresis settings in the driver.

In my case, I am using two LDO 2804 motors paralleled together on one driver. The Thevenin equivalent for this circuit gives me .3mH, .35ohms, 5.6A peak current, 60V, 12MHz, TBL = 0, toff setting = 3.

  • The current Klipper implementation of the driver settings forces me use 31 as a CS value. This gives me a HystStart_MIN of 30, which is above the recommended limit and results in too low of chopper frequency. The recommended Rsense value is 0.035Ohm, which is above the Rsense currently installed on my driver. Reducing the Rsense will not help me reduce HystStart_Min.
  • My code sets CS to 22. This gives me a HystStart_Min of 20, which is within the recommended limits. The recommended Rsense value is 0.021Ohm, which is within +/- 3% of my actual Rsense on the BTT tmc5160T plus of 0.022Ohm.

Reading TMC5160 datasheet, section 9 (rev 1.18) 'Selecting Sense Resistors' suggests that both CS and GLOBALSCALER affect the maximum current, and they both are used to scale the TMC sine wave table. FWIW, they both appear to be a software coefficients, meaning that they do not affect the current measurements done by the driver in any way, and therefore they do not affect the accuracy of the current measurements.

Agreed. The current measurements performed by the driver are hardware only.

That accuracy is ultimately determined by the R_sense resistor and the reference voltage V_SRT. Since most of the TMC5160 drivers are designed to drive high-current motors, using them to drive lower currents (e.g. ~1A) results in the lower accuracy stepping, regardless of how you adjust CS and GLOBALSCALER individually.

The driver uses the R_sense, globalscaler, and CS to calculate the Irms as used by the software within the driver, per "Calculation of RMS current," pg. 74 of the datasheet. Mild inaccuracies will result by not correctly setting the CS value, but not enough to be noteworthy.

Now to your point: it does not seem that there is a 'correct way' to calculate the CS and GLOBALSCALER params. That is, they together must be set such that I_RMS is equal to the configured current. It is possible that CS has influence on other chopper parameters. However, the tmc5160_calculations.xlsx provided by trinamic uses CS=31 as the default to calculate the chopper parameters. So if anything, CS=31 seems to be a more appropriate and compatible choice that is already implemented in Klipper. Meaning that an average user that uses the spreadsheet from trinamic should get the best results with CS=31 implemented by Klipper.

The user will get the best results by setting the CS value to where it results in an Rsense that is +/-3% of the actual value of the user's preinstalled sense resistor. Alternatively the user may swap out their sense resistor, however in my application that still wouldn't help as it would result in inadequate hysteresis settings.

Regardless of all of this, the current Klipper code for the TMC5160 drivers unintentionally hard sets CS to 31. Everyone who is on Klipper and happens to use a tmc5160 driver has their CS set to 31. Systems of equations says we can't find non-zero variables from one equation with two unknowns, correct?

Now as to why you may be getting the results that you are getting. Having chopper parameters out of tune may result in noisy stepper operation and excessive heat dissipation, as per trinamic datasheet. I see that you adjusted chopper parameters from their default values supposedly to better suite your stepper configuration. However, it may be that the specs published by the stepper manufacturer (especially inductance) may deviate from the actual stepper parameters, thus fine-tuning the chopper parameters using manufacturer specs may not produce good results. And since it does not appear that you re-tuned the chopper parameters for the updated CS value for your new code, you may have accidentally produced better chopper configuration with a different CS value (in your modified code you get CS=22 AFAICT). I would re-tune chopper parameters using the TMC spreadsheet with an updated CS value and see if you get the same (bad) results as with CS=31. Then separately I see you have TBL=0, which is not recommended due to higher noise in the current measurements (use at least TBL=1).

I'm glad we can agree that the CS value needs to change and not be hard set to 31 otherwise it will result in poorly tuned steppers. Please see the attached spreadsheets, with my values prefilled. One sets CS to 31, the other sets it to 22. If you have ideas for how I can tune these more effectively I am all ears!

-Brandon, BSECE

@dmbutyugin
Copy link
Collaborator

I'm glad we can agree that the CS value needs to change and not be hard set to 31 otherwise it will result in poorly tuned steppers.

I'm sorry if my message sounded that way, this was not my intention. So far, I did not find any indications that the CS=31 value used by Klipper causes any problems. So, all I wanted to say is that if you do modify CS, you should calculate the chopper parameters accordingly. I just saw that in both of your logs you have

CHOPCONF: 345007f3 toff=3 hstrt=7 hend=15 tpfd=5 mres=4(16usteps) intpol=1 dedge=1 

so I assumed you didn't change these parameters between CS=31 and CS=22 values. However, if in practice you did, then good.

However,

Forgot to attach. TMC220x_TMC222x_Calculations_correctly_implemented_code.xlsx TMC220x_TMC222x_Calculations_current_klipper_code.xlsx

I'm unsure why you attached TMC22xx spreadsheets for calculations related to TMC5160. Are you using TMC22xx spreadsheet to calculate the parameters for TMC5160?

Separately,

In my case, I am using two LDO 2804 motors paralleled together on one driver.

I'm afraid this isn't a setup recommended for stepper motor drivers and I suspect it won't work well. If I am not mistaken, the only 'kind of recommended' way to connect two stepper motors to one driver is in series. This way, at least, the stepper motor driver can reliably measure the current that goes through the stepper motors coils. The parallel setup does not allow that.

@HonestBrothers
Copy link
Author

HonestBrothers commented Jul 14, 2024

I changed the CS value in both spreadsheets to demonstrate my point. The CS value in my instance, regardless of good practice, needs to be set to 22 to properly tune the chopper. Setting it to 31 results in inadequate hysteresis.

Klipper prohibits the CS value from changing from 31. Which is not intentional via the code. There is an attempt to calculate it, albeit implemented incorrectly.

`def_calc_globalscaler(self, current):

    globalscaler = int((current * 256. * math.sqrt(2.) #not including CS here sets it to 31 per pg. 74 in the datasheet.

                        * self.sense_resistor / VREF) + .5)
                        
    globalscaler = max(32, globalscaler)

    if globalscaler >= 256:

        globalscaler = 0

    return globalscaler

def _calc_current_bits(self, current, globalscaler):

    if not globalscaler:

        globalscaler = 256

    cs = int((current * 256. * 32. * math.sqrt(2.) * self.sense_resistor)

             / (globalscaler * VREF)

             - 1. + .5)`

This will always result in a value of 31. Why include the formula, why not just say cs=31?

Setting CS to 31 is the recommended ideal situation, as is setting Globalscaler to 256.

@dmbutyugin
Copy link
Collaborator

Yes, I understand where CS in Klipper comes from and why it gets 31. However, let me again stress my points:

  1. changing CS calculation in Klipper now will likely break all existing Klipper installations, because they were tuned, for the most part, assuming CS=31 value, as per default value in the spreadsheet that likely nobody modified;
  2. it is not immediately clear whether your improved results will transfer to other printers and setups.

In light of (1), it seems that the change in its current form is dangerous to merge. An alternative implementation would be to expose CS parameter in TMC stepper configuration, and add a command like TMC_ESTIMATE_CS STEPPER=<...> that would, based on the specified current parameters would recommend the best CS value. Then the user could specify that CS value in the spreadsheet, tune chopper parameters accordingly, and put that CS value together with the correctly tuned chopper parameters into the stepper config section.

In light of (2), it would be great to see more broad testing of this feature. Klipper Discourse may be a good starting point for such conversations.

Please do not take my message as discouragement of your work, and also note that I am not the one taking the ultimate call here. I'm merely providing my view on the matter, and I hope this can go into some positive direction. If anything, I'm also curious to test non-default CS values on my printer with TMC5160 drivers now.

@HonestBrothers
Copy link
Author

Agreed, merging in the form it's in would likely have wide ranging, negative consequences for existing driver settings. However, I'm not so sure that these consequences don't already exist by leaving it as it is in the current form.

I understand my situation is likely unique, and not recommended. I am pushing the TMC5160 to the limits, and really a tiny bit beyond them, as I'm sure you're aware from the spreadsheet. But nonetheless, situations do exist where this causes an issue.

Please do not take my message as discouragement of your work, and also note that I am not the one taking the ultimate call here. I'm merely providing my view on the matter, and I hope this can go into some positive direction. If anything, I'm also curious to test non-default CS values on my printer with TMC5160 drivers now.

I appreciate the discussion, not discouraged, just trying to defend my case.

I will raise the issue on Discourse and see if I can get some input. Let me know the results of your testing.

@HonestBrothers
Copy link
Author

Updated:

I added a field called tmc_cs: which can be called under:

[tmc5160 stepper_*]
tmc_cs: some number between 16 and 31

Code needs cleaning up. If no tmc_cs is defined, it will default to 31.

@KevinOConnor
Copy link
Collaborator

The existing code calculates the correct current, but does not use CS to do it, only globalscaler. This is unintentional, though.

It is very much intentional. The code was specifically written to maximize the value of IRUN (aka CS).

The trinamic specifications can be esoteric, arcane, and difficult to read. On close inspection, though, it is clear that a low IRUN value can reduce the precision of its sine wave table. That is, the stepper drivers set a particular stepper position by altering the current through the two stepper motor coils (different coil currents thus control the stepper shaft angle). The trinamic drivers can use this same mechanism to lower the overall current through both coils, and this is what IRUN does. However, if IRUN is low enough, then it ultimately impacts the precision of each stepper motor microstep position.

All of the trinamic drivers have a mechanism to set the current outside of IRUN - tmc2130/tmc2209 use VSENSE, tmc5160/tmc2240 use GLOBALSCALER. On all drivers, Klipper attempts to set the requested current while maximizing the IRUN (or CS) value. This is purposely done to maximize the microstep precision. This is also, as near as I can tell from the tmc specs, the recommendation from Trinamic.

If you have some unusual setup that requires special fields, then you can use the SET_TMC_FIELD command to set the field to whatever value you need. You can issue these commands in your homing macros or use a delayed_gcode config section to run it at startup. For what it is worth, though, it seems odd that you would tune to a lower IRUN value as I don't recall seeing a recommendation from Trinamic to ever purposely use a lower IRUN.

-Kevin

@HonestBrothers
Copy link
Author

HonestBrothers commented Jul 16, 2024

Hey Kevin,

I created a thread on Discourse on the topic to discuss further.

https://klipper.discourse.group/t/tmc5160-py-hard-sets-cs-to-31-causing-chopper-hysteresis-issues/17655

The existing code calculates the correct current, but does not use CS to do it, only globalscaler. This is unintentional, though.

It is very much intentional. The code was specifically written to maximize the value of IRUN (aka CS).

The code just sets IRUN to 31 in every instance of tmc5160 Klipper. It doesn't calculate it. I am unsure why we would include _calc_current_bits, if the goal were to just set CS=31. It is not mathematically possible to arrive at any value other than CS=31 in the current implementation.

The trinamic specifications can be esoteric, arcane, and difficult to read. On close inspection, though, it is clear that a low IRUN value can reduce the precision of its sine wave table. That is, the stepper drivers set a particular stepper position by altering the current through the two stepper motor coils (different coil currents thus control the stepper shaft angle). The trinamic drivers can use this same mechanism to lower the overall current through both coils, and this is what IRUN does. However, if IRUN is low enough, then it ultimately impacts the precision of each stepper motor microstep position.

All of the trinamic drivers have a mechanism to set the current outside of IRUN - tmc2130/tmc2209 use VSENSE, tmc5160/tmc2240 use GLOBALSCALER. On all drivers, Klipper attempts to set the requested current while maximizing the IRUN (or CS) value. This is purposely done to maximize the microstep precision. This is also, as near as I can tell from the tmc specs, the recommendation from Trinamic.

Agreed, simply put the datasheet leaves a lot to be desired.
The datasheet recommends IRUN be between 16-31, and globalscaler above 128. Although, pg. 62 mentions IRUN being as low as 8. IRUN should ideally be as high as possible, as should globalscaler. Auto setting this to 31 causes hysteresis issues in some motors, regardless of voltage and correctly chosen drivers/Rsense.

By leaving this value at 31 and choosing microstep precision, excessive heat, resonance (which causes worse precision, but I digress), and decreased torque is being invited in. In addition, it prevents chopper parameters from being tuned.

@KevinOConnor
Copy link
Collaborator

It is not mathematically possible to arrive at any value other than CS=31 in the current implementation.

That is incorrect. For low run_current requests, the GLOBALSCALER will be set to its minimum (32) and then IRUN will be reduced to best meet the requested current.

It's actually, unfortunately, a bit common. Some extruder setups need a very low current that can only be obtained by configuring both a low GLOBALSCALER and low IRUN setting.

By leaving this value at 31 and choosing microstep precision, excessive heat, resonance (which causes worse precision, but I digress), and decreased torque is being invited in.

I don't believe that to be correct. As I understand it, VSENSE and GLOBALSCALER are effectively used to scale the sense_resistor, while IRUN is effectively used to scale the sine wave table. I haven't seen anything that indicates scaling the sine wave table is a fundamentally better way to manage torque, heat, nor resonance. (Nor that they are even directly related.)

-Kevin

@HonestBrothers
Copy link
Author

HonestBrothers commented Jul 16, 2024

Kevin,

Klipper uses a single equation to find two non-zero unknowns. This is a mathematical impossibility.

This is the subject of linear algebra.
https://en.m.wikipedia.org/wiki/System_of_linear_equations

https://en.m.wikipedia.org/wiki/Underdetermined_system

@dmbutyugin
Copy link
Collaborator

Just a small notice on:

I don't believe that to be correct. As I understand it, VSENSE and GLOBALSCALER are effectively used to scale the sense_resistor, while IRUN is effectively used to scale the sine wave table.

Unfortunately, the datasheet does not speak very clearly about GLOBALSCALER, however it says
"Hint: Choose sense resistors in a way, that normal IRUN is 16 to 31 for best microstep performance."
and for GLOBAL SCALER
"... This value is multiplied to the current scaling to adapt a drive to a certain motor type. This value should be chosen before tuning other settings because it also influences chopper hysteresis.
...
Hint: Values >128 recommended for best results"

and

"Fine-tune the current to the specific motor via the 8-bit GLOBALSCALER. Situation specific motor current adaptation is done by 5-bit scalers (actual scale can be read via CS)"

and then the formulae for I_RMS suggest that both GLOBALSCALER and CS are equivalent. Meaning that we don't get better microstepping by configuring higher CS and lower GLOBALSCALER. Just that CS can be modified by the driver itself (e.g. if IHOLD != IRUN, the driver will choose CS based on the current operation mode).

And @HonestBrothers, in light of that message "This value should be chosen before tuning other settings because it also influences chopper hysteresis." for GLOBALSCALER, I think you are mistaken to think that if you adjust CS and keep GLOBALSCALER larger, you will get different hysteresis parameters. Basically, TMC spreadsheet simply does not account for the existence of GLOBALSCALER and assumes it is set to 0 (==256, full scale).

@HonestBrothers
Copy link
Author

HonestBrothers commented Jul 17, 2024

@dmbutyugin

And @HonestBrothers, in light of that message "This value should be chosen before tuning other settings because it also influences chopper hysteresis." for GLOBALSCALER, I think you are mistaken to think that if you adjust CS and keep GLOBALSCALER larger, you will get different hysteresis parameters.

Do we know what the hysteresis settings are based on? There are indications that some parameters, PWM_SCALE_SUM pg. 63 for instance, only uses CS_ACTUAL in it's calculations. I know this is for stealthchop, but we are given very limited information about spreadcycle.

You may very well be right about my tuning, but implementing this in the way in which it's implemented uses a lot of assumptions...

Basically, TMC spreadsheet simply does not account for the existence of GLOBALSCALER and assumes it is set to 0 (==256, full scale).

Back calculating CS after setting Globalscaler results in CS never changing. The other way around is as defined in the spreadsheet, doesn't result in an underdetermined situation, and scales both CS and Globalscaler.

Also,
"Fine-tune the current to the specific motor via the 8-bit GLOBALSCALER. Situation specific motor current adaptation is done by 5-bit scalers (actual scale can be read via CS)"

This speaks to me to set CS first, then get a more exact Irms with Globalscaler.

@HonestBrothers
Copy link
Author

@KevinOConnor

That is incorrect. For low run_current requests, the GLOBALSCALER will be set to its minimum (32) and then IRUN will be reduced to best meet the requested current.

Try to calculate any of the values from the spreadsheet using a Globalscaler set to 32. Set global scaler to 32, CS to 31, then solve the equation on pg 74 using an Rsense found in one of the TMC5160 drivers.
If we do this for the step sticks 0.075ohm , we find that Irms is 0.38A. Plug a ~0.38A stepper into the spreadsheet, including values for L and R that would be reasonable for a 0.38A motor, Googling gives me a 7.4mH and 17ohms for a 0.5A motor. Plug those into the spreadsheet. Change CS to match +/-3% or the Rsense, we find that CS needs to be set to 2 or 3. It would likely be even lower on a 0.38A motor.

@KevinOConnor KevinOConnor removed the pending feedback Topic is pending feedback from submitter label Jul 17, 2024
@dmbutyugin
Copy link
Collaborator

Do we know what the hysteresis settings are based on? There are indications that some parameters, PWM_SCALE_SUM pg. 63 for instance, only uses CS_ACTUAL in it's calculations. I know this is for stealthchop, but we are given very limited information about spreadcycle.

I do not know, the documentation is very limited. The available information, however, suggests that GLOBALSCALER and CS behave the same way, just GLOBALSCALER has higher resolution and can only be changed via SPI, and CS has lower resolution, but can be adjusted by the driver itself based on other settings (like IRUN and IHOLD).

So, instead of focusing too much on Klipper 'incorrect behavior' (which, again, is correct, just does not match your desired behavior), try to take the chopper parameters you tuned for supposedly lower CS value and pass them to mainline Klipper without any changes in the code, and see if they will behave the same way as on modified Klipper. Then you can test for yourself whether reducing GLOBALSCALER and CS has the same effect on chopper parameters or not.

@KevinOConnor
Copy link
Collaborator

KevinOConnor commented Jul 17, 2024

Meaning that we don't get better microstepping by configuring higher CS and lower GLOBALSCALER.

The tmc specs can be obtuse and confusing. However it is clear that IRUN (and CS) scale the microstep table. All the specs (tmc2130, tmc2660, tmc2240, and tmc5160) have some variant of:

IRUN
Current scale when motor is running. Scales coil
current values as taken from the internal sine
wave table. For high precision motor operation,
work with a current scaling factor in the range 16
to 31, because scaling down the current values
reduces the effective microstep resolution by
making microsteps coarser. This setting also
controls the maximum current value set by
CoolStep.

Similarly, although we don't get a lot of details on how GLOBALSCALER is actually implemented, we do know it replaced VSENSE in tmc2130 (and similar) drivers. In the tmc2130 spec:

vsense
sense resistor voltage based current scaling

0: Low sensitivity, high sense resistor voltage
1: High sensitivity, low sense resistor voltage

So, I think there is good reason to believe both VSENSE and GLOBALSCALER are implemented using a separate mechanism from IRUN (and CS).

Further, from the description of HEND we get a glimpse of how hysteresis, the sine table, and IRUN interact. It seems the math is something like: dac_output = ((sine_table_entry * IRUN) >> 5) + hysteresis. (Where dac_ouput would then be routed, along side the voltage from the sense resistor, to an analog comparator which controls the current chopper.) This is speculation, of course, but it is what I got by "reading between the lines" of the spec.

Cheers,
-Kevin

EDIT: Just to be clear, it's the integer operation of ((sine_table * IRUN) >>5) that introduces the "coarseness". For example, an IRUN of 1 would reduce the precision of the default sine table (values 0..248) to a much lower precision (values 0..7). There is no indication that GLOBALSCALER (nor VSENSE) introduce that type of digitalization artefact.

@KevinOConnor
Copy link
Collaborator

KevinOConnor commented Jul 17, 2024

Also, FYI, CS and IRUN are the same thing - you can see this in the tmc2660 spec:

CS
Current scale. Scales both coil current values as
taken from the internal sine wave table or from
the SPI interface. For high precision motor
operation, work with a current scaling factor in
the range 16 to 31, because scaling down the
current values reduces the effective microstep
resolution by making microsteps coarser. This
setting also controls the maximum current value
set by coolStep™.

Which is an identical description of IRUN in newer drivers. It seems that when tmc introduced IHOLD they decided to rename CS to IRUN, but it's clearly the same thing (at least when the motor is moving, when the motor is not moving then CS would be equal to IHOLD).

-Kevin

@dmbutyugin
Copy link
Collaborator

So, I think there is good reason to believe both VSENSE and GLOBALSCALER are implemented using a separate mechanism from IRUN (and CS).

Further, from the description of HEND we get a glimpse of how hysteresis, the sine table, and IRUN interact. It seems the math is something like: dac_output = ((sine_table_entry * IRUN) >> 5) + hysteresis. (Where dac_ouput would then be routed, along side the voltage from the sense resistor, to an analog comparator which controls the current chopper.) This is speculation, of course, but it is what I got by "reading between the lines" of the spec.

If this were the case (chopper parameters depend only on CS but not on GLOBALSCALER), then it may make sense to expose CS as a configuration option for the drivers. At the very least, TMC spreadsheet clearly uses CS as an input in the calculations - by default it is set to 31 there, but changing it modifies recommended HSTRT and HEND values. So it can happen that for certain combinations of motors and drivers the default CS=31 will produce recommended values for HSTRT and HEND outside of the permitted range (and modifying TBL and TOFF parameters does not bring them to the permitted range). At least I can attest that under some conditions the TMC spreadsheet will not produce valid recommendations for chopper parameters with CS=31 (as it happens for tmc5160 driver, LDO-42STH48-2804 stepper motor, running at 48 volts).

This is why I asked @HonestBrothers to test the chopper parameters optimized for CS < 31 on the default Klipper code. If they happen to work well the same way as with Klipper modified to compute different CS values - then I believe no modifications to Klipper code are necessary. If they will not work, perhaps the configuration option should be made available. Though I agree that reducing CS (as, IRUN/IHOLD) is suboptimal due to the loss of microstepping precision, so it should be consider a 'power option' for the users understanding what they are doing. Alas, I cannot reproduce the problem on my hardware - I do have a printer with tmc5160 drivers, and I can produce chopper parameters for CS=31 and reduced CS (projected from GLOBALSCALER value), however I do not observe noticeable difference in steppers performance for both sets of parameters.

@dmbutyugin
Copy link
Collaborator

@HonestBrothers look, there is no question that CS can be calculated differently. You are missing the point: Klipper calculates CS and GLOBALSCALER in a specific way (such as to maximize CS while keeping GLOBALSCALER in the valid range). The question is, is it an optimal approach? From microstepping precision standpoint - yes, it is the best we can do. The only question remains is, are there any other considerations where it may be suboptimal? The only argument I can think of is that maybe it is not good for chopper performance. However, optimizing CS such that recommended RSense matches the actual RSense clearly is not the right approach - I honestly don't see any reason for that. Like, maybe one possibility would be to maximize CS such that the chopper parameters are still in the valid range - but I don't see putting such code into Klipper - it would be on user to fiddle with various chopper parameters anyway to arrive to the best possible combination for TOFF, TBL and CS for the given stepper. This is why if you could test your good working chopper parameters on default Klipper, that would be great, we'd at least have some data point whether CS modifications are necessary at all. Otherwise, we go in circles on this discussion, I'm afraid.

@HonestBrothers
Copy link
Author

HonestBrothers commented Jul 18, 2024

@dmbutyugin

Edit: Sineos coming in with pg 111

I understand the reasoning behind wanting to maintain the resolution, but I believe the datasheet gives us parameters recommended to maintain the resolution, CS > 16, Globalscaler > 128. It appears like the instantaneous motor current is calculated with both CS and Globalscaler, but I'm not confident Globalscaler is used in hysteresis calcs. Hand calculating with CS that is tuned via the spreadsheet and whatever Globalscaler gets set to does arrive at a more precise Irms, as would be expected.

I can not get the spreadsheet to produce valid hysteresis results using a CS of 31. I can not get Klipper to produce a result for CS other than 31. I am not aware of anyone having a CS of a value other than 31, and I believe this to be because of the faux pas.

The result, for me at least, is the spreadsheet says to use fast decay only. Using CS=31, I end up with a Globalscaler of 97, below the recommended min of 128. No settings for hysteresis will get me anywhere near acceptable settings via the spreadsheet.

If I change CS, I can get the acceptable hysteresis settings, lower motor temps, and it seems to have reduced some artifacts that I thought were from belts, but now I'm not so sure. This is anecdotal though. The only thing now is Rsense is higher than what I have on the driver in the spreadsheet. If my understanding is correct, if I change the Rsense to a slightly higher value, CS and Globalscaler will increase to a more acceptable value, too.

HystStart_MIN is 27, needs to be under 22, when using a CS of 31.

I will see if I can get some more measurable testing data.

@HonestBrothers
Copy link
Author

HonestBrothers commented Jul 18, 2024

Section 9.1 (I realize this is 2209, I'm assuming it works the same way).

CS scales the VREF used in the chopper comparators. So if 5160 works this way, 100% leaving CS at 31 leads to poor chopper performance. CS is used as a way to scale Rsense.

https://www.analog.com/media/en/technical-documentation/data-sheets/tmc2209_datasheet_rev1.09.pdf

@Sineos
Copy link
Collaborator

Sineos commented Jul 18, 2024

TMC5160 spec, page 74
grafik

TMC5160 spec, page 111
grafik

Wouldn't these two pieces of information indicate that:

  • GLOBALSCALER is a "one time thing" used for "globally" setting the run_current according to the specification of the stepper motor. With a properly chosen hardware RSENSE, it would be 256 (fully scale). The more the stepper driver max current (as dictated by the hardware RSENSE) deviates from the real max current demand of the connected stepper, the lower GLOBALSCALER gets.
  • After this "global scaling", IRUN or IHOLD take over (summarized as CS) and do the actual "in operation" scaling. They should, in the ideal case, scale between 16 and 31, which is the equivalent of VSENSE=1 in the older driver generations
  • "Tuning" according to the spread sheet is done from a GLOBALSCALER=256 perspective and thus you should aim for
    grafik
  • The resulting CS value then gives you an indication of how much "fine-grained control" is left

So, what is done in our reality today, is basically doing all this "backwards":

  • The hardware RSENSE mostly does not fit to the connected stepper, e.g. a LDO-36STH17-1004AHG (Peak: 0.35 A) vs RSENSE=0.075 (Peak: 3.42 A)
  • Parameters in the spread-sheet are tuned until you halfway match the RSENSE value in C46, which typically leads to very bad hysteresis values and a very low CS

@HonestBrothers
Copy link
Author

HonestBrothers commented Jul 18, 2024

So, what is done in our reality today, is basically doing all this "backwards":

  • The hardware RSENSE mostly does not fit to the connected stepper, e.g. a LDO-36STH17-1004AHG (Peak: 0.35 A) vs RSENSE=0.075 (Peak: 3.42 A)
  • Parameters in the spread-sheet are tuned until you halfway match the RSENSE value in C46, which typically leads to very bad hysteresis values and a very low CS

This is 100% my understanding of this datasheet, since we are not choosing Rsense. There is nothing preventing the end user from swapping Rsense to better match their motors. Keeping CS=31 does however prevent the user from matching their motors to the drivers.

There are certain circumstances where keeping CS=31 just prevents the lowering of hysteresis values enough to be usable. 2804s at 48V could work perfectly at CS=22, Rsense=0.075, which are the step sticks. If we keep CS=31 and the user swaps out their Rsense to to match the 0.114 output in C46, they will still have too high of hysteresis.

Implementing changes to code should probably cap the users ability to adjust CS lower than 16. If they reach this case they need to change RSense or buy a different driver.

@HonestBrothers
Copy link
Author

@Sineos is the flow chart assuming Rsense was correctly chosen so that max current flows at or slightly above CS=31?

This datasheet has too many holes.

@HonestBrothers
Copy link
Author

@KevinOConnor @dmbutyugin

I'd just like to reiterate:

  1. There is nothing to gain by leaving CS at 31. Per the Imot calculation on pg 74, both Globalscaler and CS will cause resolution loss of the lookup table. If anything, including CS as a scalable value results in a more precise Irms and Imot.
  2. Leaving CS=31 leaves constrained hysteresis availability, causing some motor, driver, voltage combos to be unusable.
  3. You can't back calculate the CS value from Globalscaler. This causes the equation to be an underdetermined system. Meaning it's a fundamental violation of linear algebra.

@Sineos
Copy link
Collaborator

Sineos commented Jul 19, 2024

is the flow chart assuming Rsense was correctly chosen so that max current flows at or slightly above CS=31?

Heh, you are asking the wrong person here. I'm just trying to interpret the spec and this chapter has the heading "Current Settings and First Steps" and actually it makes sense for me to set the desired maximum current at startup to the upper limit of the scaling range.

For me the key aspects in the spec are:

Page 36

grafik

Page 38

grafik

Page 52

grafik

Page 62

grafik

Page 74

grafik

Page 75 (complementary to page 36 and 38)

grafik

grafik

Page 111

The "Quick Configuration Guide"

Summary

FWIW, this is just the basics. There are so many dependencies, like running Stealth Chop or Spread Cycle etc, that I'm far from claiming to understand them.
However, my understanding is that giving users the ability to tune IRUN might actually be a bad idea, since it seems easy to violate some relevant limits (e.g. page 62) or to start running the stepper out of at least half-optimal settings. This in turn could lead to problems or quality defects that would be almost impossible to diagnose.

IMO, it would be much more worthwhile if OEMs producing such drivers would stop chasing the next marketing award and offer e.g. 3 lines of TMC5160s or TMCs in general:

  • Low Current (up to 1.2A for pancake and extruder steppers),
  • Medium Current (e.g. up to 2.5A for regular motion steppers),
  • High Current for anyone who needs it.

The number of printer designs that use NEMA34 steppers seems somewhat limited. (Hint @bigtreetech)

Edit and side note:

Almost every electrical/electronic device that has any kind of control or conversion functionality (even a "stupid" toroidal transformer) has an optimal operating point that is usually neither at the low end nor at the high end of its range. Leaving this point leads to artifacts, low efficiency, excess heat, etc.
Also, the TMCs seem to start doing funky things when the current gets too low. See https://klipper.discourse.group/t/bug-stealtchop-ignoring-run-current-setting/13877 for an example.

What might actually be interesting, if Klipper had a CSACTUAL monitoring (spec page 92) to see what is happening during regular printer operation. I do not know if this would be feasible, as it also seems to appear only in relation to CoolStep.

@HonestBrothers
Copy link
Author

HonestBrothers commented Jul 19, 2024

@Sineos

Part of problem is, the current code doesn't switch CS until Globalscaler hits 32. This violates best results you show from pg 36. Even if we changed that limit of 32 to 128, I don't believe the code will behave in the way Trinamic intended due to my point 3 in my last comment. Imot uses both CS and Globalscaler.

Also, the TMCs seem to start doing funky things when the current gets too low. See https://klipper.discourse.group/t/bug-stealtchop-ignoring-run-current-setting/13877 for an example.

For me changing CS to a lower value helped reduce the heat and decrease artifacts.

@HonestBrothers
Copy link
Author

@dmbutyugin doing some testing today, I can actually get that audible resonance during printing by changing IRUN. I'll see if I can get a video of it.

Copy link

github-actions bot commented Aug 5, 2024

Thank you for your contribution to Klipper. Unfortunately, a reviewer has not assigned themselves to this GitHub Pull Request. All Pull Requests are reviewed before merging, and a reviewer will need to volunteer. Further information is available at: https://www.klipper3d.org/CONTRIBUTING.html

There are some steps that you can take now:

  1. Perform a self-review of your Pull Request by following the steps at: https://www.klipper3d.org/CONTRIBUTING.html#what-to-expect-in-a-review
    If you have completed a self-review, be sure to state the results of that self-review explicitly in the Pull Request comments. A reviewer is more likely to participate if the bulk of a review has already been completed.
  2. Consider opening a topic on the Klipper Discourse server to discuss this work. The Discourse server is a good place to discuss development ideas and to engage users interested in testing. Reviewers are more likely to prioritize Pull Requests with an active community of users.
  3. Consider helping out reviewers by reviewing other Klipper Pull Requests. Taking the time to perform a careful and detailed review of others work is appreciated. Regular contributors are more likely to prioritize the contributions of other regular contributors.

Unfortunately, if a reviewer does not assign themselves to this GitHub Pull Request then it will be automatically closed. If this happens, then it is a good idea to move further discussion to the Klipper Discourse server. Reviewers can reach out on that forum to let you know if they are interested and when they are available.

Best regards,
~ Your friendly GitIssueBot

PS: I'm just an automated script, not a human being.

@HonestBrothers
Copy link
Author

HonestBrothers commented Aug 28, 2024

Edit: Changed naming conventions, and changed CS to allow 0.

I updated the code:

  1. driver_cs: -1
    Sets the system to auto-calculate
  2. driver_cs: 0-30
    Lets the user choose the tmc_cs value
  3. driver_cs: not defined or 31
    Default condition.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants