# SANPO USB to CAN SANPO USB to CAN lets a Windows or Linux serial application control classic CAN devices. The host adds a Channel around the CAN ID and data, and the board converts between USB serial and CAN. For CAN FD, see [SANPO USB to FDCAN](usb_fdcan). To use Linux `canX`, `cansend`, `candump`, or `python-can` directly, see [SocketCAN](socketcan). ## Connection and Setup A complete board normally exposes two USB serial ports. One accesses CAN-1/2, and the other accesses CAN-3/4. `COM` or `/dev/ttyACM*` numbering may not follow board silkscreen order. For first use, connect one CAN device to identify the mapping. 1. Open the USB serial port for the target MCU. 2. Send `AT+SETFDCAN?` to query CAN settings. 3. If needed, change them as described in [Communication Settings](baudrate_config). Classic CAN uses the first bitrate parameter. 4. Send complete frames from this page in hexadecimal or binary mode. USB is a virtual serial port. The serial bitrate selected in the host application does not change the CAN bus speed. If older software changed the USB CAN format, send `AT+ET` as text with a `CRLF` line ending. After receiving `OK`, the format on this page is active. This is normally unnecessary after power-up. ## Select a CAN Channel | Current USB port | Channel | Target | | --- | --- | --- | | Port for CAN-1/2 | `0x01` | CAN-1 | | Port for CAN-1/2 | `0x02` | CAN-2 | | Port for CAN-3/4 | `0x03` | CAN-3 | | Port for CAN-3/4 | `0x04` | CAN-4 | | Either USB port | `0x00` | Both CAN interfaces on the current MCU | Internally, `1/3` select the first local interface and `2/4` select the second. Use the whole-board numbers above so host configuration matches board silkscreen. Replies use local numbering: `0x01` for the first interface and `0x02` for the second. CAN-3 feedback therefore appears as Channel 1 on the second USB port. ## CAN Extended Frame Transmit and receive use the same format: | Field | Length | Description | | --- | ---: | --- | | Header | 2 bytes | Fixed `45 54` (`ET`) | | Channel | 1 byte | CAN interface number | | CAN ID | 4 bytes | 29-bit extended ID, most significant byte first | | Data length | 1 byte | `0` to `8` | | CAN data | 0 to 8 bytes | Must match the length field | | Tail | 2 bytes | Fixed `0D 0A` | Send 8 bytes to extended ID `0x0000FD01` on Channel 1: ```text 45 54 01 00 00 FD 01 08 01 02 03 04 05 06 07 08 0D 0A ``` ## CAN Standard Frame | Field | Length | Description | | --- | ---: | --- | | Header | 2 bytes | Fixed `53 54` (`ST`) | | Channel | 1 byte | CAN interface number | | Reserved | 2 bytes | Fixed `00 00` | | CAN ID | 2 bytes | 11-bit standard ID, most significant byte first | | Data length | 1 byte | `0` to `8` | | CAN data | 0 to 8 bytes | Must match the length field | | Tail | 2 bytes | Fixed `0D 0A` | Send 4 bytes to standard ID `0x142` on Channel 2: ```text 53 54 02 00 00 01 42 04 11 22 33 44 0D 0A ``` ## CyberGear Example Example: [USB to CAN CyberGear](https://gitcode.com/sanpo/robot/blob/unified-main/products/spine/v6/demo/can/usb2can_cybergear_demo_v6.py) Windows: ```powershell python usb2can_cybergear_demo_v6.py --port COM8 --motors 1 --channel 1 ``` Linux: ```bash sudo python3 usb2can_cybergear_demo_v6.py --port /dev/ttyACM0 --motors 1 --channel 1 ``` Update the serial port, interface, and motor ID to match the wiring. ## Troubleshooting | Symptom | Action | | --- | --- | | No USB serial port | Check the USB cable, driver, control power, and reconnect the board | | Device does not reply | Check USB port mapping, Channel, CAN ID, bitrate, termination, wiring, and power | | Frame is sent on both CAN interfaces | Channel is `0x00`; select a specific channel | | Reply Channel is 1/2 instead of board 3/4 | Replies use local numbering; this is normal | | Reply format differs from this page | Send `AT+ET` as text, wait for `OK`, and retry |