Tmc2209 V1.3 Confusion and more confusion

MCU: Raspberry pi pico

Hello, I am interested in using this driver but I have doubts, I don’t know how to connect the clock pin and if klipper would recognize it, also every time I look for a config for this I see this:

[tmc2209 stepper_x]
uart_pin: gpio9
tx_pin: gpio8

tx from what I saw it also needs a 1k resistor… but I don’t understand which pin the uart_pin would go on and if it needs a 1k resistor

I looked for the manufacturer’s configuration and found this… and it confused me more… because two pins would go to the same pin if the rx and tx pins exist in the driver as you can see in the image above

Furthermore, the information available is from a driver with the previous version…

In regards to the 1k resistor between the TX and RX line, this is a current sink that prevents the TX line from being back driven when the TMC2209 is driving the PDN_UART line. It’s a very standard approach to wiring two unidirectional serial lines to a single pin bidirectional serial interface.

I’m a bit puzzled by the need for this approach as well. When I look at different boards, this 1k current sink is used sometimes and in others, a single pin is used and its connected directly to the PDN_UART pin of the TMC driver.

My understanding is that the two pins and resistor are not required because:
a) Klipper uses bit-banging code for UART operations so the pin selected does not matter
b) Klipper changes the pin operation between input and output as required by the next communications operation

I wondered if it was a Marlin issue, but it Marlin seems to handle boards like the M8P (which has a single line going to each TMC2209 driver) just fine.

