SANPO SPI to CAN

SANPO SPI to CAN lets a Jetson, Raspberry Pi, or another host controller operate classic CAN devices periodically. The host sends a fixed-length SPI message containing a CAN ID and data and reads device feedback during the current or a later transfer.

For CAN FD, see SANPO SPI to FDCAN.

SPI Settings

Item

Setting

SPI mode

Mode 0 (CPOL=0, CPHA=0)

Bit order

MSB First

SHORT

22-byte message area + 1-byte CRC, 23 bytes total

LONG

72-byte message area + 1-byte CRC, 73 bytes total

CRC-8

Polynomial 0x07, initial value 0x00, no final XOR

Factory default is SHORT. Classic CAN works in both SHORT and LONG, but use SHORT for lower overhead when CAN FD is not required.

Switch modes over USB serial:

AT+SPIMODE=SHORT
AT+SPIMODE=LONG

Send the command as text with a CRLF line ending. The setting is saved. After success, wait at least 10 ms before starting transfers with the new length.

Select a CAN Channel

SPI chip select

Channel

Target

First MCU

0x01

CAN-1

First MCU

0x02

CAN-2

Second MCU

0x03

CAN-3

Second MCU

0x04

CAN-4

Either chip select

0x00

Both CAN interfaces on the current MCU

Internally, 1/3 select the first local interface and 2/4 select the second. Replies only use local Channel 1/2.

Software CS0 and CS1 on a Linux host normally connect to the board’s two external chip selects. Confirm actual wiring rather than relying only on software numbering.

SHORT Message

Extended Frame

Byte position

Content

0 to 1

Fixed 45 54 (ET)

2

Channel

3 to 6

29-bit CAN ID, most significant byte first

7

Data length 0 to 8

8 to 15

8-byte data area; fill unused bytes with 00

16 to 21

00

22

CRC-8 over the first 22 bytes

Standard Frame

Byte position

Content

0 to 1

Fixed 53 54 (ST)

2

Channel

3 to 4

Fixed 00 00

5 to 6

11-bit CAN ID, most significant byte first

7

Data length 0 to 8

8 to 15

8-byte data area; fill unused bytes with 00

16 to 21

00

22

CRC-8 over the first 22 bytes

For Channel 1, extended ID 0x0000FD01, and 8 data bytes, the 22 bytes before CRC are:

45 54 01 00 00 FD 01 08 01 02 03 04 05 06 07 08 00 00 00 00 00 00

LONG Message

The first 8 bytes match SHORT. Bytes 8 to 71 form a fixed 64-byte data area, and byte 72 is CRC-8. Classic CAN uses only the first 0 to 8 data bytes; fill the rest with 00.

Type

Bytes 0 to 7

Bytes 8 to 71

Byte 72

Extended

ET + Channel + ExtID(4B) + Len

64-byte data area

CRC-8

Standard

ST + Channel + 00 00 + StdID(2B) + Len

64-byte data area

CRC-8

Calculate CRC

def crc8(data: bytes) -> int:
    crc = 0
    for value in data:
        crc ^= value
        for _ in range(8):
            crc = ((crc << 1) ^ 0x07) & 0xFF if crc & 0x80 else (crc << 1) & 0xFF
    return crc

Calculate over the first 22 bytes for SHORT or the first 72 bytes for LONG and place the result in the final byte.

Read CAN Feedback

SPI is full duplex. Data read while sending a command may be older cached feedback or all 00. If the target reply is not immediately available, continue sending all-zero frames of the current length.

A valid reply has:

  • The total length required by the active SHORT/LONG mode.

  • A correct CRC in the final byte.

  • A message area beginning with 45 54 or 53 54.

  • Local Channel 01 or 02.

  • The valid CAN data length in byte 7.

One SPI read is not a fixed response to one request. Match feedback by CAN ID and device protocol.

Examples

Troubleshooting

Symptom

Action

Received data is all 00

No feedback is queued; wait briefly and send another empty frame

CRC fails

Check Mode 0, MSB First, fixed length, SPI clock, and chip-select timing

CAN device does not reply

Check chip select, Channel, CAN ID, bitrate, termination, wiring, and power

Frame is sent on both CAN interfaces

Channel is 00; select a specific channel

No response after switching to LONG

The host is still sending 23 bytes; send exactly 73 bytes per transfer