====== CAN interface ======
{{:github-mark-32px.png?nolink |}}
Example available on [[https://github.com/grinn-pub/examples|GitHub]].
Check [[https://github.com/grinn-pub/examples/blob/master/configs/grinn_liteboard_can_defconfig|liteboard CAN]] example.
{{ :litesom:devicetree:liteboard-can.png?nolink&500 |}}
CAN interface is a message-oriented multi-master serial communications protocol which efficiently supports distributed realtime control.
[[litesom:about|liteSOM]] contains two CAN modules compatible with ''CAN 2.0B'' protocol specification.
CAN Physical layer is defined by ''ISO 11898'' therefore to connect [[litesom:about|liteSOM]] to CAN bus it is required to use external CAN Bus Transceiver like [[https://www.ti.com/product/SN65HVD230|SN65HVD230]] used on on [[litesom:serials|RS485/CAN extension board]].
===== Device Tree =====
can1: flexcan@02090000 {
compatible = "fsl,imx6ul-flexcan", "fsl,imx6q-flexcan";
reg = <0x02090000 0x4000>;
interrupts = ;
clocks = <&clks IMX6UL_CLK_CAN1_IPG>,
<&clks IMX6UL_CLK_CAN1_SERIAL>;
clock-names = "ipg", "per";
status = "disabled";
};
can2: flexcan@02094000 {
compatible = "fsl,imx6ul-flexcan", "fsl,imx6q-flexcan";
reg = <0x02094000 0x4000>;
interrupts = ;
clocks = <&clks IMX6UL_CLK_CAN2_IPG>,
<&clks IMX6UL_CLK_CAN2_SERIAL>;
clock-names = "ipg", "per";
status = "disabled";
};
Generic configuration for both ''FLEXCAN'' modules is defined by [[https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/boot/dts/imx6ul.dtsi|imx6ul.dtsi]] file.
To enable ''linux'' CAN driver please build your kernel with ''CONFIG_CAN_FLEXCAN'' enabled.
-> Networking support
-> CAN bus subsystem support
-> CAN Device Drivers
-> Platform CAN drivers with Netlink support
-> Support for Freescale FLEXCAN based chips
This option will activate [[https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/can/flexcan.c|FLEXCAN driver]].
Documentation for this driver you can find in [[https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt|fsl-flexcan.txt]] file.
&iomuxc {
pinctrl-names = "default";
pinctrl_flexcan1: flexcan1grp{
fsl,pins = <
MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX 0x1b020
MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX 0x1b020
>;
};
};
&can1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_flexcan1>;
status = "okay";
};
''i.MX6UL'' [[litesom:devicetree##iomux_configuration|IOMUX Controller]] configuration required to connect [[litesom:liteboard|liteboard]] with [[litesom:serials|RS485/CAN extension board]] is defined by ''can1'' node in [[https://github.com/grinn-pub/examples/blob/master/board/grinn/liteboard-can/imx6ul-can.dts|imx6ul-can.dts]] file.
===== SocketCAN =====
''Linux'' supports CAN interface via [[https://www.kernel.org/doc/Documentation/networking/can.txt|SocketCAN]].
A [...] protocol family [...] implemented which provides a socket interface to user space applications and which builds upon the Linux network layer, enabling use all of the provided queueing functionality. A device driver for CAN controller hardware registers itself with the Linux network layer as a network device, so that CAN frames from the controller can be passed up to the network layer and on to the CAN protocol family module and also vice-versa. Also, the protocol family module provides an API for transport protocol modules to register, so that any number of transport protocols can be loaded or unloaded dynamically. In fact, the can core module alone does not provide any protocol and cannot be used without loading at least one additional protocol module. Multiple sockets can be opened at the same time, on different or the same protocol module and they can listen/send frames on different or the same CAN IDs. Several sockets listening on the same interface for frames with the same CAN ID are all passed the same received matching CAN frames. An application wishing to communicate using a specific transport protocol, e.g. ISO-TP, just selects that protocol when opening the socket, and then can read and write application data byte streams, without having to deal with CAN-IDs, frames, etc.
''SocketCAN'' is defined on top of //the network layer// therefore it can be automatically configured via ''/etc/network/interfaces'' file
auto can0
iface can0 inet manual
pre-up /sbin/ip link set can0 type can bitrate 125000
up /sbin/ifconfig can0 up
down /sbin/ifconfig can0 down
or configured in the runtime by the following commands:
* ''ifconfig can0 down'' - disabling CAN interface,
* ''ip link set can0 type can bitrate 250000'' - changing CAN bus baudrate to 250kbps,
* ''ifconfig can0 up'' - enabling CAN interface.
===== CAN bus info =====
''SocketCAN'' provides to the userspace various information about current CAN bus status.
==== SocketCAN version ====
# cat /proc/net/can/version
rev 20120528 abi 9
==== CAN status ====
# ifconfig can0
can0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
UP RUNNING NOARP MTU:16 Metric:1
RX packets:1 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:1 overruns:0 carrier:1
collisions:0 txqueuelen:10
RX bytes:8 (8.0 B) TX bytes:0 (0.0 B)
Interrupt:19
# ip -details link show can0
2: can0: mtu 16 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 10
link/can promiscuity 0
can state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 0
bitrate 461538 sample-point 0.846
tq 166 prop-seg 5 phase-seg1 5 phase-seg2 2 sjw 1
flexcan: tseg1 4..16 tseg2 2..8 sjw 1..4 brp 1..256 brp-inc 1
clock 30000000
====CAN statistics ====
# cat /proc/net/can/stats
2 transmitted frames (TXF)
1 received frames (RXF)
0 matched frames (RXMF)
0 % total match ratio (RXMR)
0 frames/s total tx rate (TXR)
0 frames/s total rx rate (RXR)
0 % current match ratio (CRXMR)
0 frames/s current tx rate (CTXR)
0 frames/s current rx rate (CRXR)
0 % max match ratio (MRXMR)
1 frames/s max tx rate (MTXR)
1 frames/s max rx rate (MRXR)
0 current receive list entries (CRCV)
0 maximum receive list entries (MRCV)
===== can-utils =====
[[https://buildroot.org|Buildroot]] allows you to build various tools developed by [[https://github.com/linux-can/can-utils|can-utils]] project.
To compile ''can-utils'' package please enable ''BR2_PACKAGE_CAN_UTILS'' option located in
-> Target packages
-> Networking applications
-> can-utils
To check description about all implemented by ''can-utils'' applications please read [[https://github.com/linux-can/can-utils/blob/master/README.md|project README]] file.
Below you can find few examples with frequently used commands.
==== CAN sniffer ====
# candump -x can0
can0 TX - - 1000101F [0]
can0 RX - - 10B05002 [8] 00 00 00 00 00 00 00 00
can0 RX - - 10B05001 [8] 00 00 00 00 00 00 00 00
can0 RX - - 10B05004 [8] 82 85 00 00 80 00 00 00
can0 RX - - 10B0F002 [8] 00 00 00 00 00 00 00 00
can0 RX - - 10B0F001 [8] 00 00 00 00 00 00 00 00
can0 RX - - 10B0F004 [8] 87 85 00 00 80 00 00 00
can0 RX - - 10B19002 [8] 00 00 00 00 00 00 00 00
can0 RX - - 10B19001 [8] 00 00 00 00 00 00 00 00
can0 RX - - 10B19004 [8] 8C 85 00 00 A3 00 00 00
==== CAN sender ====
To send 0 length //data frame// to the node with address ''1000101F'' you can use following command
cansend can0 1000101F#
To send //remote frame// to the node with address ''1000101F'' you can use following command
cansend can0 1000101F#R
==== CAN bus load test ====
To test CAN bus load performance you can use following command
canbusload can0@125000 -r -t -b -c
===== C/C++ API =====
In case when you want to develop your own application to access CAN bus via ''SocketCAN'' please check [[https://www.kernel.org/doc/Documentation/networking/can.txt|Section 4 in SocketCAN readme]] file.
In most cases access to the CAN bus looks like access to the ''linux'' network interface . Please check //pseudo-code// example presented below.
int s;
struct sockaddr_can addr;
struct ifreq ifr;
/*
* Open connection with CAN bus
*/
s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
strcpy(ifr.ifr_name, "can0" );
ioctl(s, SIOCGIFINDEX, &ifr);
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(s, (struct sockaddr *)&addr, sizeof(addr));
/*
* build CAN data frame
*/
struct can_frame frame;
frame.can_id = node_id | CAN_EFF_FLAG; // node id + extended frame format
frame.can_dlc = 6; // data frame length
frame.data[0] = 0x11; // data frame first byte
frame.data[1] = 0x22;
frame.data[2] = 0x33;
frame.data[3] = 0x44;
frame.data[4] = 0x55;
frame.data[5] = 0x66; // data frame last byte
/*
* send data frame via CAN bus
*/
write(s, &frame, sizeof(frame));
===== Python API =====
Via [[https://buildroot.org|Buildroot]] ''BR2_PACKAGE_PYTHON_CAN'' option located in
-> Target packages
-> Interpreter languages and scripting
-> External python modules
-> python-can
you can build ''python-can'' [[https://www.python.org/download/releases/3.0/|Python3]] package.
Please read [[https://python-can.readthedocs.io/en/stable/|python-can documentation]] to check how to access CAN from python based application.