We have wired an MCP2515 chip to the SPI lo-speed connector and have configured the kernel build of hikey-kernel to activate CAN and SPI. When we try to create a device via: ip link add dev can0 type can we get the message: RTNETLINK ANSWERS: Operation not supported on transport endpoint. Also the ‘ip’ command does not appear to support type ‘can’.
I believe that we are missing something in our configuration. Any suggestions?
In the file: arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts we added the following in the &spi2 section: can0: mcp2515@0 { compatible = "microchip,mcp2515"; reg = <0>; clocks = <&clk16m>; interrupt-parent = <&gpio2>; interrupts = <0 0x2>; spi-max-frequency = <500000>; /* may be too high. 500000 was recommended */ };
The spi-max-frequency was initially set to 10MHz. By reducing it to 500KHz we started to see additional messages in the kernel logs:
[ 7.013583] ssp-pl022 ffd68000.spi: flush [ 7.013588] ssp-pl022 ffd68000.spi: flush [ 7.013591] ssp-pl022 ffd68000.spi: polling transfer ongoing ... [ 7.013595] ssp-pl022 ffd68000.spi: readwriter, rx: ffffffc0b4f33b18, rxend: ffffffc0b4f33b19, tx: ffffffc0b4f33b98, txend: ffffffc0b4f33b99 [ 7.013600] ssp-pl022 ffd68000.spi: readwriter, rx: ffffffc0b4f33b18, rxend: ffffffc0b4f33b19, tx: ffffffc0b4f33b99, txend: ffffffc0b4f33b99
This was not sufficient to get the CAN driver up, though.
I work with Marianne here at Pillar Technology.
We don’t quite recall what our original problem was (we ended up stumbling over a number of problems), but the title of this question is very searchable so we wanted to share a working solution.
The following is a step by step guide to enabling CAN on the Hikey960, with lots of checkpoints to verify things are going correctly along the way.
Enable CAN in Kernel
Run lunch to put the prebuilt cross compiler on the PATH.
$ . build/envsetup.sh
$ lunch hikey960-userdebug
Clone the kernel source and verify you can build it
Then regenerate the .config file and rebuild the kernel.
make ARCH=arm64 hikey960_defconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-android- -j24
Follow the steps above to copy the kernel image into the aosp tree, rebuild aosp, and flash your device.
Verify the CAN modules have been added with VCAN.
adb root # must be root to add the net device
adb shell ip link add dev vcan0 type vcan
adb shell ifconfig vcan0 up
adb shell ifconfig # you should see vcan0 in the results
Modify the Device Tree
Enable the 1.8V regulator
The GPIO on the Hikey960 runs at 1.8V and CAN runs at either 3.3v or 5v.
This means you need a level shifter in your hardware design.
The level shifter will require a 1.8V reference voltage.
By default, LDO11 (Pin 35) is not enabled, so you need to apply the following patch to the dts, credit leo-yan.
Then include it at the bottom of the main hi3660-hikey960.dts file.
(We want our additions to be overlayed on top of the original hardware definition.)
/include/ "hi3660-hikey960-can.dts"
Clock Speed
Be sure to verify the oscillator frequency of the crystal on your CAN module. Ours runs at 8MHz, but many run at 16MHz.
Adjust this accordingly.
The driver uses this frequency to calculate the bit timing for the CAN protocol.
If this frequency isn’t correct, you won’t be able to establish communications later.
Interrupts
In the device tree node above, the interrupt-parent is a reference to one of the Hikey’s GPIO groups.
The interrupts entry defines the GPIO’s index within the group and as well as the trigger type.
For our board, we picked GPIO_019 (Pin 32) because there’s no alternative function for the pin.
We connected this pin to the interrupt pin on the MCP2515 module.
The Hi3660 Datasheet describes how to convert from a GPIO to a GPIO group and index in Sect. 8.5.1.
You can obtain the group ID of a GPIO pin by using the following formula:
Group ID = int(GPIO pin number/8)
The remainder is the sequence number of this pin in the group, ranging from 0 to 7. (0 is the
LSB and 7 is the MSB.)
Sequence number within the group = mod(GPIO pin number/8)
Take GPIO_017 as an example. The pin number is 17. Its group ID is 2 (int(17/8)), and the
remainder is 1. Therefore, GPIO_017 belongs to GPIO group 2 (GPIO2), and its sequence
number within this group is 1. Similarly, the sequence number of GPIO_016 in GPIO2 is 0,
and that of GPIO_023 in GPIO2 is 7.
If you use a pin other than 32, you’ll need to reference the hardware guide and perform this calculation yourself.
Verify device tree modifications
Build the dtb, copy it to the aosp tree, build, and flash.
Wire your CAN module into the low-speed connector then
add the can0 network device, and verify you can bring it up.
adb shell ip link set can0 type can bitrate 500000
adb shell ifconfig can0 up
adb shell ifconfig
Adding CAN-Utils to the device
You may skip this step, but we found it useful to have can utils like cansend and candump on the target device for debugging/development/verification purposes while we were going through this process.
Add the CAN-Utils Source to the AOSP Tree
Add a local manifest to the ~/aosp/.repo/local_manifests/ directory.
Building and flashing at this point will now result in… nothing.
Or rather, apparently nothing.
Manually starting the service and inspecting the logs will reveal a SELinux error.
$ adb root
$ adb shell start can && dmesg
init: Control Message 'start' recieved
init: Could not ctl.start for service can: File /system/bin/sh(labeled "u:object_r:shell_exec:s0") has incorrect label or no domain transition from u:r:init:s0 to another SELinux domain defined. Have you configured your service correctly? https://source.android.com/security/selinux/device-policy#label_new_services_and_address_denials
The link will tell you to create a new domain, but the fact that the /system/bin/sh executable is already labeled indicates that a domain already exists.
We just need to allow it to run in the init domain.
All we need to do is add a device/linaro/hikey/sepolicy/shell.te file with the following line.
# Allow init to run sh
# We need this for one shot setup of the can network
init_daemon_domain(shell)
Build & flash one more time.
Running ifconfig will show that the can0 network device was automatically configured and started.
Hi,
I followed the steps as described. Unfortunately it is not working. When I run the command "adb shell ip link set can0 type can bitrate 500000 " it says no device can0 available.
Any idea about the reason ? Thanks in advance for your support.
Hatem
Hi! What have you tried? Are you seeing any messages in the kernel logs? Did you power on the remote system before the Hikey? I did sometimes see issues if the Hikey wasn’t powered on after the rest of the devices on the CAN bus. Or it might have been the other way around. I haven’t worked on this in some months now. I believe we saw this most often when we had some kind of hardware connection issue on the SPI bus. Make sure the SPI interrupt pin is securely connected. Those tiny European headers can be hard to get a good connection with sometimes.
It looks like there is some traffic on the SPI bus, but it’s unable to initialize properly. What’s the clock speed of the crystal on your CAN module? That looks like a genuine Electrodragon. It should be 16hz, if I recall correctly, but check for markings on the crystal (the silver oblong) and the datasheet. My module was a knock off with an 8hz clock. Double check that you’ve set the clock speed correctly in the device tree.
HOLD ON JUST A MINUTE THERE!!!
Are you TRYING to murder your hikey960?
You are interfacing a 5v device with a 1.8v device without a LEVEL SHIFTER.
Even if its protected from setting the world on fire, the high and low logic levels are NOT going to align, which means they will NOT communicate successfully.
Well, how about doing the obvious? Add a level shifter. And cross your fingers that you didn’t cook your SoC.
You have to make sure that the level shifter you use is capable of SPI.
It looks like the “sensors mezzanine” board has SPI routed through a level shifter (TXB0108), but I’m not sure how well that will work, I’ve read that TXB is not a great level shifter for SPI, rather it would be better to use TXS0108 for that. Its possible that the TXB may work adequately at low speeds, but I can’t confirm.
EDIT: I would be tempted to try the sensors mezzanine, especially if you happen to already own one, and if not, they’re a great tool for this type of hacking. If SPI doesn’t work through the TXB and you (or someone you know) is halfway decent at surface mount soldering, you can swap the TXB for a TXS. They are pin compatible, so its a real easy swap.
@doitright thanks a lot . I understand better now the choice of your name (do it right) .
Hi @rubberduck203, in your case how did you manage to do the level shifting. thx
You’re welcome! One tip I do have there is to get yourself some of the smaller 0.2mm jumpers and strip one end off to solder to your level shifter proto. I did manage to make 0.2mm headers work, but it takes an extremely steady hand to solder those tiny buggers. I think you’d have better luck with using jumpers. Bad hardware connections plagued my project for months.