How to get CAN working on JetPack 4.3+

Prashant Dandriyal
6 min readNov 30, 2022

It is not for him to pride himself who loveth his own country, but rather for whom who loveth the whole world. ~Bahá’u’lláh

Photo by Pawel Czerwinski on Unsplash

The recent versions of JetPack have this inherent issue of the CAN devices failing to interact with the bus; no read or write. Along this, one might see kernel errors when probing using dmesg . The issue boils down to the lack of suitable frequency for the two devices. Symptoms include similar errors in the dmesglog.

[  +4.999186] mttcan_handle_bus_err: 8746 callbacks suppressed
[ +0.000205] mttcan c320000.mttcan can1: Acknowledgement Error Detected
[ +0.000146] mttcan c320000.mttcan can1: IR 0x8000000 PSR 0x427b
[ +0.000786] mttcan c320000.mttcan can1: Acknowledgement Error Detected
[ +0.000144] mttcan c320000.mttcan can1: IR 0x8000000 PSR 0x427b
[ +0.001013] mttcan c320000.mttcan can1: Acknowledgement Error Detected
[ +0.000133] mttcan c320000.mttcan can1: IR 0x8000000 PSR 0x427b
[ +0.001010] mttcan c320000.mttcan can1: Acknowledgement Error Detected
[ +0.000132] mttcan c320000.mttcan can1: IR 0x8000000 PSR 0x427b
[ +0.001001] mttcan c320000.mttcan can1: Acknowledgement Error Detected
[ +0.000164] mttcan c320000.mttcan can1: IR 0x8000000 PSR 0x427b
[ +1.769043] mttcan c320000.mttcan can1: Bit0 Error Detected
[ +0.000312] mttcan c320000.mttcan can1: Bit0 Error Detected
[ +0.000356] mttcan c320000.mttcan can1: Bit0 Error Detected
[ +0.000264] mttcan c320000.mttcan can1: Bit0 Error Detected
[ +0.000311] mttcan c320000.mttcan can1: Bit0 Error Detected
[ +0.000429] mttcan c320000.mttcan can1: Bit0 Error Detected
[ +0.000215] mttcan c320000.mttcan can1: Bit0 Error Detected

NVIDIA suggests changing the parent clocks of both CAN0 and CAN1 using the device tree. The source clock needs to be changed from osc to pllaon. The current clock for the CAN devices can be checked using

nvidia@xavier:~$ cat /proc/device-tree/mttcan@c310000/pll_source
pllaon # CAN won't work if you get osc
nvidia@xavier:~$ sudo cat /sys/kernel/debug/bpmp/debug/clk/can1/parent
pll_c

This is my experience on how to do it.

Download JetPack but don’t install

Use the sdkmanager to download JP (JetPack) 4.6.1 (in my case), but ensure to disconnect the devkit (NVIDIA Jetson Xavier AGX for me) and select Download now. Install later .

Continue till step 4 and finish and exit.

Change device-tree files

Once JP is downloaded, the OS files are saved to a ~/nvidia/nvidia_sdk/ . We need to modify two device tree files or binaries by first converting them to an editable form: dts/device tree source.

1. tegra194-a02-bpmp-p2888-a04.dtb

cd ~/nvidia/nvidia_sdk/JetPack_4.6.1_Linux_JETSON_AGX_XAVIER_TARGETS/Linux_for_Tegra/bootloader/t186ref
# create backup
cp tegra194-a02-bpmp-p2888-a04.dtb backup_tegra194-a02-bpmp-p2888-a04.dtb
# de-compile the binary into source
dtc -I dtb -O dts tegra194-a02-bpmp-p2888-a04.dtb -o tegra194-a02-bpmp-p2888-a04.dts
# edit the source
sudo nano tegra194-a02-bpmp-p2888-a04.dts

The updated file should look as follows:

clock@can1 {
allow_fractional_divider = <0x1>;
allowed-parents = <0x121 0x5b 0x13a 0x5e>; //old: <0x121 0x5b 0x13a>;
clk-id = <0x9>;
};

clock@can2 {
allow_fractional_divider = <0x1>;
allowed-parents = <0x121 0x5b 0x13a 0x5e>; //old: <0x121 0x5b 0x13a>;
clk-id = <0xb>;
};

Replace the older files

# remove original binary
rm tegra194-a02-bpmp-p2888-a04.dtb
# compile modified file
dtc -I dts -O dtb tegra194-a02-bpmp-p2888-a04.dts -o tegra194-a02-bpmp-p2888-a04.dtb

There will be a lot of warnings but we can ignore them for now.

2. tegra194-p2888-0001-p2822-0000.dtb

Repeat the steps for this one.

cd ~/nvidia/nvidia_sdk/JetPack_4.6.1_Linux_JETSON_AGX_XAVIER_TARGETS/Linux_for_Tegra/kernel/dtb
cp tegra194-p2888-0001-p2822-0000.dtb backup_tegra194-p2888-0001-p2822-0000.dtb
dtc -I dtb -O dts tegra194-p2888-0001-p2822-0000.dtb -o tegra194-p2888-0001-p2822-0000.dts
sudo nano tegra194-p2888-0001-p2822-0000.dts

Make changes around lines 3331 and 13645. The updated file should look as follows:

mttcan@c310000 {
compatible = "nvidia,tegra194-mttcan";
reg = <0x0 0xc310000 0x0 0x400 0x0 0xc311000 0x0 0x32 0x0 0xc312000 0x0 0x1000>;
reg-names = "can-regs", "glue-regs", "msg-ram";
interrupts = <0x0 0x28 0x4>;
pll_source = "pllaon"; //old: "osc";
clocks = <0x4 0x11c 0x4 0xa 0x4 0x9 0x4 0x5e>; //old: <0x4 0x11c 0x4 0xa 0x4 0x9 0x4 0x5b>;
clock-names = "can_core", "can_host", "can", "pllaon"; //old: "can_core", "can_host", "can", "osc";
resets = <0x5 0x4>;
reset-names = "can";
mram-params = <0x0 0x10 0x10 0x20 0x0 0x0 0x10 0x10 0x10>;
tx-config = <0x0 0x10 0x0 0x40>;
rx-config = <0x40 0x40 0x40>;
status = "okay";
linux,phandle = <0x189>;
phandle = <0x189>;
};

mttcan@c320000 {
compatible = "nvidia,tegra194-mttcan";
reg = <0x0 0xc320000 0x0 0x400 0x0 0xc321000 0x0 0x32 0x0 0xc322000 0x0 0x1000>;
reg-names = "can-regs", "glue-regs", "msg-ram";
interrupts = <0x0 0x2a 0x4>;
pll_source = "pllaon"; //old:"osc";
clocks = <0x4 0x11d 0x4 0xc 0x4 0xb 0x4 0x5e>; //old: <0x4 0x11d 0x4 0xc 0x4 0xb 0x4 0x5b>;
clock-names = "can_core", "can_host", "can", "pllaon"; //old: "can_core", "can_host", "can", "osc";
resets = <0x5 0x5>;
reset-names = "can";
mram-params = <0x0 0x10 0x10 0x20 0x0 0x0 0x10 0x10 0x10>;
tx-config = <0x0 0x10 0x0 0x40>;
rx-config = <0x40 0x40 0x40>;
status = "okay";
linux,phandle = <0x18a>;
phandle = <0x18a>;
};

// ... around line 13654

clocks-init {
compatible = "nvidia,clocks-config";
status = "okay";
disable {
clocks = <0x4 0x9 0x4 0xb>; //old: clocks = <0x14f 0x5e 0x4 0x9 0x4 0xb>;
};
};
rm tegra194-p2888-0001-p2822-0000.dtb
# compile modified file
dtc -I dts -O dtb tegra194-p2888-0001-p2822-0000.dts -o tegra194-p2888-0001-p2822-0000.dtb

Flash

Power On the Jetson devkit and put it into recovery mode by following these steps:

  1. Power On the device; press and release immediately
  2. Press Force Recovery button
  3. Press Reset button
  4. Release Reset button
  5. Release Force Recovery button

Use the default script to flash.

cd ~/nvidia/nvidia_sdk/JetPack_4.6.1_Linux_JETSON_AGX_XAVIER_TARGETS/Linux_for_Tegra/
sudo ./flash.sh jetson-agx-xavier-devkit mmcblk0p1

After a while, it ends successfully

...
[ 303.8242 ] tegradevflash_v2 --write MEM_BCT_b mem_coldboot_sigheader.bct.encrypt
[ 303.8256 ] Bootloader version 01.00.0000
[ 303.8306 ] Writing partition MEM_BCT_b with mem_coldboot_sigheader.bct.encrypt
[ 303.8315 ] [................................................] 100%
[ 303.8523 ]
[ 303.8524 ] Flashing completed
[ 303.8526 ] Coldbooting the device
[ 303.8878 ] tegrarcm_v2 --ismb2
[ 303.9121 ]
[ 303.9186 ] tegradevflash_v2 --reboot coldboot
[ 303.9198 ] Bootloader version 01.00.0000
[ 303.9263 ]
*** The target t186ref has been flashed successfully. ***
Reset the board to boot from internal eMMC.

Test CAN0 and CAN1

To test the device CAN, configure and enable both devices as follows. The dsjw and bitrate , etc are subjective.

#cancfg.sh
sudo ip link set down can1
sudo ip link set down can0
sudo busybox devmem 0x0c303000
sudo busybox devmem 0x0c303010
sudo busybox devmem 0x0c303008
sudo busybox devmem 0x0c303000 32 0x0000C400
sudo busybox devmem 0x0c303008 32 0x0000C458
sudo busybox devmem 0x0c303010 32 0x0000C400
sudo busybox devmem 0x0c303018 32 0x0000C458
sudo modprobe can
sudo modprobe can_raw
sudo modprobe mttcan
sudo ip link set can0 up type can bitrate 250000 sjw 127 dbitrate 2000000 dsjw 15 berr-reporting on fd on
sudo ip link set can1 up type can bitrate 250000 sjw 127 dbitrate 2000000 dsjw 15 berr-reporting on fd on
sudo ip link set up can0
sudo ip link set up can1
ip -s -d link show can0
ip -s -d link show can1

side-note

I have tested this to work on JetPack4.6.1 which I also intended to use with PyTorch. Unfortunately, this flashing method (sometimes) skips the installation of CUDA which can be explicitly installed. For e.g., JetPack4.6.1 supports CUDA 10.2 (check this in the respective Linux Driver Package L4T page; R32.7.1 in my case.

sudo apt-get update
sudo apt-get install cuda-toolkit-10-2

Don’t forget to update the PATH later.

It is always solicitous to make a backup of the OS image. On the Jetson Xavier AGX, this can be done as:

# create backup
sudo ./flash.sh -r -k APP -G backup_filename.img jetson-agx-xavier-devkit mmcblk0p1
# flash using backup
sudo ./flash.sh -r -k APP jetson-agx-xavier-devkit mmcblk0p1

For more info, refer to Basic Flashing Procedures on NVIDIA Linux Developer guide.

--

--