I also wondered if it was a single UART line to multiple differently addressed (using the MS#_ADR# pins) TMC2209s, but that doesn’t seem to make sense.

Please correct me if I’m wrong, but shouldn’t @Mago3D be able to run with:

uart_pin: gpio9

and not bother with the tx_pin: gpio8 line all together?

Can anybody explain? I half expect that the answer is that the first boards that were designed to communicate with the TMC220x (probably the TMC2208) did it this way and people just carried on with it.

As far as my understanding goes, this is a protocol trick to distinguish between receiving and sending on just one pin.
The resistor is needed to act as a pull-up when the TMC has “nothing to say”. Now Klipper would switch the MCU pin to output and send something. When done with sending, Klipper switches the pin back to input and the TMC takes over to drive the line and to send this response.
Once the TMC is done, it again “switches off” its sending mode (= TX pull the line high via the pull-up) and would be ready to read the next instructions.
If there is only 1 line from PDN_UART to the MCU, then the driver would be in “write access only” mode.

This is my very rough understanding, and I happily stand corrected. Also see https://www.analog.com/media/en/technical-documentation/data-sheets/TMC2202_TMC2208_TMC2224_datasheet_rev1.14.pdf#page=20

and https://www.analog.com/media/en/technical-documentation/data-sheets/TMC2202_TMC2208_TMC2224_datasheet_rev1.14.pdf#page=5
→ THREE MODES OF OPERATION

That’s not a correct.

As I indicated before, the MCU TX output connected to the MCU RX input with a 1k (or whatever value) resistor with the MCU RX line connected to a device’s bidirectional pin simply allows the MCU TX to remain in output mode (ie driving) when the device’s bidirectional pin is in output mode and not have the MCU TX pin (or the device’s bidirectional pin) being backdriven.

As I said above, this is a very common way of combining two unidirectional serial IOs into one bidirectional line.

Again, my question is, based on my understanding of how Klipper’s generic (any pin) TMC serial communications, is there any reason why a single MCU pin can’t be used for the TMC220x “uart” pin when communicating with multiple TMC220x chips, each given a different address in a Main Controller Board running Klipper?

Again, as noted above, when I look at boards like the Manta M#P, there is a single IO pin serially communicating with a single socketed TMC220x but when there is multiple TMC220x chips built onto the board there are two separate TX and RX lines combined to provide a single bidirectional communications line that is connected to, with addressing, to each of the chips’ PDN_UART lines.

I suspect that this is the same situation as my question last week about the end stops capacitor; there doesn’t seem to be any legitimate need for it now, just that it was wired that way in the past and designers haven’t been willing to investigate whether or not it is still valid or required.

I have found one reference stating that a single wire is required (no TX/RX and 1k resistor) for using a UART interface with TMC220x on a RAMPS board.

https://www.reddit.com/r/klippers/comments/tbl30n/tmc2209_on_ramps/

Based on my understanding, this is not correct. TX is effectively not used in the sense of transmitting data but only to indicate if the TMC is in receiving state or sending state. This is also kind of backed up by the TMC spec:

This seems also to align with what Marlin is doing, e.g.

  #define X_SERIAL_TX_PIN  PC13
  #define X_SERIAL_RX_PIN  PC13

  #define Y_SERIAL_TX_PIN  PE3
  #define Y_SERIAL_RX_PIN  PE3

or Klipper’s documentation:

But as stated before, I’m not an expert here but for me, your explanation does not add up to the rest of the information.

I read them both, understood some things, thank you very much, so I tried doing this;
connect this like this:

image

result:

image

So
image

After that there were no conflicts at least with the cfg, but I didn’t connect them yet, I just saved the cfg because I wanted to know what they thought…

If you have this up, could you comment out tx_pin: gpio14 in the second case with just uart_pin: gpio15?

This is the single TMC2209 use case.

I’ll try this on my Pico and respond to the comment written by @Sineos with this test result.

If I mention the tx line I would be working with a single cable as the reference says, and I think that in that case I would need the resistance… (I’m assuming)

https://www.klipper3d.org/Config_Reference.html?h=tmc2209#tmc2209

I run with the single wire solution and this TMC config (example):

[tmc2209 stepper_x]
uart_pin: PB3
uart_address: 0
interpolate: True
run_current: 1.15
stealthchop_threshold: 999999 # 0 or 200

How many TMC2209s connected serially are in the board?

What are the values for each of their uart_address: lines?

Four to one UART line and each one coded for the address.
And no serial connection, just parallel.

1 Like

I’m starting to build my own boards for that reason I first want to test everything before starting to put various motors.

In my case it is literally this, nothing has changed yet:

Thanx for clarifying - that’s not the case we’re looking for here.

You have separate lines for TX/RX on the TMC2209 module - these are normally shorted together.

In your case, as confirmed by @EddyMI3D you can have a single line (defined as a uart_pin: going to pin 4 (TX) at the side of the module or the UART pin at its end.

1 Like

What we’re talking about here is implementing two unidirectional communication lines in a device to a single bidirectional communications line on another device.

In the device with two unidirectional communications lines, one is a “TX” line which is always driving an output and one is an “RX” line which is always an input. I don’t know if it’s obvious to people but when the TX line is driving out a value there should never be another driver from another device connected directly to it.

The problem in this case is what happens when the two drivers are outputting different values - the output pin driving a high voltage level is sourcing current to the output pin sinking current to provide the low voltage. This is called “backdriving” and the actual voltage on the line is considered to be “indeterminate” - it is possible, if one driver is much stronger than the other, that one of the output pins will be damaged due to the other pin sourcing/sinking more current than it is designed for.

The most common way to avoid backdriving is to place a resistor between the two outputs. When the outputs are at different voltage levels, a small amount of current will flow, much less than there would be in the case previously where there was no resistor.

This is what was done, back in the day when only Arduinos were available as 3D printer Main Controller Boards, so that the MCU’s “TX” pin would not backdrive the TMC stepper driver’s PDN_UART pin when the PDN_UART was driving a value out.

By connecting the MCU’s “RX” pin to the side of the resistor connected to the TMC stepper driver’s PDN_UART pin, the value received by the “RX” pin would either be “TX” pin’s output (when a command was being sent by the MCU) or from the TMC stepper driver’s PDN_UART pin when it is sending requested information.

This is illustrated here:

In Cases 1 and 2, the MCU is driving and the Device’s IO pin is in a high impedance (“HighZ”) state so it is not driving the line. The RX pin reads what’s on the TX pin.

Case 3 has both the MCU and the Device are both driving a “High” voltage so, even if there was not a resistor between them, there would be no backdriving.

Case 4 shows what happens when the MCU’s TX pin and the Device’s pin are driving different voltage levels. The actual voltage read at “RX” is what is coming out of the Device’s IO pin and current is passing through the 1k resistor so there is no significant (or possibly damaging) backdriving of the MCU’s TX pin.

You could say the 1k resistor “allows” the Device’s IO pin to override the MCU’s TX pin and you’d get part marks on an electrical engineering exam.

Going back to the question at hand, I took an SKR Pico board, loaded it with Klipper, set up the default printer.cfg and then commented out the tx_pin: lines as so (I should note that I brought up the [mcu] and [printer] statements to the top of the file and added [include mainsail.cfg] but made no other changes):

# This file contains common pin mappings for the BIGTREETECH SKR Pico V1.0
# To use this config, the firmware should be compiled for the RP2040 with
# USB communication.

# The "make flash" command does not work on the SKR Pico V1.0. Instead,
# after running "make", copy the generated "out/klipper.uf2" file
# to the mass storage device in RP2040 boot mode

# See docs/Config_Reference.md for a description of parameters.

[include mainsail.cfg]

[mcu]
serial: /dev/serial/by-id/usb-Klipper_rp2040_45503571290FAAA8-if00

[printer]
kinematics: cartesian
max_velocity: 300
max_accel: 3000
max_z_velocity: 5
max_z_accel: 100

[stepper_x]
step_pin: gpio11
dir_pin: !gpio10
enable_pin: !gpio12
microsteps: 16
rotation_distance: 40
endstop_pin: ^gpio4
position_endstop: 0
position_max: 235
homing_speed: 50

[tmc2209 stepper_x]
uart_pin: gpio9
# tx_pin: gpio8
uart_address: 0
run_current: 0.580
stealthchop_threshold: 999999

[stepper_y]
step_pin: gpio6
dir_pin: !gpio5
enable_pin: !gpio7
microsteps: 16
rotation_distance: 40
endstop_pin: ^gpio3
position_endstop: 0
position_max: 235
homing_speed: 50

[tmc2209 stepper_y]
uart_pin: gpio9
# tx_pin: gpio8
uart_address: 2
run_current: 0.580
stealthchop_threshold: 999999

[stepper_z]
step_pin: gpio19
dir_pin: gpio28
enable_pin: !gpio2
microsteps: 16
rotation_distance: 8
endstop_pin: ^gpio25
position_endstop: 0.0
position_max: 250

[tmc2209 stepper_z]
uart_pin: gpio9
# tx_pin: gpio8
uart_address: 1
run_current: 0.580
stealthchop_threshold: 999999

[extruder]
step_pin: gpio14
dir_pin: !gpio13
enable_pin: !gpio15
microsteps: 16
rotation_distance: 33.500
nozzle_diameter: 0.400
filament_diameter: 1.750
heater_pin: gpio23
sensor_type: EPCOS 100K B57560G104F
sensor_pin: gpio27
control: pid
pid_Kp: 21.527
pid_Ki: 1.063
pid_Kd: 108.982
min_temp: 0
max_temp: 250

[tmc2209 extruder]
uart_pin: gpio9
# tx_pin: gpio8
uart_address: 3
run_current: 0.650
stealthchop_threshold: 999999

[heater_bed]
heater_pin: gpio21
sensor_type: ATC Semitec 104GT-2
sensor_pin: gpio26
control: pid
pid_Kp: 54.027
pid_Ki: 0.770
pid_Kd: 948.182
min_temp: 0
max_temp: 130

[fan]
pin: gpio17

[heater_fan heatbreak_cooling_fan]
pin: gpio18

[heater_fan controller_fan]
pin: gpio20

[temperature_sensor pico]
sensor_type: temperature_mcu

[neopixel board_neopixel]
pin: gpio24
chain_count: 1
color_order: GRB
initial_RED: 0.3
initial_GREEN: 0.3
initial_BLUE: 0.3

#[bltouch]
#sensor_pin: gpio22
#control_pin: gpio29

#[filament_switch_sensor runout_sensor]
#switch_pin: ^gpio16

and everything works fine.

When researching this, I did find my discussion with Kevin on this in November of '22:

So I did remember correctly - Klipper does not require hardware UARTs for communicating with TMC220x stepper drivers and, by doing so, can act dynamically as an input or an output pin.

In you highlighted screenshot of the Klipper documentation:

I’m noting the “If” at the start of the sentence. “separate receive and transmit lines to communicate” are NOT REQUIRED.

As for what Marlin does - as I said I found one reference indicating that a single line could be used for communications but I also found the same information in the configuration.h and configuration_adv.h files as you put in. Regardless, we’re talking about Klipper here.

So, to net things out, in Klipper only the uart: line (and no tx_pin: line) is required in the printer.cfg for serial communications with TMC stepper drivers, whether there is a separate “uart” line for each TMC stepper driver in the system or if there are multiple TMC stepper drivers, each with a different address.

This should probably go into the Knowledge Base as it’s useful for anybody using a main controller board with TMC220x that are being interfaced with serially or for someone like @Mago3D who is designing their own hardware.

1 Like

Thanks for the in-depth answer and TBH I’m not sure if we are talking about something different or if we are agreeing on the same but use different wording.

  1. I agree that Klipper is not using hardware UART and as far as I can see, I never maintained the position it would.

  2. I think we agree that Klipper uses a single pin for the communication and toggles this pin between being an output when it wants to write to the driver, respectively an input when it wants to read from the driver

  3. I assume that Klipper actually mostly writes to the driver via UART and I’m not really sure if it ever reads from the driver (maybe only on a DUMP_TMC command?). Likely it will also read status messages and command ACKs.

  4. Where we might be disagreeing (or not?) is that I interpret the resistor rather as some kind of pullup that is used to signal if the driver “has nothing to say” (= driven high by the TMC = I’m just chilling my driver life) or if he wants to say something and tries to motivate Klipper to listen by pulling it low.

I would very much appreciate it if someone (@koconnor?) who really knows would redeem us :laughing:

  1. Yes.

  2. Yes. (When only “uart_pin” is configured. When both “tx_pin” and “uart_pin” are configured then tx_pin is used solely for transmit and “uart_pin” is used solely for receive.)

  3. No - Klipper regularly reads from the driver (even more frequently than writes).

  4. No - it’s as Myke describes. When using both tx_pin and uart_pin, the resistor is needed on the “tx_pin” so that the “uart_pin” can actually read the data from the driver’s pdn_uart pin when it is transmitting. (If the resistor were not there, the tx_pin output would interfere with the pdn_uart transmissions and the uart_pin wouldn’t be able to reliably receive the information.) This is all very confusing, because on almost all hardware there is no reason to use a “tx_pin” when using Klipper. (If, however, one chooses to configure both tx_pin and uart_pin in Klipper, then Klipper will only transmit on tx_pin and only receive on uart_pin, and never change the orientation of either of those two pins.)

To the original question asked here - if you’re designing a board for use with Klipper, it’s probably simpler to only wire one pin to the driver (wire uart_pin to pdn_uart). I can’t speak to other firmware though.

Hope that helps,
-Kevin

3 Likes

And again, thanks a lot. Learned something new (again) :+1:

@mykepredko, you won that point. On to the next :joy:

1 Like

Thank you very much, for now I will use 2 pins, uart_pin to pdn_uart and tx to tx; Then I’ll do the resistance thing because I’ll save a pin with that…
Still I have doubts

  1. Why is the “clk” pin not supported? or is it because it is no longer necessary…

Thank you very much for creating klipper, it changed my way of working for the better.

clk_pin is not used with the TMC2209

https://www.klipper3d.org/Config_Reference.html#tmc2209

1 Like