CAN (Controller Area Network) is a serial communication protocol bus for real-time applications, which can use twisted pair wires to transmit signals and is one of the most widely used fieldbuses in the world. It was developed by Bosch in Germany in the 1980s specifically for the automotive industry. Multiple nodes can be supported on one CAN group.
In Linux systems, CAN is a network device that sends and receives by means of socket communication.
There is one CAN on the development board, and the corresponding pin locations are as follows
The corresponding NIC device is CAN0. There is no CAN transceiver on the board, and the interfaces are CAN TX and CAN RX. A CAN transceiver module with a level of 3.3V is needed, and TI's SN65HVD230 can be chosen; connect the CAN TX and CAN RX on the board to the CAN TX and CAN RX of the SN65HVD230 module, and connect CANH and CANL of the SN65HVD230 to the CANH and CANL of the CAN analyzer to conduct the transceiver test. SN65HVD230 CANH, CANL and CAN analyzer CANH and CANL connection can be transceiver test. The wiring is as follows
The operation can be performed using canutil under Linux.
Set the baud rate to 250k. canfd is not currently available on the board, but the RK3568 itself supports canfd, so a canfd baud rate must be set here as well
root@linaro-alip:~# ip link set can0 type can bitrate 250000 dbitrate 3000000 fd on
Start CAN0
root@linaro-alip:~# ip link set can0 up
Send standard frame id 0x123 data 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88
root@linaro-alip:~# cansend can0 123#1122334455667788
Send extended frame id 0x12345678 data 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88
root@linaro-alip:~# cansend can0 12345678#1122334455667788
After sending the CAN analyzer displays the following
Receiving data
root@linaro-alip:~# candump can0
Send standard frame id 0x234 data 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 using CAN analyzer
By linking to the libperipheral_api.a static library, the following interfaces can be called in C to operate CAN
/**
* @name: user_can_init
* @description: Initialize CAN
* @param can_name: can network card device name e.g. can0
* @param can_baud: baud rate e.g. 250000
* @param canfd_baud: canfd baud rate e.g. 3000000
* @return greater than or equal to 0 - Success; less than 0 - Failure
*/
int user_can_init(char *can_name, int can_baud, int canfd_baud);
/**
* @name: user_can_deinit
* @description: De-initialize CAN
* @param can_name: can network card device name e.g. can0
* @return greater than or equal to 0 - Success; less than 0 - Failure
*/
int user_can_deinit(char *can_name);
/**
* @name: user_can_send
* @description: Send a frame of CAN data
* @param can_name: can network card device name e.g. can0
* @param frame: CAN Structs in Linux
* @return Greater than 0 - Success; Less than 0 - Failure; Equal to 0 - Temporarily unable to send, buffer may be full
*/
int user_can_send(char *can_name, struct can_frame frame);
/**
* @name: user_can_recv
* @description: Recv a frame of CAN data
* @param can_name: can network card device name e.g. can0
* @param frame: CAN Structs in Linux
* @return Greater than 0 - Success; Less than 0 - Failure; Equal to 0 - No data received, receive buffer empty
*/
int user_can_recv(char *can_name, struct can_frame *frame);
The test demo is as follows, taking the operation of CAN0 as an example, with an external CAN analyzer
void can_api_test(void)
{
struct can_frame frame_tx = {0};
struct can_frame frame_rx = {0};
int nbytes = 0;
user_can_init("can0",250000,3000000);
frame_tx.can_id = 0x123;
frame_tx.can_dlc = 8;
frame_tx.data[0] = 0x11;
frame_tx.data[1] = 0x22;
frame_tx.data[2] = 0x33;
frame_tx.data[3] = 0x44;
frame_tx.data[4] = 0x55;
frame_tx.data[5] = 0x66;
frame_tx.data[6] = 0x77;
frame_tx.data[7] = 0x88;
nbytes = user_can_send("can0",frame_tx);
frame_tx.can_id = 0x12345678 | CAN_EFF_FLAG;
frame_tx.can_dlc = 8;
frame_tx.data[0] = 0x11;
frame_tx.data[1] = 0x22;
frame_tx.data[2] = 0x33;
frame_tx.data[3] = 0x44;
frame_tx.data[4] = 0x55;
frame_tx.data[5] = 0x66;
frame_tx.data[6] = 0x77;
frame_tx.data[7] = 0x88;
nbytes = user_can_send("can0",frame_tx);
nbytes = user_can_recv("can0",&frame_rx);
/* printf the received frame */
if (nbytes > 0) {
printf("%#x [%d] ", frame_rx.can_id, frame_rx.can_dlc);
for (unsigned char i = 0; i < frame_rx.can_dlc; i++)
printf("%#x ", frame_rx.data[i]);
printf("\n");
}
user_can_deinit("can0");
return;
}
int main()
{
can_api_test();
return 0;
}
Put the peripheral_api.a static library, peripheral_api.h and the test demo source code test.c into the same path, compile the command as follows
aarch64-none-linux-gnu-gcc test.c peripheral_api.a -I. -o cantest
The results of the run are as follows