Socket CAN Sending Incorrect Messages

I have a Jetson Orin Dev and I have successfully run CAN sends via command line and I have used python socketCAN to communicate with my CAN interfaces on my MIT mini cheeta style motors. When I attempt to use the cantransmit.c example with socketcan on C my frame reads incorrectly on my scope and my motors cannot read the message as they do not send back their return state frame.

My CAN setup file is as follows.

Close any CAN buses that are up

sudo ip link set down can0
sudo ip link set down can1

set pins for CAN

sudo busybox devmem 0x0c303000 32 0x0000C400
sudo busybox devmem 0x0c303008 32 0x0000C454
sudo busybox devmem 0x0c303010 32 0x0000C400
sudo busybox devmem 0x0c303018 32 0x0000C454

sudo modprobe can
sudo modprobe can_raw
sudo modprobe mttcan
sudo ip link set can0 type can bitrate 1000000 sjw 4 dbitrate 1000000 berr-reporting on fd on
sudo ip link set can1 type can bitrate 1000000 sjw 4 dbitrate 1000000 berr-reporting on fd on
sudo ip link set up can0
sudo ip link set up can1

#show bus status
ip link show dev can0
ip link show dev can1

open terminal and show CAN messages

candump -ta -x -c -c can0 can1
exec bash

I have physically connected my can0 and can1 buses to act as a loopback.

When I run cansend can0 00B#FFFFFFFFFFFFFFFD
I receive
(1738266282.439201) can0 TX - - 00B [8] FF FF FF FF FF FF FF FD
(1738266282.439231) can1 RX - - 00B [8] FF FF FF FF FF FF FF FD
(1738266282.439335) can0 RX - - 00B [6] 0B 7F B2 80 57 FF
(1738266282.439320) can1 RX - - 00B [6] 0B 7F B2 80 57 FF

Good message. Scope is clean and matches the message.

I have modified the address and message in the cantransmit.c to the following

include <stdio.h>
include <stdlib.h>
include <string.h>
include <unistd.h>

include <net/if.h>
include <sys/ioctl.h>
include <sys/socket.h>

include <linux/can.h>
include <linux/can/raw.h>

int main(int argc, char **argv)
{
int s;
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame frame;

printf("CAN Sockets Demo\r\n");

if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
    perror("Socket");
    return 1;
}

strcpy(ifr.ifr_name, "can0" );
ioctl(s, SIOCGIFINDEX, &ifr);

memset(&addr, 0, sizeof(addr));
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;

if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
    perror("Bind");
    return 1;
}

frame.can_id = 0x00B ; 
frame.can_dlc = 8;

unsigned char message[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD};

memcpy(frame.data, message, sizeof(message));

if (write(s, &frame, sizeof(struct can_frame)) != sizeof(struct can_frame)) {
    perror("Write");
    return 1;
}

if (close(s) < 0) {
    perror("Close");
    return 1;
}
return 0;

}

The Command line returns

(1738265246.860569) can0 TX B E 00B [8] FF FF FF FF FF FF FF FD
(1738265246.860597) can1 RX B E 00B [08] FF FF FF FF FF FF FF FD

There are B and E flags which I believe to be Base and Extended CAN ID flags which I believe to be conflicting.

The Scope reads

Note the DLC is 7 not 8 and the first nibble in the message is 1 not F, the last byte has been pushed out of the dlc length.
It is my current theory that the motor is reading the same as the scope as the motor does not send back an acknowledgement.

I believe my hardware to be setup correctly as I can run can with the CL and python.

Has anyone successfully verified socketcan on the jetson orin? What setup code has worked? I have followed the available Nvidia setup guide to my knowlege.

Turns out the struct can_frame provided by Linux has certain padding frames set high by default.

In my case the good message from command line was:
frame: 0B 00 00 00 08 00 00 00 FF FF FF FF FF FF FF FD

The bad from c:
frame: 0B 00 00 00 08 FF 00 00 FF FF FF FF FF FF FF FD

To fix this,
struct can_frame frame;

frame.can_id = 0x00B ; //set ID
frame.len = 8; // set dlc the dlc was depreciated

frame.__pad=0x00; // SET PADDING TO 0X00

I used the following code to print out the complete CAN messages including padding.

include <stdio.h>
include <stdlib.h>
include <string.h>
include <unistd.h>

include <net/if.h>
include <sys/ioctl.h>
include <sys/socket.h>

include <linux/can.h>
include <linux/can/raw.h>

int main(int argc, char **argv)
{
int s, i;
int nbytes;
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame frame;

printf("CAN Sockets Receive Demo 1: \r\n");

if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
    perror("Socket");
    return 1;
}

strcpy(ifr.ifr_name, "can0" );
ioctl(s, SIOCGIFINDEX, &ifr);

memset(&addr, 0, sizeof(addr));
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;

if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
    perror("Bind");
    return 1;
}

printf("Socket Descriptor: %d\n", s);

nbytes = read(s, &frame, sizeof(struct can_frame));

if (nbytes < 0) {
    perror("Read");
    return 1;
}

printf("0x%03X [%d] ",frame.can_id, frame.can_dlc);

for (i = 0; i < frame.can_dlc; i++)
    printf("%02X ",frame.data[i]);

printf("\r\n");

if (close(s) < 0) {
    perror("Close");
    return 1;
}


printf("frame: ");
unsigned char *frame_ptr = (unsigned char *)&frame;
for (int i = 0; i < sizeof(struct can_frame); i++) {
    printf("%02X ", frame_ptr[i]);
}
printf("\n");

return 0;

}

Hi westjeremy6,

What’s the Jetpack version in use?

Could you share the block diagram of your connections with your motor?

It seems the issue is specific to your CAN application since it works as expected if you use cansend to send data.
Is cantransmit.c written by you?

Have you managed to get it work?

I have managed to get everything to run smoothly as intended. My bug has been resolved.

My jetpack version is 6.0+b106 .

My testing setup is as follows.

cantransmit.c is a common test file for testing the socketcan c package. I found it included in a git repo to test motors. You can find cantransmit.c here.
https://github.com/craigpeacock/CAN-Examples

I modified the address and message to make the lowest level motor controller I could for debugging purposes.

My problem lied in the provided can.h dependency of socketcan provides a struct can_frame.

https://docs.kernel.org/networking/can.html

This frame has ID,DLC, message, and padding bytes.

My problem was one of these padding bytes __pad was set high instead of low and this caused the candump to read off the B and E flags, confused the scope, and stopped the motor from recognizing the message. After sending several unreceivable messages, the bus would fill with traffic and this would crash the bus.

The solution is to set the padding frame low.

struct can_frame frame;

frame.__pad = 0x00; //set padding low

frame.can_id = 0x00B ; //set ID
frame.len = 8; //set dlc

CAN send uses low bytes for padding by default so that is why it works with no issues but using c socketcan it will fail. I hope this can save someone a few days of debugging time :)

1 Like

Nice work! Thanks for sharing the root cause about socketcan with that padding byte.