Skip to content
Christian edited this page Nov 21, 2023 · 8 revisions

General

The TMC2209 offer a UART interface, trough which the settings in the driver can be changed.

UART - wikipedia.org

UART uses normally 1 wire for transmitting (RX) and 1 wire for receiving (TX) and is therefore duplex capable.

UART Single Wire Interface

The TMC2209 stepper driver uses one Pin (PDN_UART) for UART RX and TX. So the PD_UART-Pin needs to be connected to the Raspberrry Pis RX-Pin directly and to the TX-Pin with an 1kOhm resistor. You can read more about this in the datasheet from Trinamic.

Because the TMC2209 use one shared pin for transmit and receive in the UART communication line, the Raspberry Pi also receives what it sends. Well, the Pi receives 4 bytes from itself and 8 bytes from the driver. So the Pi receives a total of 12 bytes and only the last 8 are the reply, of which only 4 are data bytes.

Datagram Structure

Write Access

0-63 (8 bytes)

function sync +
reserved
8 bit
slave addr
RW + 7 bit
reg addr
32 bit data CRC
bytes 0 1 2 3-6 7
bits 0-7 8-15 16-23 24-55 56-63

Read Access

0-31 (4 bytes)

function sync +
reserved
8 bit
slave addr
RW + 7 bit
reg addr
CRC
bytes 0 1 2 7
bits 0-7 8-15 16-23 56-63

Read Access Reply

0-63 (8 bytes)

function sync +
reserved
8 bit
master addr
RW + 7 bit
reg addr
32 bit data CRC
bytes 0 1 2 3-6 7
bits 0-7 8-15 16-23 24-55 56-63

The read response is sent to the master using address code %11111111

Example

The image shows in yellow the TX line of the Raspberry Pi, so the data, the Raspberry send to the TMC and in blue the signal on the RX line, everything the Raspberry Pi received. In this case it is a read access on the IOIN register.

TMC2209_UART_IOIN_Read
TMC2209_0: TEST UART
TMC2209: received 12 bytes; 96 bits
TMC2209: hex: 550006e805ff06210002419d
TMC2209: bin: 010101010000000000000110111010000000010111111111000001100010000100000000000000100100000110011101
TMC2209_0: length snd: 4
TMC2209_0: length rtn: 12
TMC2209_0: the Raspberry Pi received the sended bits and the answer from the TMC
TMC2209_0: the Raspberry Pi received exactly the bits it has send. the first 4 bits are the same
TMC2209_0: complete
TMC2209_0: 550006e8
TMC2209_0: 550006e805ff06210002419d
TMC2209_0: just the first 4 bits
TMC2209_0: 550006e8
TMC2209_0: 550006e8

the data send in HEX:

55 00 06 e8

the received data in HEX:

55 00 06 e8 05 ff 06 21 00 02 41 9d

The first 4 bytes can be ignored, since they are the ones, the Pi send itself.

So the reply datagram for the IOIN is this:

05 ff 06 21 00 02 41 9d

function sync +
reserved
8 bit
master addr
RW + 7 bit
reg addr
32 bit data CRC
bytes 0 1 2 3-6 7
example 05 ff 06 21 00 02 41 9d

the 4 data bytes 21 00 02 41 are in binary 00100001000000000000001001000001

table from the TMC2209 datasheet 0x06 IOIN Register:

Bit Input
0 ENN
1 0
2 MS1
3 MS2
4 DIAG
5 0
6 PDN_UART
7 STEP
8 SPREAD_EN
9 DIR
24-31 Version

So as an example the first received data bit is 1 and that means, that the ENN pin is on a HIGH level, which indicates, that the motor current output is disabled.

Source Code

The source code for the UART communication is in the TMC_2209_uart.py file

These arrays are being used for the UART communication bytes.

rFrame  = [0x55, 0, 0, 0 ]
wFrame  = [0x55, 0, 0, 0 , 0, 0, 0, 0 ]

Write Access

write_reg function

When a write access is done, the TMC driver does not return anything, so in order to check whether the access was successful the IFCNT register can be checked. THE IFCNT register is a counter for every successful write access. This is automatically checked in the write_reg_check function

self.wFrame[1] = self.mtr_id
self.wFrame[2] =  register | 0x80;  # set write bit
        
self.wFrame[3] = 0xFF & (val>>24)
self.wFrame[4] = 0xFF & (val>>16)
self.wFrame[5] = 0xFF & (val>>8)
self.wFrame[6] = 0xFF & val
        
self.wFrame[7] = self.compute_crc8_atm(self.wFrame[:-1])

Read Access

read_reg function

In a read access the CRC value of the reply datagram can be checked to verify the reply datagram. This is automatically done in the read_int function

self.rFrame[1] = self.mtr_id
self.rFrame[2] = register
self.rFrame[3] = self.compute_crc8_atm(self.rFrame[:-1])