# SPI to RS485 - The following protocol applies to firmware V4.1 or later - Send the AT+VER serial command to check the firmware version; if no version is returned or it shows V33, please update to the latest firmware - The SANPO Motor Debug Tool can generate test code quickly and supports CAN/RS485 motors ## Protocol Overview | Use Case | Wiring | TX Protocol (SPI->RS485) | RX Protocol (RS485->SPI) | | --- | --- | --- | --- | | RS485 motors (fixed 23-byte frames) | CS1 controls RS485-1/RS485-2; CS2 controls RS485-3/RS485-4 | Transparent, fixed length 23 bytes. Last 3 bytes reserved: last is CRC, second last is valid data length, third last is Channel. | Transparent, fixed length 23 bytes. Last 3 bytes reserved: last is CRC, second last is valid data length, third last is Channel. | - The first two bytes of RS485 frames must not be the reserved headers 0x45 0x54, 0x41 0x54, or 0x53 0x54 ### Frame Examples TX frame | RS485 data passthrough (pad to 20 bytes with 0x00) | Channel | Data length | CRC (1 byte) | | --- | --- | --- | --- | | 0x22 0x33 0x00 0x53 0x54 0x00 0x53 0x54 0x00 0x53 0x54 0x00 0x53 0x54 0x00 0x53 0x54 0x00 0x00 0x00 | 0x00 | 0x17 | 0x0F | RX frame | RS485 feedback passthrough | Channel | Data length | CRC (1 byte) | | --- | --- | --- | --- | | 0x22 0x33 0x00 0x53 0x54 0x00 0x53 0x54 0x00 0x53 0x54 0x00 0x53 0x54 0x00 0x53 0x00 0x00 0x00 0x00 | 0x00 | 0x16 | 0x0F | ### Code Snippet (SPI to RS485, Python) Full example: spi_unitree_GO_M8010_demo_v4.py ```python # TX: motor command data (<=20 bytes, pad with 0x00) + Channel + Data length + CRC def build_spi_rs485_frame(cmd: bytes, channel: int) -> bytes: data_bytes = bytearray(cmd[:20]) data_len = len(data_bytes) if data_len < 20: data_bytes.extend([0x00] * (20 - data_len)) payload = bytes(data_bytes) + bytes([channel & 0xFF, data_len]) crc = crc8_calculator.calculate(payload) return payload + bytes([crc]) # fixed length 23 bytes tx = build_spi_rs485_frame(cmd, channel=0x00) rx = spi.xfer2(list(tx)) # fixed length 23 bytes # RX parse: CRC check + read valid data length data_part = rx[:22] crc_ok = crc8_calculator.calculate(data_part) == rx[22] data_len = rx[21] motor_data = rx[:data_len] ``` ## Examples - SPI to RS485 example (Python): Download - SPI uses fixed 23-byte frames by default