Linux application development [Chapter 13] CAN programming application development

Posted by suttercain on Wed, 15 Dec 2021 15:24:29 +0100

Article catalog

13CAN programming application development

13.1 CAN introduction

13.1. 1 what is can?

CAN, fully known as "Controller Area Network", namely Controller Area Network, is one of the most widely used fieldbuses in the world.

Initially, CAN was designed as a microcontroller communication in the automotive environment to exchange information between on-board electronic control devices and ECU s to form the automotive environment

Electronic control network. For example, CAN control devices are embedded in engine management system, transmission controller, instrument equipment and electronic backbone system

Set.

In a single network composed of CAN bus, countless nodes can be connected in theory. In practical application, the number of nodes is affected by the network hardware

Limited by the electrical characteristics of. For example, when Philips P82C250 is used as a CAN transceiver, 110 nodes are allowed to be connected in the same network.

CAN can provide data transmission rate up to 1Mbit/s, which makes real-time control very easy. In addition, the error verification characteristics of hardware are also increased

The anti electromagnetic interference ability of CAN is strengthened.

13.1. 2 origin of can

CAN first appeared in the automotive industry in the late 1980s and was first proposed by Bosch Company of Germany. At that time, due to consumers' enthusiasm for cars

There are more and more requirements for energy, and the realization of these functions is mostly based on electronic operation, which makes the communication between electronic devices more and more complex,

It also means that more connecting signal lines are required. The original motivation of CAN bus is to solve the huge electronic control equipment in modern vehicles

Communication between devices to reduce the increasing number of signal lines. Therefore, they designed a single network bus, and all peripheral devices can be used

Attach to the bus. In 1993, CAN has become the international standard iso11898 (high speed application) and iso111519 (low speed application).

CAN is a serial communication bus with multi master mode. The basic design specification requires high bit rate, high anti electromagnetic interference and CAN detect

Any errors are detected. When the signal transmission distance reaches 10Km, CAN can still provide data transmission rate up to 50Kbit/s.

Because CAN bus has high real-time performance, CAN has been used in automobile industry, aviation industry, industrial control, safety protection and so on

Domain has been widely used.

13.1.3 CAN transmission model

CAN communication protocol mainly describes the information transmission mode between devices. The definition of CAN layer is consistent with the open systems interconnection model (OSI)

One layer communicates with the same layer on another device. The actual communication occurs on two adjacent layers of each device, and the device only passes through the physical model

Physical medium interconnection of layers. The specification of CAN defines the lowest two layers of the model: data link layer and physical layer. The following table shows OSI open

Each layer of the interconnection model. The application layer protocol CAN be defined by CAN users into any scheme suitable for special industrial fields. It has been used in industrial control and manufacturing

The widely used standard in the manufacturing field is DeviceNet, which is designed for PLC and intelligent sensor. In the automotive industry, many manufacturers

Apply their own standards.

Table OSI development system interconnection model

Serial number

arrangement

describe

7

application layer

The highest level. It is used for information exchange among users, software, network terminals, etc.

6

Presentation layer

Convert the information of two systems using different data formats into a format that can be understood jointly

5

Session layer

Rely on low-level communication functions for effective data transmission.

4

Transport layer

Data transmission control between two communication nodes. Operations such as data retransmission and data error repair

3

network layer

It specifies the protocol for the establishment, maintenance and removal of network connections. Such as routing and addressing

2

data link layer

Specifies the arrangement and organization of data bits transmitted on the medium. Such as data checksum frame structure

1

physical layer

Specify the physical characteristics of the communication medium. E.g. explanation of electrical characteristics and signal exchange

Although the can transmission protocol refers to the OSI seven layer model, in fact, the CAN protocol only defines two layers of "physical layer" and "data link layer", so there are various "application layer" protocols, such as fieldbus standard DeviceNet for automation technology, CanOpen for industrial control, and diagnostic protocol OBD for passenger cars UDS (Unified diagnostic service, ISO14229), can bus protocol SAEJ1939 for commercial vehicles

Table CAN

Serial number

arrangement

describe

7

application layer

It mainly defines the CAN application layer.

2

data link layer

The data link layer is divided into logical link control sublayer LLC and media access control sublayer Mac. MAC sublayer is the core of CAN protocol. It provides the received message to the LLC sublayer and receives the message from the LLC sublayer. The MAC sublayer is responsible for message framing, arbitration, response, error detection and calibration. The MAC sublayer is also referred to as the management entity of fault definition. The LLC sublayer involves message filtering, overload notification, and recovery management. LLC = Logical Link Control MAC = Medium Access Control

1

physical layer

The physical layer is the physical coding sublayer PCS. this layer defines how signals are actually transmitted, so it involves in place time, bit coding and synchronization.

13.1.4 CAN network topology

CAN bus is a distributed control bus.

As a controller area network, CAN bus is composed of many CAN nodes like ordinary Ethernet.

The network topology is shown in the figure below:

Each node of the CAN network is very simple, which is composed of a MCU (microcontroller), a CAN controller and a CAN transceiver, and then connected to the CAN network with twisted pair.

13.1.5 CAN physical characteristics

CAN bus complies with international standards ISO11898, such as ISO11898-1, ISO11898-2, ISO11898-3 and ISO11898-4.

Serial number

standard

describe

1

ISO11898-1

Data link layer and physical layer signals

2

ISO11898-2

High speed access unit

3

ISO11898-3

Low speed fault tolerant access unit

4

ISO11898-4

Time triggered communication

5

ISO11898-5

Low power access unit

6

ISO11898-6

Selective wake-up high speed access unit

CAN can use a variety of physical media, such as twisted pair, optical fiber, etc. The most commonly used is twisted pair.

The signal is transmitted using differential voltage, and the two signal lines are called "CAN_H" and "CAN_L".

Static CAN_H and CAN_L is about 2.5V. At this time, the state is represented as logic "1", which can also be called "recessive".

With CAN_H ratio CAN_L high indicates logic "0", which is called "explicit". At this time, the normal voltage value is: CAN_H = 3.5V and CAN_L

= 1.5V .

At present, the commonly used CAN transceivers are as follows:

Serial number

model

describe

1

PCA82C250

High speed CAN transceiver

2

PCA82C251

High speed CAN transceiver

3

PCA82C252

Fault tolerant CAN transceiver

4

TJA1040

High speed CAN transceiver

5

TJA1041

High speed CAN transceiver

6

TJA1042

High speed CAN transceiver

7

TJA1043

High speed CAN transceiver

8

TJA1050

High speed CAN transceiver

9

TJA1053

Fault tolerant CAN transceiver

10

TJA1054

Fault tolerant CAN transceiver

At present, the commonly used CAN controllers are as follows:

Serial number

model

describe

1

SJA1000

Independent CAN controller

2

MCU internal controller

At present, many microcontrollers on the market, such as STM32 series, S32K series, IMX6 series and so on, have integrated CAN control internally.

13.1.6 CAN message frame

13.1.6.1 CAN message format

The flag length of standard CAN is 11 bits, while the flag length of extended format CAN can CAN be up to 29 bits.

Version 2.0A of CAN protocol stipulates that the CAN controller must have an 11 bit flag.

At the same time, it is specified in version 2.0B that the flag length of CAN controller can be 11 bits or 29 bits.

Follow can2 The CAN controller of 0b protocol can send and receive 11 bit identifier standard format message or 29 bit identifier extended format message.

Comparison between standard frame and extended frame

frame format

Standard frame

Extended frame

standard

CAN2.0A

CAN2.0B

CAN ID (identifier) length

11 bits

29 bits

CAN ID (identifier) range

0x000~0x7FF

0x00000000~0x1FFFFFFF

13.1.6.2 CAN message frame type

CAN message types are divided into 5 frame types:

Data frame: a frame mainly used for transmitting data from the sender to the receiver;

Remote control frame: it is mainly used to receive the frame of data requested by the sender with the same ID in the direction;

Error frame: it is mainly used to notify other nodes of errors when errors are detected.

Overload frame: it is mainly used for the receiver to notify other frames that are not ready for reception.

Interval frame: it is mainly used to separate the data frame and remote control frame from the previous frame.

Among them, data frames are the most used frame types. Here we focus on the following data frames.

The data frame is shown in the figure below:

As shown in the above figure, the data frame includes:

(1) Frame start. A segment that represents the beginning of a data frame.

(2) Arbitration segment. A segment that represents the priority of the frame.

(3) Control segment. A segment that represents the number of bytes and reserved bits of data.

(4) Data segment. The content of data. 0 ~ 8 bytes of data can be sent in a frame.

(5) CRC segment. A segment that checks for frame transmission errors.

(6) ACK segment. Indicates the segment that confirms normal reception.

(7) End of frame. A segment that represents the end of a data frame.

For details, see "can2 0A”,”CAN2. "0b" details.

We mainly focus on several paragraphs that we need to pay attention to in programming:

ID: CAN message ID;

IDE: 0 is the standard frame and 1 is the extended frame;

RTR: 0 is the data frame and 1 is the remote frame;

DLC: CAN message data length, range 0 ~ 8 bytes;

Data: data, 0 ~ 8 bytes;

13.2 CAN programming framework creation

At present, what we are learning is application programming. In order to make the CAN programming framework universal and portable in the future, we create an abstract CAN application programming framework, which CAN be applied to MCU application programming or linux application programming.

Therefore, according to the general properties of CAN bus programming, we abstract the following properties:

attribute

Attribute description

explain

CAN port number

Describe CAN ports, such as CAN1, CAN2 and CAN3, which are related to specific hardware peripherals.

CAN transceiver configuration

Describe CAN transceiver mode settings. Transceiver modes include Normal, Stanley, Sleep, ListenOnly and other modes; The transceiver used in this section is the default hardware configuration, so it does not need to be configured.

CAN controller configuration

Describe CAN transceiver configuration, such as CAN baud rate configuration, sampling rate setting, filter setting, etc;

CAN interrupt configuration

Describe CAN interrupt receiving function configuration

Read CAN message

Describe the implementation of CAN read message

Send CAN message

Describe the implementation of CAN sending message

According to the attributes described in the above table, the CAN application programming framework is created as follows:

typedef struct _CAN_COMM_STRUCT
{
    /* CAN Hardware name */
    char name[10];
    /* CAN Port number, which is the port number in the bare metal machine; Socket socket interface in linux Application */
    int  can_port;                                
    /* CAN The controller configuration function returns the port number assigned to can_port */
    int  (*can_set_controller)( void );                  
    /* CAN Create an interface interrupt, and create a receiving thread in linux */
    void (*can_set_interrput)( int can_port , pCanInterrupt callback );             
    /* CAN Read message interface */
    void (*can_read)( int can_port , CanRxMsg* recv_msg);   
    /* CAN Send message interface*/
    void (*can_write)( int can_port , CanTxMsg send_msg);   
}CAN_COMM_STRUCT, *pCAN_COMM_STRUCT;

This framework can be applied to MCU by analogy, and can also be used in Linux socket can application programming.

13.3 STM32 CAN Application Programming

This section mainly uses the application programming framework in 14.2 to test the feasibility of the framework on the single chip microcomputer, and explains it with a basic case of receiving and sending;

13.3.1 STM32 CAN interface circuit

As shown in the figure below, it is the development board STM32 minimum system and CAN transceiver interface circuit used by STM32 routine in this chapter.

Figure 13.3 1-1 stm32f407 minimum system

Figure 13.3 1-1 tja1050 can transceiver interface circuit

13.3.2 STM32 CAN application programming steps

Next, we implement can application programming based on STM32 step by step according to the programming framework of CAN communication.

STM32 CAN application programming, the steps are as follows:

13.3. 2.1 preparation of STM32 engineering template

See code "01_stm32f407_can" routine in Chapter 14;

The development environment used is MDK 5.24

After opening the MDK project, see the following figure:

The directory in the above figure is CMSIS, STM32F407_LIB and main are the basic frameworks for STM32 operation.

Directory app_can is the file required for CAN application programming.

13.3. 2.2 write the implementation function of CAN abstract framework

(1) Define CAN port number

See "can_controller.h" file in code "01_stm32f407_can_addline" in Chapter 14.

Mainly according to the can of STM32 hardware, there are multiple channels, which are defined as can in turn_ PORTCAN1, CAN_ PORT_ Can2, etc. the current CAN1 can be known from "14.3.1 STM32 CAN interface circuit"

25 /* CAN Port number definition*/
26 enum
27 {
28     CAN_PORT_NONE = 0,
29     CAN_PORT_CAN1,
30     CAN_PORT_CAN2,
31     CAN_PORT_MAX
32 };

(2) Configure CAN controller

The configuration of CAN controller has three parts: GPIO(CAN_TX,CAN_RX pin) configuration, can baud rate configuration and can filter configuration.

See "can_controller.c" file int can in code "01_stm32f407_can_addline" in Chapter 14_ Set_ Controller (void) function.

A.GPIO(CAN_TX,CAN_RX pin) configuration

The configuration GPIO code is as follows:

96     /*************************************************************/
97     /*CAN Relevant GPIO configuration, here is: CAN_TX, CAN_RX*/
98
99     /*Enable GPIO clock*/
100     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
101     /*Initialize pin configuration*/
102     GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_0 ;
103     GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_AF;
104     GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
105     GPIO_InitStructure.GPIO_OType   = GPIO_OType_PP;
106     GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_UP;
107     GPIO_Init(GPIOD, &GPIO_InitStructure);
108
109     GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_1;
110     GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_AF;
111     GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
112     GPIO_InitStructure.GPIO_OType   = GPIO_OType_PP;
113     GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_UP;
114     GPIO_Init(GPIOD, &GPIO_InitStructure);
115     /*Set GPIO to CAN multiplexing mode*/
116     GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_CAN1);
117     GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_CAN1);

B. Configure baud rate and working mode

According to the following code, enable the CAN peripheral, set the CAN working mode to Normal, and set the baud rate to 500kbps.

119     /*************************************************************/
120     /*CAN Related configuration of controller, baud rate, sampling rate, etc*/
121
122     /* Enable CAN clock */
123     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
124
125     /* Initialize CAN controller operating mode*/
126     CAN_DeInit(CAN1);
127     CAN_StructInit(&CAN_InitStructure);
128     CAN_InitStructure.CAN_TTCM = DISABLE;
129     CAN_InitStructure.CAN_ABOM = DISABLE;
130     CAN_InitStructure.CAN_AWUM = DISABLE;
131     CAN_InitStructure.CAN_NART = DISABLE;
132     CAN_InitStructure.CAN_RFLM = DISABLE;
133     CAN_InitStructure.CAN_TXFP = DISABLE;
134     CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;//CAN operating mode
135
136     /* Initialize CAN baud rate */
137     CAN_Baud_Process(500,&CAN_InitStructure);
138     CAN_Init(CAN1, &CAN_InitStructure);

The function of configuring baud rate is a user-defined function, which can not be understood here. You only need to know that it is configuring baud rate. If you need to use the code in this chapter, you can view the specific source code project.

C. Configure CAN filter

The following code configures the filter:

141     /*************************************************************/
142     /* Initialize CAN filter */
143     CAN_FilterInitStructure.CAN_FilterNumber = 0;                       /* CAN1 Filter numbers range from 0 to 13 */
144     CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;     /* Filter shielding mode */
145     CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
146     CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
147     CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
148     CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;      /* No ID is masked */
149     CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;           /* No ID is masked */
150     CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0;
151
152     CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
153     CAN_FilterInit(&CAN_FilterInitStructure);
154
155     /*************************************************************/
156     /* After setting the CAN, return to the port number of the currently set CAN, which is mainly similar to the socket interface in Linux socket CAN */

Here we set the filter not to shield any message ID. here we just understand some processes under the single chip microcomputer.

(3) Configure CAN receive interrupt

CAN bus supports sending interrupt and receiving interrupt. Only receiving interrupt is used here.

See "can_controller.c" file void can in code "01_stm32f407_can_addline" in Chapter 14_ Set_ Interrupt (int can_port, pcaninterrupt callback) function.

CAN interrupt configuration code is as follows:

163 /**********************************************************************
164 * Function name: void CAN_Set_Interrupt(int can_port,  pCanInterrupt callback)
165 * Function Description: enable CAN interrupt processing and transfer it to the callback function of the application. The callback function mainly deals with the functions of the application layer
166 * Input parameter: can_port, port number
167 *            callback:  The callback function that interrupts the specific processing application function
168 * Output parameters: None
169 * Return value: None
170 * Modification date version number modified by
171 * -----------------------------------------------
172 * 2020/05/13         V1.0             bert            establish
173 ***********************************************************************/
174 void CAN_Set_Interrupt(int can_port,  pCanInterrupt callback)
175 {
176     NVIC_InitTypeDef NVIC_InitStructure;
177
178     /* Configure the interrupt according to the CAN port number */
179     switch( can_port )
180     {
181         case CAN_PORT_CAN1:
182         {
183             /* Initialize callback interface function */
184             if ( NULL != callback )
185             {
186                 g_pCanInterrupt = callback;
187             }
188
189             /* Use CAN0_RX interrupt is similar to creating a receiving thread in linux socket can */
190             NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
191             NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
192             NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
193             NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
194             NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
195             NVIC_Init(&NVIC_InitStructure);
196             CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
197         }
198         break;
199
200         default:
201             break;
202
203     }
204     return ;
205 }

CAN receive interrupt function is as follows:

275 /**********************************************************************
276 * Function name: void CAN1_RX0_IRQHandler(void)
277 * Function Description: CAN receive interrupt function
278 * Input parameters: None
279 * Output parameters: None
280 * Return value: None
281 * Modification date version number modified by
282 * -----------------------------------------------
283 * 2020/05/13         V1.0             bert            establish
284 ***********************************************************************/
285 void CAN1_RX0_IRQHandler(void)
286 {
287     /* If the callback function exists, the callback function is executed */
288     if( g_pCanInterrupt != NULL)
289     {
290         g_pCanInterrupt();
291     }
292
293     /* Clear pending interrupt */
294     CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);
295 }

Here CAN interrupt through callback function G_ The pcaninterrupt() function layers the code required by the application layer to the application layer. Here is the general interface of the driving part.

(4) CAN message reading function

When the CAN receiving interrupt is generated, read the received CAN message from FIFO through the CAN message reading function.

See "can_controller.c" file void can in code "01_stm32f407_can_addline" in Chapter 14_ Read (int can_port, canrxmsg * recv_msg) function.

CAN message reading function is as follows:

208 /**********************************************************************
209 * Function name: void CAN_Read(int can_port, CanRxMsg* recv_msg)
210 * Function Description: CAN reads the receiving register and takes out the received message
211 * Input parameter: can_port, port number
212 * Output parameter: recv_msg: receive message
213 * Return value: None
214 * Modification date version number modified by
215 * -----------------------------------------------
216 * 2020/05/13         V1.0             bert            establish
217 ***********************************************************************/
218 void CAN_Read(int can_port, CanRxMsg* recv_msg)
219 {
220     switch( can_port )
221     {
222         case CAN_PORT_CAN1:
223         {
224             /* Read CAN message from FIFO */
225             CAN_Receive(CAN1,CAN_FIFO0, recv_msg);
226         }
227         break;
228
229         default:
230             break;
231     }
232     return ;
233 }

(5) CAN message sending function

When it is necessary to send CAN message, start sending message by sending mailbox filling data to CAN.

See "can_controller.c" file void can in code "01_stm32f407_can_addline" in Chapter 14_ Write (int can_port, cantxmsg send_msg) function.

CAN message reading function is as follows:

235 /**********************************************************************
236 * Function name: void CAN_Write(int can_port, CanTxMsg send_msg)
237 * Function Description: CAN message sending interface, call sending register to send message
238 * Input parameter: can_port, port number
239 * Output parameter: send_msg: send message
240 * Return value: None
241 * Modification date version number modified by
242 * -----------------------------------------------
243 * 2020/05/13         V1.0             bert            establish
244 ***********************************************************************/
245 void CAN_Write(int can_port, CanTxMsg send_msg)
246 {
247     unsigned char i;
248     uint8_t transmit_mailbox = 0;
249     CanTxMsg TxMessage;
250
251     switch( can_port )
252     {
253         case CAN_PORT_CAN1:
254         {
255             TxMessage.StdId = send_msg.StdId;     // The standard identifier is 0x000~0x7FF
256             TxMessage.ExtId = 0x0000;             // Extension identifier 0x0000
257             TxMessage.IDE   = CAN_ID_STD;         // Use standard identifier
258             TxMessage.RTR   = CAN_RTR_DATA;       // Set as data frame
259             TxMessage.DLC   = send_msg.DLC;       // Data length: the maximum data length specified in can message is 8 bytes
260
261             for(i=0; i<TxMessage.DLC; i++)
262             {
263                 TxMessage.Data[i] = send_msg.Data[i];
264             }
265             transmit_mailbox = CAN_Transmit(CAN1,&TxMessage);  /* Return the mailbox number 0,1,2 of this information request or no mailbox request to send no_box */
266         }
267         break;
268
269         default:
270             break;
271     }
272     return ;
273 }

(6) CAN abstract structure framework initialization

Define a Can1 communication structure instance CAN_COMM_STRUCT can1_controller;

Using the functions implemented in steps (1) ~ (5), initialize can1_controller to form a connection point associated with the application layer.

298 /**********************************************************************
299 * Name: can1_controller
300 * Function Description: CAN1 structure initialization
301 * Modification date version number modified by
302 * -----------------------------------------------
303 * 2020/05/13         V1.0             bert            establish
304 ***********************************************************************/
305 CAN_COMM_STRUCT can1_controller = {
306     .name                   = "can0",
307     .can_port               = CAN_PORT_CAN1,
308     .can_set_controller     = CAN_Set_Controller,
309     .can_set_interrput      = CAN_Set_Interrupt,
310     .can_read               = CAN_Read,
311     .can_write              = CAN_Write,
312 };

13.3. 2.3 writing CAN application layer code

According to 14.3 2.2 the specific CAN hardware operation has been realized, and the CAN programming framework has been abstractly instantiated.

But we haven't connected to the application layer yet. The application layer doesn't know which interface to call.

(1) CAN application layer registration instance

Write a general instantiation registration function in the application layer.

See "app_can.c" file int register in code "01_stm32f407_can_addline" in Chapter 14_ can_ Controller (const pcan_comm_struct p_can_controller) function.

The code implementation is as follows:

62 /**********************************************************************
63 * Function name: int register_can_controller(const pCAN_COMM_STRUCT p_can_controller)
64 * Function Description: the application layer registers CAN1 structure
65 * Input parameter: p_can_controller, abstract structure of CAN controller
66 * Output parameters: None
67 * Return value: None
68 * Modification date version number modified by
69 * -----------------------------------------------
70 * 2020/05/13         V1.0             bert            establish
71 ***********************************************************************/
72 int register_can_controller(const pCAN_COMM_STRUCT p_can_controller)
73 {
74     /* Judge incoming p_ can_ The controller is non empty to confirm that the structure is an entity*/
75     if( p_can_controller != NULL )
76     {
77         /* The passed in parameter p_ can_ The controller is assigned to the application layer structure gCAN_COMM_STRUCT */
78
79         /*Port number, analog socket can socket*/
80         gCAN_COMM_STRUCT.can_port              = p_can_controller->can_port;
81         /*CAN Controller configuration function*/
82         gCAN_COMM_STRUCT.can_set_controller    = p_can_controller->can_set_controller;
83         /*CAN Interrupt configuration*/
84         gCAN_COMM_STRUCT.can_set_interrput     = p_can_controller->can_set_interrput;
85         /*CAN Message reading function*/
86         gCAN_COMM_STRUCT.can_read              = p_can_controller->can_read;
87         /*CAN Message sending function*/
88         gCAN_COMM_STRUCT.can_write             = p_can_controller->can_write;
89         return 1;
90     }
91      return 0;
92 }

Then by calling register_ can_ controller( &can1_controller ); Set instance Can1_ The controller is registered with the 4 static can of the application_ COMM_ STRUCT gCAN_ COMM_ STRUCT;

After that, the application layer only needs to call its own gcan_ COMM_ The structure instance CAN operate the CAN communication function.

315 /**********************************************************************
316 * Function name: void CAN1_contoller_add(void)
317 * Function Description: CAN structure registration interface. CAN1 is used in the application layer_ Controller prior call
318 * Input parameters: None
319 * Output parameters: None
320 * Return value: None
321 * Modification date version number modified by
322 * -----------------------------------------------
323 * 2020/05/13         V1.0             bert            establish
324 ***********************************************************************/
325 void CAN1_contoller_add(void)
326 {
327     /*Set Can1_ The controller is passed to the application layer*/
328     register_can_controller( &can1_controller );
329 }

(2) CAN application layer initialization

CAN application layer initialization code is as follows:;

94 /**********************************************************************
95 * Function name: void app_can_init(void)
96 * Function Description: CAN application layer initialization
97 * Input parameters: None
98 * Output parameters: None
99 * Return value: None
100 * Modification date version number modified by
101 * -----------------------------------------------
102 * 2020/05/13         V1.0             bert            establish
103 ***********************************************************************/
104 void app_can_init(void)
105 {
106     /**
107     * Application layer for CAN1 structure registration
108     */
109     CAN1_contoller_add();
110
111     /*
112     *Call can_ set_ The controller configures the CAN controller,
113     *Return to can_port, similar to the socket interface in linux socketcan, it is used as a custom CAN channel in the MCU routine
114     */
115     gCAN_COMM_STRUCT.can_port = gCAN_COMM_STRUCT.can_set_controller();
116     /**
117     * Call can_set_interrput configures the CAN receiving interrupt, which is similar to the receiving thread in socketcan
118     */
119     gCAN_COMM_STRUCT.can_set_interrput( gCAN_COMM_STRUCT.can_port, CAN_RX_IRQHandler_Callback );
120 }

(3) Design a simple periodic message sending function

The function code of CAN periodic sending message is realized as follows:

123 /**********************************************************************
124 * Function name: void app_can_tx_test(void)
125 * Function Description: CAN application layer message sending function, which is used to send messages in test cycle
126 * Input parameters: None
127 * Output parameters: None
128 * Return value: None
129 * Modification date version number modified by
130 * -----------------------------------------------
131 * 2020/05/13         V1.0             bert            establish
132 ***********************************************************************/
133 void app_can_tx_test(void)
134 {
135     // Run the CAN test program based on 10ms
136
137     unsigned char i=0;
138
139     /* Send message definition */
140     CanTxMsg TxMessage;
141
142     /* A byte is used as a counter in the sent message */
143     static unsigned char tx_counter = 0;
144
145     /* Taking 10ms as the benchmark, set the period of running code after the processing function to 1 second through the timer counter*/
146     static unsigned int timer =0;
147     if(timer++>100)
148     {
149         timer = 0;
150     }
151     else
152     {
153         return ;
154     }
155
156     /* Send message data filling, and the message cycle is 1 second */
157     TxMessage.StdId = TX_CAN_ID;          /* The standard identifier is 0x000~0x7FF */
158     TxMessage.ExtId = 0x0000;             /* Extension identifier 0x0000 */
159     TxMessage.IDE   = CAN_ID_STD;         /* Use standard identifier */
160     TxMessage.RTR   = CAN_RTR_DATA;       /* Set as data frame  */
161     TxMessage.DLC   = 8;                  /* Data length: the maximum data length specified in can message is 8 bytes */
162
163     /* Fill data, which can be filled according to the actual application */
164     TxMessage.Data[0] = tx_counter++;       /* Counter used to identify message sending */
165     for(i=1; i<TxMessage.DLC; i++)
166     {
167         TxMessage.Data[i] = i;
168     }
169
170     /*  Call can_write send CAN message */
171     gCAN_COMM_STRUCT.can_write(gCAN_COMM_STRUCT.can_port, TxMessage);
172
173 }

(4) Design a simple message receiving function

220 /**********************************************************************
221 * Function name: void CAN_RX_IRQHandler_Callback(void)
222 * Function Description: CAN1 receive interrupt function; In linux, you CAN use threads or timers to read CAN data
223 * Input parameters: None
224 * Output parameters: None
225 * Return value: None
226 * Modification date version number modified by
227 * -----------------------------------------------
228 * 2020/05/13         V1.0             bert            establish
229 ***********************************************************************/
230 void CAN_RX_IRQHandler_Callback(void)
231 {
232     /* Definition of received message */
233     CanRxMsg RxMessage;
234
235     /* Reset received message */
236     memset( &RxMessage, 0, sizeof(CanRxMsg) );
237
238     /* Via can_ The read interface reads the message received by the register */
239     gCAN_COMM_STRUCT.can_read(gCAN_COMM_STRUCT.can_port, &RxMessage);
240
241     /* Copy the read can message to the global message structure g_CAN1_Rx_Message */
242     memcpy(&g_CAN1_Rx_Message, &RxMessage, sizeof( CanRxMsg ) );
243
244     /* Set the current reception completion flag and judge that the current received message ID is RX_CAN_ID, set g_CAN1_Rx_Flag=1*/
245     if( g_CAN1_Rx_Message.StdId == RX_CAN_ID )
246     {
247         g_CAN1_Rx_Flag = 1;
248     }
249 }
176 /**********************************************************************
177 * Function name: void app_can_rx_test(void)
178 * Function Description: the CAN application layer receives the message processing function, which is used to process the message received in the interrupt function
179 * Input parameters: None
180 * Output parameters: None
181 * Return value: None
182 * Modification date version number modified by
183 * -----------------------------------------------
184 * 2020/05/13         V1.0             bert            establish
185 ***********************************************************************/
186 void app_can_rx_test(void)
187 {
188     unsigned char i=0;
189
190     /* Send message definition */
191     CanTxMsg TxMessage;
192
193     /* A byte is used as a counter in the sent message */
194     static unsigned char rx_counter = 0;
195
196
197     if( g_CAN1_Rx_Flag == 1)
198     {
199         g_CAN1_Rx_Flag = 0;
200
201         /* Send message data filling, and the message cycle is 1 second */
202         TxMessage.StdId = RX_TO_TX_CAN_ID;    /* The standard identifier is 0x000~0x7FF */
203         TxMessage.ExtId = 0x0000;             /* Extension identifier 0x0000 */
204         TxMessage.IDE   = CAN_ID_STD;         /* Use standard identifier */
205         TxMessage.RTR   = CAN_RTR_DATA;       /* Set as data frame  */
206         TxMessage.DLC   = 8;                  /* Data length: the maximum data length specified in can message is 8 bytes */
207
208         /* Fill data, which can be filled according to the actual application */
209         TxMessage.Data[0] = rx_counter++;      /* Counter used to identify message sending */
210         for(i=1; i<TxMessage.DLC; i++)
211         {
212             TxMessage.Data[i] = g_CAN1_Rx_Message.Data[i];
213         }
214
215         /*  Call can_write send CAN message */
216         gCAN_COMM_STRUCT.can_write(gCAN_COMM_STRUCT.can_port, TxMessage);
217     }
218 }

13.3.2.4 STM32 CAN case test

After writing the code in the previous chapters, let's do a test;

The test tools are Valuecan3(CAN protocol box) and Vehicle Vspy3 (computer software) of interbest.

You CAN also buy a cheap USB to CAN tool on Taobao.

The test steps are as follows:

Step 1: download the completed STM32 CAN test program to the actual development board;

Step 2: Send a message with message ID 0X201 through CAN test tool Vehicle Vspy3;

Step 3: observe the CAN test software display as follows:

The message with message ID 0x101 is sent according to 1-second cycle, as shown in Figure 14.3 2.4-1.

The message with message ID 0x201 is sent by Vehicle Spy3 to STM32 development board according to the cycle of 500ms, as shown in Figure 14.3 2.4-1

The message with message ID 0x301 is transferred to the message with message ID 0x301 after receiving the message with message ID 0x201, as shown in Figure 14.3 2.4-2.

Figure 13.3 2.4-1 message sending result viewing

Figure 13.3 2.4-2 viewing message reception

13.4 basic application programming of Linux socketcan

13.4.1 socketcan overview

socketcan is an implementation method of CAN protocol (Controller Area Network) under Linux. Can is a network technology widely used in the fields of automatic control, embedded equipment and automobile all over the world. The earliest method of using can under Linux is based on character device. The difference is that Socket CAN uses Berkeley's socket interface and Linux network protocol stack. This method enables can device driver to call through network interface. The Socket CAN interface is designed to be as close to the TCP/IP protocol as possible, so that programmers familiar with network programming can learn and use it easily.

The main purpose of using Socket CAN is to provide socket interface based on Linux network layer for user space applications. Different from the well-known TCP/IP protocol and Ethernet, can bus has no MAC layer address similar to Ethernet and can only be used for broadcasting. CAN ID is only used for bus arbitration. Therefore, the CAN ID must be unique on the bus. When designing a CAN-ECU(Electronic Control Unit) network, the can message ID can be mapped to a specific ECU. Therefore, the can message ID can be used as the address of the sending source.

13.4. 2. Basic knowledge of socketcan

In "14.3 STM32 CAN Application Programming", we have completely constructed the CAN application programming framework. However, in linux application programming, the idea of operating the CAN underlying driver is similar to that of STM32, but the operation methods or called interfaces are still very different, because STM32 is an SDK package or register directly called, However, linux system needs to call system commands or linux CAN driver to realize the operation of the physical layer.

Therefore, here we focus on some system call commands on linux and some concepts related to socket can.

13.4.2.1 CAN equipment operation

CAN equipment has three functions: on, off and parameter setting. Because the CAN device under linux is a way to simulate network operation, the opening, closing and setting of the CAN device here are operated through ip commands.

At 100ask_ Open the serial port on the imx6ull development board and use "ifconfig -a" to view all network nodes. It is found that the first node is "can0".

(1) Linux CAN device on:

#define ip_ cmd_ Open "ifconfig CAN0 up" / * open CAN0*/

Description: can0: can device name;

up: open device command

(2) Linux CAN device shutdown:

#define ip_ cmd_ Close "ifconfig CAN0 down" / * close CAN0*/

Description: can0: can device name;

down: shutdown device command

(2) Linux CAN parameter settings (baud rate, sampling rate):

#define ip_cmd_set_can_params "ip link set can0 type can bitrate 500000 triple-sampling on"

/* Set CAN0 baud rate to 500000 bps */

Description: can0: can device name;

down: shutdown device command

Type can: the device type is can

Bitrate 500000: baud rate is set to 500kbps

Triple sampling on: sampling on

13.4. 2.2 what is Socket socket interface

In linux, the network operation uses socket to create the interface. Unexpectedly, the CAN device is also a virtual network interface and a socket socket interface.

As shown in the figure below, telephone A calls telephone b, telephone A will enter the number of telephone b, and telephone B will receive an incoming call from telephone A.

Phone A and phone B are two endpoints. The linux socket interface is similar to this telephone communication. The socket interface is A communication endpoint, and there is A communication link between the endpoints; Telephone communication is dial-up communication through telephone number, and socket interface uses address to identify each other.

Figure 13.2 2.2 telephone communication model

13.4.2.3 Socket interface function

If we want to create and use socket sockets for communication programming, we need to understand the socket related interface functions.

If you need to query the functions in the linux system, you can view them through the man command.

give an example:

man socket / * view socket function description*/

(1) socket() function

Under linux system, query socket() function through "man socket" command is described as follows:

The prototype of Socket function is as follows:

#include <sys/types.h>     

#include <sys/socket.h>

int socket(int domain, int type, int protocol);  /* Socket function prototype */

The three parameters of the function are as follows:

Domain: protocol domain, It is also called protocol family. The commonly used protocol families include AF_INET, AF_INET6, AF_LOCAL (or AF_UNIX, Unix domain socket), AF_ROUTE, etc. the protocol family determines the address type of socket, and the corresponding address must be used in communication. For example, AF_INET determines the ipv4 address (32-bit) and port number to be used The combination of (16 bit), AF_UNIX determines to use an absolute pathname as the address.

Type: Specifies the socket type. The commonly used socket types are SOCK_STREAM,SOCK_DGRAM,SOCK_RAW,SOCK_PACKET,SOCK_SEQPACKET, etc.

Protocol: Specifies the protocol. Commonly used protocols are IPPROTO_TCP,IPPTOTO_UDP,IPPROTO_SCTP,IPPROTO_TIPC, etc., which correspond to TCP transmission protocol, UDP transmission protocol, STCP transmission protocol and TIPC transmission protocol respectively.

be careful:

​ 1. The above type and protocol can not be combined at will, such as SOCK_STREAM cannot be associated with IPPROTO_UDP combination. When the protocol is 0, the default protocol corresponding to the type will be automatically selected.

When we call socket to create a socket, the returned socket descriptor exists in the address family (AF_XXX) space, but does not have a specific address. If you want to assign an address to it, you must call the bind() function. Otherwise, when you call connect() and listen(), the system will automatically assign a port at random.

​ 2. The domain protocol domain used by socketcan is AF_ Can (or PF_CAN), type is SOCK_RAW, specifies that the protocol is CAN_RAW.

(2) bind() function

Under linux system, query the bind() function through the "man bind" command. The description is as follows:

The bind() function assigns a specific address in an address family to the socket. For example, corresponding to AF_INET,AF_INET6 is to assign an ipv4 or ipv6 address and port number combination to the socket.

The Bind function prototype is as follows:

#include <sys/types.h>          
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

The three parameters of the function are:

sockfd: socket descriptor, which is created by socket() function and uniquely identifies a socket. The bind() function is to bind a name to this descriptor.

addr: a const struct sockaddr * pointer to the protocol address to be bound to sockfd. The address structure is different according to the address protocol family when creating the socket,

For example, ipv4 corresponds to:

struct sockaddr_in {
    sa_family_t    sin_family;   /* address family: AF_INET */
    in_port_t      sin_port;    /* port in network byte order */
    struct in_addr sin_addr;     /* internet address */
};
/* Internet address. */struct in_addr {
    uint32_t       s_addr;     /* address in network byte order */
};

ipv6 corresponds to:

struct sockaddr_in6 { 
    sa_family_t     sin6_family;   /* AF_INET6 */ 
    in_port_t       sin6_port;     /* port number */ 
    uint32_t        sin6_flowinfo; /* IPv6 flow information */ 
    struct in6_addr  sin6_addr;     /* IPv6 address */ 
    uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */ 
};
struct in6_addr { 
    unsigned char   s6_addr[16];   /* IPv6 address */ 
};

Unix domain corresponds to:

#define UNIX_PATH_MAX  108
struct sockaddr_un { 
  sa_family_t sun_family;        /* AF_UNIX */ 
  char    sun_path[UNIX_PATH_MAX]; /* pathname */ 
};

The CAN domain corresponds to:

It is defined in the file "Linux-4.9.88\include\uapi\linux\can.h", which is the focus of this chapter.

/**
 * struct sockaddr_can - CAN sockets Address structure of
 * @can_family:  Address protocol family AF_CAN.
 * @can_ifindex:  CAN Network interface index
 * @can_addr:    Protocol address information
 */
struct sockaddr_can {
	__kernel_sa_family_t can_family;
	int         can_ifindex;
	union {
		/* Transmission protocol class address information (e.g. ISOTP) */
		struct { canid_t rx_id, tx_id; } tp;

		/* CAN protocol address information reserved for future use*/
	} can_addr;
};

addrlen: corresponds to the length of the address.

Usually, when the server starts, it will bind a well-known address (such as ip address + port number) to provide services, and the client can connect to the server through it. The client does not need to specify it. The system automatically assigns a combination of port number and its own ip address. This is why the server usually calls bind() before listen, The client will not call, but will be randomly generated by the system when connect().

(3) ioctl() function

Under linux system, query ioctl() function through "man ioctl" command. The description is as follows:

The call hierarchy of Ioctl() function is shown in the following figure:

The prototype of Ioctl() function is as follows:

#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);

Two structures ifconf and ifreq are used to obtain the local network interface address with ioctl.

struct ifreq definition ifreq is used to store the information of an interface.

struct ifreq is defined in the file "Linux-4.9.88\include\uapi\linux\if.h". This only needs to be understood that it is used to obtain the CAN device index (ifr_ifindex) when ioctl() function is called. Other parameters CAN be ignored.

/*
 * Interface request structure used for socket
 * ioctl's.  All interface ioctl's must have parameter
 * definitions which begin with ifr_name.  The
 * remainder may be interface specific.
 */

/* for compatibility with glibc net/if.h */
#if __UAPI_DEF_IF_IFREQ
struct ifreq {
#define IFHWADDRLEN	6
	union
	{
		char	ifrn_name[IFNAMSIZ];		/* if name, e.g. "en0" */
	} ifr_ifrn;
	
	union {
		struct	sockaddr ifru_addr;
		struct	sockaddr ifru_dstaddr;
		struct	sockaddr ifru_broadaddr;
		struct	sockaddr ifru_netmask;
		struct  sockaddr ifru_hwaddr;
		short	ifru_flags;
		int	ifru_ivalue;
		int	ifru_mtu;
		struct  ifmap ifru_map;
		char	ifru_slave[IFNAMSIZ];	/* Just fits the size */
		char	ifru_newname[IFNAMSIZ];
		void __user *	ifru_data;
		struct	if_settings ifru_settings;
	} ifr_ifru;
};
#endif /* __UAPI_DEF_IF_IFREQ */

#define ifr_name	ifr_ifrn.ifrn_name	/* interface name 	*/
#define ifr_hwaddr	ifr_ifru.ifru_hwaddr	/* MAC address 		*/
#define	ifr_addr	ifr_ifru.ifru_addr	/* address		*/
#define	ifr_dstaddr	ifr_ifru.ifru_dstaddr	/* other end of p-p lnk	*/
#define	ifr_broadaddr	ifr_ifru.ifru_broadaddr	/* broadcast address	*/
#define	ifr_netmask	ifr_ifru.ifru_netmask	/* interface net mask	*/
#define	ifr_flags	ifr_ifru.ifru_flags	/* flags		*/
#define	ifr_metric	ifr_ifru.ifru_ivalue	/* metric		*/
#define	ifr_mtu		ifr_ifru.ifru_mtu	/* mtu			*/
#define ifr_map		ifr_ifru.ifru_map	/* device map		*/
#define ifr_slave	ifr_ifru.ifru_slave	/* slave device		*/
#define	ifr_data	ifr_ifru.ifru_data	/* for use by interface	*/
#define ifr_ifindex	ifr_ifru.ifru_ivalue	/* interface index	*/
#define ifr_bandwidth	ifr_ifru.ifru_ivalue    /* link bandwidth	*/
#define ifr_qlen	ifr_ifru.ifru_ivalue	/* Queue length 	*/
#define ifr_newname	ifr_ifru.ifru_newname	/* New name		*/
#define ifr_settings	ifr_ifru.ifru_settings	/* Device/proto settings*/

struct ifconf definition ifconf is usually used to save all interface information. It is not used in this chapter and will not be described in detail here.

(4) setsockopt() function

Under linux system, query setsockopt() function through "man setsockopt" command. The description is as follows:

The prototypes of setsockopt() and getsockopt functions are as follows:

#include <sys/types.h>    
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

Setsockopt() is used for any type and any state Socket interface Set option value for. Although there are options at different protocol layers, this function only defines the options at the highest "socket" level.

The function parameters are as follows:

sockfd: a descriptor that identifies a socket interface.

Level: the level defined by the option; Support SOL_SOCKET,IPPROTO_TCP,IPPROTO_IP,IPPROTO_IPV6,SOL_CAN_RAW et al.

optname: options to be set.

optval: pointer to the buffer where the new value of the option to be set is stored.

optlen: length of optval buffer.

Examples of function calls are as follows:

Example 1: set the CAN filter to not receive all messages.

//Disable the filtering rule. This process does not receive messages and is only responsible for sending them. / / set the filtering rule setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);

Example 2: set the CAN filter to receive a specified message

//Define the receiving rule, and only receive messages with the symbol 0x201. / / it is defined in the linux header file, or you can define #define can by yourself_ SFF_ Mask 0x000007ffu / / define a filter (1) struct can_filter rfilter [1]; rfilter [0]. Can_id = 0x201; rfilter [0]. Can_mask = can_sff_mask. / / set the filter rule setsockopt (s, sol_, can_raw, can_filter, & rfilter, sizeof (rfilter));

Example 2: set the CAN filter to receive a specified message

//Define the receiving rule, and only receive messages with the symbol 0x201. / / it is defined in the linux header file, or you can define #define can by yourself_ SFF_ Mask 0x000007ffu / / define filters (3): struct can_filter rfilter[3]; rfilter[0].can_id = 0x201; rfilter[0].can_mask = CAN_SFF_MASK; rfilter[1].can_id = 0x401; rfilter[1].can_mask = CAN_SFF_MASK; rfilter[2].can_id = 0x601; rfilter[2].can_mask = CAN_SFF_MASK; / / set the filter rule setsockopt (s, sol_can_raw, can_raw_filter, & rfilter, sizeof (rfilter));

(5) write() function

Under linux system, query the write() function through the "man 2 write" command. The description is as follows:

The prototype of Write function is as follows:

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

(6) read() function

Under linux system, query the read() function through the "man 2 read" command. The description is as follows:

The prototype of Read function is as follows:

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);

(7) close() function

Under linux system, query the close() function through the "man 2 close" command. The description is as follows:

The prototype of the close() function is as follows:

#include <unistd.h>
int close(int fd);

13.4.3 socket_can simple sending example

Simple send instance code directory: "02_socketcan_send"

Case description:

  1. Send the message with message ID: 0x101 within 1 second;

Understanding content: IMX6 CAN interface circuit

From the following CAN peripheral circuit, it is exactly the same as STM32, but it only deals with the internal CAN controller. There will be some small differences due to different chip manufacturers. The circuit here is just a comparison. linux applications do not need to pay attention to the underlying driver processing.

Now we build the framework of CAN application programming under STM32 according to chapter 14.3, and write the application programming of socket CAN under linux step by step.

preparation:

We have prepared the code file of can application according to chapter 14.3:

file name

File content description

App_can.c

Realization of CAN application function

App_can.h

CAN application function header file

Can_controller.c

Concrete implementation of CAN drive operation abstraction layer

Can_controller.h

CAN driver operation abstraction layer header file

Can_msg.h

The basic structure of CAN message, copied from STM32 CAN driver, mainly uses the structure we are most familiar with when using CAN message. This file is a new file relative to STM32, because our framework is based on MCU application, and then analogically migrate to linux.

Makefile

Makefile compilation script

13.4. 3.1 write the implementation function of the abstract framework

First, we use the abstract structure already built in Chapter 14.3, as follows:

See "can_controller.h" in code "02_socketcan_send_addline" in Chapter 14.

34 /* CAN Communication abstract structure definition*/
35 typedef struct _CAN_COMM_STRUCT
36 {
37     /* CAN Hardware name */
38     char *name;
39     /* CAN Port number, which is the port number in the bare metal machine; Socket socket interface in linux Application */
40     int  can_port;                                
41     /* CAN The controller configuration function returns the port number assigned to can_port */
42     int  (*can_set_controller)( void );                  
43     /* CAN Create an interface interrupt, and create a receiving thread in linux */
44     void (*can_set_interrput)( int can_port , pCanInterrupt callback );             
45     /* CAN Read message interface */
46     void (*can_read)( int can_port , CanRxMsg* recv_msg);   
47     /* CAN Send message interface*/
48     void (*can_write)( int can_port , CanTxMsg send_msg);   
49 }CAN_COMM_STRUCT, *pCAN_COMM_STRUCT;
50 

We write CAN in the order of this structure_ controller. C CAN drive operation specific implementation function.

(1) Define CAN devices

According to 14.4 Chapter 2.1 describes that the linux application layer needs to know the device name to operate the CAN device

At 100ask_ Open the serial port on the imx6ull development board, use the "ifconfig -a" command to check, and know that the current CAN device name is "can0".

You CAN turn on, set up, and turn off CAN devices directly using IP commands on the linux command line. Therefore, we define three macro IPS_ cmd_ open, ip_ cmd_ close,ip_ cmd_ set_ CAN_ Params, these three macros CAN be executed through the system call system().

See the macro definition in the "can_controller.c" file in the code "02_socketcan_send_addline" in Chapter 14.

29 /**************Macro definition**************************************************/
30 
31 /* Set CAN0 baud rate to 500000 bps */
32 #define ip_cmd_set_can_params  "ip link set can0 type can bitrate 500000 triple-sampling on"
33 
34 /* Open CAN0 */
35 #define ip_cmd_open            "ifconfig can0 up"     
36 
37 /* Close CAN0 */    
38 #define ip_cmd_close           "ifconfig can0 down"   

(2) Configure CAN controller

There are three parts to configure CAN controller: open can0 device, CAN baud rate configuration and CAN filter configuration.

See "can_controller.c" file int can in code "01_stm32f407_can_addline" in Chapter 14_ Set_ Controller (void) function.

A. Configure baud rate and open can0 device

Use the three commands in (1) ip_cmd_open, ip_cmd_close,ip_cmd_set_can_params to call through the system: the specific code is as follows:

77     /* Set the CAN baud rate by calling the ip command through the system */
78     system(ip_cmd_close);               
79     system(ip_cmd_set_can_params);
80     system(ip_cmd_open);

B. Create socket

Because linux application operating devices use read and write operations, everything in linux is a file, and socketcan is a special file, so we need to call socket() function to create a socketcan interface and obtain the socket_ FD descriptor.

The specific codes are as follows:

82   /*************************************************************/
83   /* Create socket sock_fd */
84   sock_fd = socket(AF_CAN, SOCK_RAW, CAN_RAW);
85 	if(sock_fd < 0)
86 	{
87 		perror("socket create error!\n");
88 		return -1;
89 	}

C. Binding can0 device and socket interface

The specific codes are as follows:

92   //Bind socket to can0
93   strcpy(ifr.ifr_name, "can0");
94 	ioctl(sock_fd, SIOCGIFINDEX,&ifr); // Set device to can0
95 
96 	ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name);
97 	printf("ifr_name:%s \n",ifr.ifr_name);
98 	printf("can_ifindex:%d \n",ifr.ifr_ifindex);
99 
100 addr.can_family = AF_CAN;
101 addr.can_ifindex = ifr.ifr_ifindex;
102 		
103 if( bind(sock_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0 )
104 {
105 	perror("bind error!\n");
106 	return -1;
107 }

C. Configure filter

The specific codes are as follows:

109 	/*************************************************************/
110 	//The filtering rule is disabled. This process does not receive messages and is only responsible for sending them
111  setsockopt(sock_fd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); 

D. Configure non blocking operations

The read and write functions called by Linux system are blocked and non blocked. When calling in a cycle, we use the non blocking method to read and write the CAN message.

The specific code is as follows:

114     //Set the read() and write() functions to non blocking mode
115     int flags;
116     flags = fcntl(sock_fd, F_GETFL);
117     flags |= O_NONBLOCK;
118     fcntl(sock_fd, F_SETFL, flags);  

E. Return sock_fd socket

The specific code is as follows:

int CAN_ Set_ After the controller (void) function ends directly, the return value is assigned to the can_ COMM_ Can of struct_ Port member.

SOC accessed by subsequent application layer_ FD descriptor is can_port.

(3) Create CAN receive thread

In STM32, receive FIFO interrupts are used for processing. In linux applications, thread polling is used to read messages.

Therefore, we need to create a CAN receiving thread. The specific code is as follows:

127 /**********************************************************************
128 * Function name: void CAN_Set_Interrupt(int can_port,  pCanInterrupt callback)
129 * Function Description: create a CAN receiving thread and pass in the callback function of the application. The callback function mainly deals with the functions of the application layer
130 * Input parameter: can_port, port number
131 *          callback:  The callback function that interrupts the specific processing application function
132 * Output parameters: None
133 * Return value: None
134 * Modification date version number modified by
135 * -----------------------------------------------
136 * 2020/05/13         V1.0             bert            establish
137 ***********************************************************************/
138 void CAN_Set_Interrupt(int can_port,  pCanInterrupt callback)
139 {
140     int err;
141     
142     if ( NULL != callback ) 
143     {
144         g_pCanInterrupt = callback;
145     }
146     
147     err = pthread_create(&ntid, NULL,CAN1_RX0_IRQHandler, NULL );
148     if( err !=0 )
149     {
150         printf("create thread fail! \n");
151         return ;
152     }
153     printf("create thread success!\n");
154     
155 
156     return ;
157 }

The thread function after creation is as follows:

CAN1_RX0_IRQHandler is a can receiving thread function, which is similar to the can receiving interrupt function. Only the polling method is used here to read the can message.

253 /**********************************************************************
254 * Function name: void CAN1_RX0_IRQHandler(void)
255 * Function Description: CAN receiving thread function
256 * Input parameters: None  
257 * Output parameters: None
258 * Return value: None
259 * Modification date version number modified by
260 * -----------------------------------------------
261 * 2020/05/13         V1.0             bert            establish
262 ***********************************************************************/
263 void *CAN1_RX0_IRQHandler(void *arg)
264 {
265     /* Definition of received message */
266     while( 1 )
267     {
268     /* If the callback function exists, the callback function is executed */
269         if( g_pCanInterrupt != NULL)
270         {
271             g_pCanInterrupt();
272         }
273         usleep(10000);
274     }
275 }

(4) CAN message reading function

161 /**********************************************************************
162 * Function name: void CAN_Read(int can_port, CanRxMsg* recv_msg)
163 * Function Description: CAN reads the receiving register and takes out the received message
164 * Input parameter: can_port, port number     
165 * Output parameter: recv_msg: receive message
166 * Return value: None
167 * Modification date version number modified by
168 * -----------------------------------------------
169 * 2020/05/13         V1.0             bert            establish
170 ***********************************************************************/
171 void CAN_Read(int can_port, CanRxMsg* recv_msg)
172 { 
173     unsigned char i;
174     static unsigned int rxcounter =0;
175     
176     int nbytes;
177     struct can_frame rxframe;
178     
179     
180     nbytes = read(can_port, &rxframe, sizeof(struct can_frame));
181 	if(nbytes>0)
182 	{
183 	    printf("nbytes = %d \n",nbytes );
184 	    
185 	    recv_msg->StdId = rxframe.can_id;
186 	    recv_msg->DLC = rxframe.can_dlc;
187 	    memcpy( recv_msg->Data, &rxframe.data[0], rxframe.can_dlc);
188 	    
189 		rxcounter++;
190 		printf("rxcounter=%d, ID=%03X, DLC=%d, data=%02X %02X %02X %02X %02X %02X %02X %02X \n",  \
191 			rxcounter,
192 			rxframe.can_id, rxframe.can_dlc,  \
193 			rxframe.data[0],\
194 			rxframe.data[1],\
195 			rxframe.data[2],\
196 			rxframe.data[3],\
197 			rxframe.data[4],\
198 			rxframe.data[5],\
199 			rxframe.data[6],\
200 			rxframe.data[7] );
201 	}
202 
203     return ;
204 }
205  

(5) CAN message sending function

206 /**********************************************************************
207 * Function name: void CAN_Write(int can_port, CanTxMsg send_msg)
208 * Function Description: CAN message sending interface, call sending register to send message
209 * Input parameter: can_port, port number     
210 * Output parameter: send_msg: send message
211 * Return value: None
212 * Modification date version number modified by
213 * -----------------------------------------------
214 * 2020/05/13         V1.0             bert            establish
215 ***********************************************************************/
216 void CAN_Write(int can_port, CanTxMsg send_msg)
217 {
218     unsigned char i;
219     static unsigned int txcounter=0;
220     int nbytes;
221     
222     struct can_frame txframe;
223     
224     txframe.can_id = send_msg.StdId;
225     txframe.can_dlc = send_msg.DLC;
226     memcpy(&txframe.data[0], &send_msg.Data[0], txframe.can_dlc);
227 
228     nbytes = write(can_port, &txframe, sizeof(struct can_frame)); //Send frame[0]
229 	
230 	if(nbytes == sizeof(txframe))
231 	{
232 	    txcounter++;
233 	    printf("txcounter=%d, ID=%03X, DLC=%d, data=%02X %02X %02X %02X %02X %02X %02X %02X \n",  \
234 			txcounter,
235 			txframe.can_id, txframe.can_dlc,  \
236 			txframe.data[0],\
237 			txframe.data[1],\
238 			txframe.data[2],\
239 			txframe.data[3],\
240 			txframe.data[4],\
241 			txframe.data[5],\
242 			txframe.data[6],\
243 			txframe.data[7] );
244     }
245     else
246 	{
247 		//printf("Send Error frame[0], nbytes=%d\n!",nbytes);
248 	}
249 
250     return ;
251 }
252 

(6) CAN abstract structure framework initialization

It is similar to the definition example of STM32 in Chapter 14.3.

Define a Can1 communication structure instance CAN_COMM_STRUCT can1_controller;

Using the functions implemented in steps (1) ~ (5), initialize can1_controller to form a connection point associated with the application layer.

298 /**********************************************************************
299 * Name: can1_controller
300 * Function Description: CAN1 structure initialization
301 * Modification date version number modified by
302 * -----------------------------------------------
303 * 2020/05/13         V1.0             bert            establish
304 ***********************************************************************/
305 CAN_COMM_STRUCT can1_controller = {
306     .name                   = "can0",
307     .can_port               = CAN_PORT_CAN1,
308     .can_set_controller     = CAN_Set_Controller,
309     .can_set_interrput      = CAN_Set_Interrupt,
310     .can_read               = CAN_Read,
311     .can_write              = CAN_Write,
312 };

13.4. 3.2 writing application layer code

According to 14.4 3.1 the specific socket CAN hardware operation under linux has been realized, and the CAN programming framework has been abstractly instantiated.

But we haven't connected to the application layer yet. The application layer doesn't know which interface to call.

(1) CAN application layer registration instance

Write a general instantiation registration function in the application layer.

See "app_can.c" file int register in code "02_socketcan_send_addline" in Chapter 14_ can_ Controller (const pcan_comm_struct p_can_controller) function.

The code implementation is as follows: (it is exactly the same as STM32 application programming, and the code hardly needs to be changed)

73 /**********************************************************************
74 * Function name: int register_can_controller(const pCAN_COMM_STRUCT p_can_controller)
75 * Function Description: the application layer registers CAN1 structure
76 * Input parameter: p_can_controller, abstract structure of CAN controller
77 * Output parameters: None
78 * Return value: None
79 * Modification date version number modified by
80 * -----------------------------------------------
81 * 2020/05/13         V1.0             bert            establish
82 ***********************************************************************/
83 int register_can_controller(const pCAN_COMM_STRUCT p_can_controller)
84 {
85     /* Judge incoming p_ can_ The controller is non empty to confirm that the structure is an entity*/
86     if( p_can_controller != NULL )
87     {
88         /* The passed in parameter p_ can_ The controller is assigned to the application layer structure gCAN_COMM_STRUCT */
89         
90         /*Port number, analog socket can socket*/
91         gCAN_COMM_STRUCT.can_port              = p_can_controller->can_port; 
92         /*CAN Controller configuration function*/
93         gCAN_COMM_STRUCT.can_set_controller    = p_can_controller->can_set_controller; 
94         /*CAN Interrupt configuration*/
95         gCAN_COMM_STRUCT.can_set_interrput     = p_can_controller->can_set_interrput;
96         /*CAN Message reading function*/
97         gCAN_COMM_STRUCT.can_read              = p_can_controller->can_read;
98         /*CAN Message sending function*/
99         gCAN_COMM_STRUCT.can_write             = p_can_controller->can_write;
100         return 1;
101     }
102 	return 0;
103 }

(2) CAN application layer initialization

CAN application layer code initialization is as follows: (exactly the same as STM32 CAN application code)

105 /**********************************************************************
106 * Function name: void app_can_init(void)
107 * Function Description: CAN application layer initialization
108 * Input parameters: None
109 * Output parameters: None
110 * Return value: None
111 * Modification date version number modified by
112 * -----------------------------------------------
113 * 2020/05/13         V1.0             bert            establish
114 ***********************************************************************/
115 void app_can_init(void)
116 {
117     /** 
118     * Application layer for CAN1 structure registration
119     */
120     CAN1_contoller_add();
121     
122     /*
123     *Call can_ set_ The controller configures the CAN controller,
124     *Return to can_port, similar to the socket interface in linux socketcan, it is used as a custom CAN channel in the MCU routine 
125     */
126     gCAN_COMM_STRUCT.can_port = gCAN_COMM_STRUCT.can_set_controller();
127     /** 
128     * Call can_set_interrput configures the CAN receiving interrupt, which is similar to the receiving thread in socketcan. This example does not need to receive, so the callback function passes NULL
129     */
130     gCAN_COMM_STRUCT.can_set_interrput( gCAN_COMM_STRUCT.can_port, NULL );
131 }

(3) Design a simple periodic message sending function

We need to design a void app_ called in the 10ms periodic function first. can_ tx_ Test (void) function, which is called in the main thread function.

The function code of CAN periodic sending message is realized as follows:

134 /**********************************************************************
135 * Function name: void app_can_tx_test(void)
136 * Function Description: CAN application layer message sending function, which is used to send messages in test cycle
137 * Input parameters: None
138 * Output parameters: None
139 * Return value: None
140 * Modification date version number modified by
141 * -----------------------------------------------
142 * 2020/05/13         V1.0             bert            establish
143 ***********************************************************************/
144 void app_can_tx_test(void)
145 {
146     // Run the CAN test program based on 10ms
147     
148     unsigned char i=0;
149     
150     /* Send message definition */
151     CanTxMsg TxMessage;
152     
153     /* A byte is used as a counter in the sent message */
154     static unsigned char tx_counter = 0;
155     
156     /* Taking 10ms as the benchmark, set the period of running code after the processing function to 1 second through the timer counter*/  
157     static unsigned int timer =0;
158     if(timer++>100)
159     {
160         timer = 0;
161     }
162     else
163     {
164         return ;
165     }
166     
167     /* Send message data filling, and the message cycle is 1 second */
168     TxMessage.StdId = TX_CAN_ID;	      /* The standard identifier is 0x000~0x7FF */
169     TxMessage.ExtId = 0x0000;             /* Extension identifier 0x0000 */
170     TxMessage.IDE   = CAN_ID_STD;         /* Use standard identifier */
171     TxMessage.RTR   = CAN_RTR_DATA;       /* Set as data frame  */
172     TxMessage.DLC   = 8;                  /* Data length: the maximum data length specified in can message is 8 bytes */
173     
174     /* Fill data, which can be filled according to the actual application */
175     TxMessage.Data[0] = tx_counter++;       /* Counter used to identify message sending */
176     for(i=1; i<TxMessage.DLC; i++)
177     {
178         TxMessage.Data[i] = i;            
179     }
180     
181     /*  Call can_write send CAN message */
182     gCAN_COMM_STRUCT.can_write(gCAN_COMM_STRUCT.can_port, TxMessage);
183     
184 }
185 

Then the void app_ can_ tx_ The test (void) function is added to the main function for 10ms cycle execution. The code implementation is as follows:

188 /**********************************************************************
189 * Function name: int main(int argc, char **argv)
190 * Function Description: main function
191 * Input parameters: None
192 * Output parameters: None
193 * Return value: None
194 * Modification date version number modified by
195 * -----------------------------------------------
196 * 2020/05/13         V1.0             bert            establish
197 ***********************************************************************/
198 int main(int argc, char **argv)
199 {
200     /* CAN Application layer initialization */
201     app_can_init();
202     
203     while(1)
204     {
205         /* CAN Application layer sends message periodically */
206         app_can_tx_test();
207         
208         /* Using the delay function of linux to design the running benchmark of 10ms */
209         usleep(10000);
210     }
211 }

13.4. 3.3 case test verification

After the above code is written, the directory file is as follows:

(1) Write Makfile

The Makefile file contents are as follows:

all:
	arm-linux-gnueabihf-gcc -lpthread -o socketcan_send   can_controller.c  app_can.c
clean:
	rm socketcan_send

(2) Compile socket_send

Note: the compilation is in 100ask VMware_ ubuntu18. 04 virtual machine environment.

Enter the socket corresponding to the ubuntu virtual machine_ Send directory

Enter the make command:

After compiling through the make command, the socket is generated_ Send executable.

(3) Run socket_send

Note: run at 100ask_ Run on the imx6 development board.

nfs files are used here to run.

Give 100ask first_ Power on the imx6ull development board and open the serial port:

Enter root to log in to the linux system of the development board;

Then mount nfs as follows:

Mount -t nfs -o nolock 192.168.1.100:/home/book  /mnt

Note: at present, my development board IP: 192.168 1.101, the Ubuntu virtual machine is 192.168 1.100.

Then run/ socketcan_send

If the runtime prompts that permission is not allowed, you can use the chmod command to set the permission:

Chmod 777 socketcan_send

After running, view the print information through the serial port as follows:

Then observe the test results of the upper computer of vehile spy3 as follows:

The message sends the CAN message with message ID 0x101 periodically according to the time of 1S.

(4) Test summary

So far, we have established the application programming framework under linux through socketcan, and successfully debugged the function programming of sending messages in CAN cycle.

Later, based on this framework, we will understand CAN application programming under linux step by step;

The purpose of the relevant case sections is set as follows:

chapter

objective

14.4.3 socket_can simple sending example

Simple and direct understanding of sending messages

14.4.4 socket_can simple receiving example

Simple and direct understanding of received messages

14.4.5 socket_can receive and send instance

Combined operation of sending and receiving messages

14.4.4 socket_can simple receiving example

Simple receive instance code directory: "03_socketcan_recv"

We're on 14.4 Chapter 3 has understood the function of sending messages, and has established the framework of application programming under linux; This section focuses on the simple receive function.

Case description:

1. Realize the message receiving message 0x201.

13.4. 4.1 write the implementation function of the abstract framework

(1) Define CAN devices

Refer to the description of "(1) define CAN device" in "14.4.3.1 writing implementation function of abstract framework".

(2) Configure CAN controller

Refer to "(2) configure CAN controller" in "14.4.3.1 writing implementation function of abstract framework".

Because in "14.4.3.1", we only send and set the filter to prohibit all messages. The specific codes are as follows:

109 /*************************************************************/
110 //The filtering rule is disabled. This process does not receive messages and is only responsible for sending them
111 setsockopt(sock_fd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);  

In this case, receiving needs to be configured, and there will be corresponding differences in filter configuration. At present, we are configured to only receive messages with message ID 0x201,

The specific implementation code is as follows:

110 	//Define the receiving rule and only receive messages with the indicator equal to 0x201
111 	struct can_filter rfilter[1];
112 	rfilter[0].can_id = 0x201;
113 	rfilter[0].can_mask = CAN_SFF_MASK;
114 	//Set filtering rules
115 	setsockopt(sock_fd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));

As an extension, we can also set multiple filters:

Define filters:

struct can_filter rfilter[5];  /*Define 10 filters*/
rfilter[0].can_id = 0x201;
rfilter[0].can_mask = 0x7FF;  /*Filter rule: can_ id & mask = 0x201 & 0x7FF = 0x201*/
rfilter[1].can_id = 0x302;
rfilter[1].can_mask = 0x7FF;  /*Filter rule: can_ id & mask = 0x302& 0x7FF = 0x302*/
rfilter[2].can_id = 0x403;
rfilter[2].can_mask = 0x7FF;  /*Filter rule: can_ id & mask = 0x403& 0x7FF = 0x403*/
rfilter[3].can_id = 0x504;
rfilter[3].can_mask = 0x700;  /*Filter rule: can_ ID & mask = 0x504 & 0x700 = 0x500, that is, the message with message ID 0x5 * * is received*/
rfilter[3].can_id = 0x605;
rfilter[3].can_mask = 0x700;  /*Filter rule: can_ id & mask = 0x504 & 0x700 = 0x600*/
setsockopt(sock_fd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));

(3) Create CAN receive thread

Refer to the description of "(3) creating CAN receiving thread" in "14.4.3.1 writing implementation function of abstract framework".

(4) CAN message reading function

Refer to "(4) CAN message reading function" in "14.4.3.1 writing implementation function of abstract framework".

(5) CAN message sending function

Refer to "(5) CAN message sending function" in "14.4.3.1 writing implementation function of abstract framework".

(6) CAN abstract structure framework initialization

Refer to "(6) CAN abstract structure frame initialization" description in "14.4.3.1 writing abstract framework implementation function".

14.4. 4.2 writing application layer code

(1) CAN application layer registration instance

Refer to "(1) CAN application layer registration example" in "14.4.3.2 writing application layer code".

(2) CAN application layer initialization

In this simple receiving example, we need to set the callback pointer function in the receiving thread_ RX_ IRQHandler_ Callback is passed in. In this function, the application layer CAN read CAN messages by itself.

105 /**********************************************************************
106 * Function name: void app_can_init(void)
107 * Function Description: CAN application layer initialization
108 * Input parameters: None
109 * Output parameters: None
110 * Return value: None
111 * Modification date version number modified by
112 * -----------------------------------------------
113 * 2020/05/13         V1.0             bert            establish
114 ***********************************************************************/
115 void app_can_init(void)
116 {
117     /** 
118     * Application layer for CAN1 structure registration
119     */
120     CAN1_contoller_add();
121     
122     /*
123     *Call can_ set_ The controller configures the CAN controller,
124     *Return to can_port, similar to the socket interface in linux socketcan, it is used as a custom CAN channel in the MCU routine 
125     */
126     gCAN_COMM_STRUCT.can_port = gCAN_COMM_STRUCT.can_set_controller();
127     /** 
128     * Call can_set_interrput configures the CAN receiving interrupt, which is similar to the receiving thread in socketcan
129     */
130     gCAN_COMM_STRUCT.can_set_interrput( gCAN_COMM_STRUCT.can_port, CAN_RX_IRQHandler_Callback );
131 }

(3) Design a simple message receiving function

About void can_ RX_ IRQHandler_ The specific implementation of callback (void) is as follows:

CAN_RX_IRQHandler_Callback is executed circularly in the receiving thread, and the application layer is in can_ RX_ IRQHandler_ The callback function performs gCAN_COMM_STRUCT.can_read read can message.

133 /**********************************************************************
134 * Function name: void CAN_RX_IRQHandler_Callback(void)
135 * Function Description: CAN1 receive interrupt function; In linux, you CAN use threads or timers to read CAN data
136 * Input parameters: None
137 * Output parameters: None
138 * Return value: None
139 * Modification date version number modified by
140 * -----------------------------------------------
141 * 2020/05/13         V1.0             bert            establish
142 ***********************************************************************/
143 void CAN_RX_IRQHandler_Callback(void)
144 {
145     /* Definition of received message */
146     CanRxMsg RxMessage; 
147     
148     /* Reset received message */
149     memset( &RxMessage, 0, sizeof(CanRxMsg) );
150    
151     /* Via can_ The read interface reads the message received by the register */
152     gCAN_COMM_STRUCT.can_read(gCAN_COMM_STRUCT.can_port, &RxMessage);
153 
154     /* Copy the read can message to the global message structure g_CAN1_Rx_Message */
155     memcpy(&g_CAN1_Rx_Message, &RxMessage, sizeof( CanRxMsg ) );
156     
157 }

In this case, there is no message sending function, and there is no code processing in the main thread, so you only need to run idly.

159 /**********************************************************************
160 * Function name: int main(int argc, char **argv)
161 * Function Description: main function
162 * Input parameters: None
163 * Output parameters: None
164 * Return value: None
165 * Modification date version number modified by
166 * -----------------------------------------------
167 * 2020/05/13         V1.0             bert            establish
168 ***********************************************************************/
169 int main(int argc, char **argv)
170 {
171     /* CAN Application layer initialization */
172     app_can_init();
173     
174     while(1)
175     {        
176         /* Using the delay function of linux to design the running benchmark of 10ms */
177         usleep(10000);
178     }
179 }
180 

13.4. 4.3 case test verification

(1) Write Makfile

The Makefile file contents are as follows:

all:

   arm-linux-gnueabihf-gcc -lpthread -o socketcan_recv  can_controller.c app_can.c

clean:

   rm socketcan_recv

(2) Compile socket_recv

Note: the compilation is in 100ask VMware_ ubuntu18. 04 virtual machine environment.

Enter the socket corresponding to the ubuntu virtual machine_ In the recv directory, execute make all to compile.

The compilation process is as follows:

(3) Run socket_recv

Note: run at 100ask_ Run on the imx6 development board.

nfs files are used here to run.

For Nfs mounting, please refer to "14.4,3.3 case test verification".

At 100ask_ Under the imx6 development board environment, execute ". / socket_recv" to run the program;

Then send the data to 100ask through Vhicle Spy3_ The CAN end of imx6 development board sends a message whose message ID is not 0x201, and the message trace is as follows:

100ask_ The serial port printing information of imx6 development board is as follows:

(4) Test summary

So far, we have successfully debugged the functional programming of CAN message reception.

13.4.5 socket_can receive and send instance

Simple receive instance code directory: "04_socketcan_recv_send"

This case integrates "14.4.3 simple sending instance" and "14.4.3 simple receiving instance" to build a combined case with both sending and receiving.

Case description:

  1. Send the message with message ID: 0x101 within 1 second;
  2. Receive the message of message 0x201, copy the content to the message of message 0x301 and send it;

13.4. 5.1 write the implementation function of the abstract framework

(1) Define CAN devices

Refer to the description of "(1) define CAN device" in "13.4.3.1 writing implementation function of abstract framework".

Refer to the description of "(1) define CAN device" in "13.4.4.1 writing implementation function of abstract framework".

(2) Configure CAN controller

Refer to "(2) configure CAN controller" in "13.4.3.1 writing implementation function of abstract framework".

Refer to "(2) configure CAN controller" in "13.4.4.1 writing implementation function of abstract framework".

(3) Create CAN receive thread

Refer to the description of "(3) creating CAN receiving thread" in "13.4.3.1 writing implementation function of abstract framework".

Refer to the description of "(3) creating CAN receiving thread" in "13.4.4.1 writing implementation function of abstract framework".

(4) CAN message reading function

Refer to "(4) CAN message reading function" in "13.4.3.1 writing implementation function of abstract framework".

Refer to "(4) CAN message reading function" in "13.4.4.1 writing implementation function of abstract framework".

(5) CAN message sending function

Refer to "(5) CAN message sending function" in "13.4.3.1 writing implementation function of abstract framework".

Refer to "(5) CAN message sending function" in "13.4.4.1 writing implementation function of abstract framework".

(6) CAN abstract structure framework initialization

Refer to "(6) CAN abstract structure frame initialization" description in "13.4.3.1 writing abstract framework implementation function".

Refer to "(6) CAN abstract structure frame initialization" description in "13.4.4.1 writing abstract framework implementation function".

14.4. 5.2 writing application layer code

(1) CAN application layer registration instance

Refer to "(1) CAN application layer registration example" in "13.4.3.2 writing application layer code".

Refer to "(1) CAN application layer registration example" in "13.4.4.2 writing application layer code".

(2) CAN application layer initialization

Refer to "(2) CAN application layer initialization" in "13.4.4.2 writing application layer code".

(3) Design a simple periodic message sending function

Refer to "(3) design a simple message sending function" in "13.4.3.2 writing application layer code".

(4) Design a simple periodic message receiving function

Refer to "(3) design a simple message receiving function" in "13.4.4.2 writing application layer code".

Meanwhile, we need to copy the received message ID:0X201 to the message ID: 0x301 and send it.

On the basis of "13.4.4 simple receiving message", we add a simple logic in the callback function of the receiving thread_ RX_ IRQHandler_ In Callback, call gCAN_. COMM_ STRUCT. can_ read(gCAN_COMM_STRUCT.can_port, &RxMessage); After receiving the message with message ID:0X201, set the flag g_CAN1_Rx_Flag = 1; Then go to the main thread to determine whether this flag is set to 1. If the flag has been received, it is displayed in the void app_ can_ rx_ In test (void), copy the message content with message ID:0X201, and then assign it to the message with message ID:0x301.

Receive thread callback function_ RX_ IRQHandler_ The implementation code of callback is as follows:

231 /**********************************************************************
232 * Function name: void CAN_RX_IRQHandler_Callback(void)
233 * Function Description: CAN1 receive interrupt function; In linux, you CAN use threads or timers to read CAN data
234 * Input parameters: None
235 * Output parameters: None
236 * Return value: None
237 * Modification date version number modified by
238 * -----------------------------------------------
239 * 2020/05/13         V1.0             bert            establish
240 ***********************************************************************/
241 void CAN_RX_IRQHandler_Callback(void)
242 {
243     /* Definition of received message */
244     CanRxMsg RxMessage; 
245     
246     /* Reset received message */
247     memset( &RxMessage, 0, sizeof(CanRxMsg) );
248    
249     /* Via can_ The read interface reads the message received by the register */
250     gCAN_COMM_STRUCT.can_read(gCAN_COMM_STRUCT.can_port, &RxMessage);
251 
252     /* Copy the read can message to the global message structure g_CAN1_Rx_Message */
253     memcpy(&g_CAN1_Rx_Message, &RxMessage, sizeof( CanRxMsg ) );
254     
255     /* Set the current reception completion flag and judge that the current received message ID is RX_CAN_ID, set g_CAN1_Rx_Flag=1*/
256     if( g_CAN1_Rx_Message.StdId == RX_CAN_ID )
257     {
258         g_CAN1_Rx_Flag = 1;  
259     }
260 }

App in main thread_ can_ rx_ The receiving trigger processing function code of test is as follows:

187 /**********************************************************************
188 * Function name: void app_can_rx_test(void)
189 * Function Description: the CAN application layer receives the message processing function, which is used to process the message received in the interrupt function
190 * Input parameters: None
191 * Output parameters: None
192 * Return value: None
193 * Modification date version number modified by
194 * -----------------------------------------------
195 * 2020/05/13         V1.0             bert            establish
196 ***********************************************************************/
197 void app_can_rx_test(void)
198 {
199     unsigned char i=0;
200     
201     /* Send message definition */
202     CanTxMsg TxMessage;
203     
204     /* A byte is used as a counter in the sent message */
205     static unsigned char rx_counter = 0;
206     
207     
208     if( g_CAN1_Rx_Flag == 1)
209     {
210         g_CAN1_Rx_Flag = 0;
211         
212         /* Send message data filling, and the message cycle is 1 second */
213         TxMessage.StdId = RX_TO_TX_CAN_ID;	  /* The standard identifier is 0x000~0x7FF */
214         TxMessage.ExtId = 0x0000;             /* Extension identifier 0x0000 */
215         TxMessage.IDE   = CAN_ID_STD;         /* Use standard identifier */
216         TxMessage.RTR   = CAN_RTR_DATA;       /* Set as data frame  */
217         TxMessage.DLC   = 8;                  /* Data length: the maximum data length specified in can message is 8 bytes */
218         
219         /* Fill data, which can be filled according to the actual application */
220         TxMessage.Data[0] = rx_counter++;      /* Counter used to identify message sending */
221         for(i=1; i<TxMessage.DLC; i++)
222         {
223             TxMessage.Data[i] = g_CAN1_Rx_Message.Data[i];            
224         }
225         
226         /*  Call can_write send CAN message */
227         gCAN_COMM_STRUCT.can_write(gCAN_COMM_STRUCT.can_port, TxMessage);
228     }
229 }

13.4. 5.3 case test verification

(1) Write Makfile

The Makefile file contains the following contents:

all:

   arm-linux-gnueabihf-gcc -lpthread -o socketcan_recv_send  can_controller.c app_can.c

clean:

   rm socketcan_recv_send

(2) Compile socket_recv_send

Note: the compilation is in 100ask VMware_ ubuntu18. 04 virtual machine environment.

Enter the socket corresponding to the ubuntu virtual machine_ In the send directory, execute make all to compile.

The compilation process is as follows:

(3) Run socket_recv_send

Note: run at 100ask_ Run on the imx6 development board.

nfs files are used here to run.

For Nfs mounting, please refer to "14.4,3.3 case test verification".

At 100ask_ Under the imx6 development board environment, execute ". / socket_recv_send" to run the program;

Then send the data to 100ask through Vhicle Spy3_ The CAN end of imx6 development board sends a message whose message ID is not 0x201, and the message trace is as follows:

Then observe 100ask_imx6 development serial port printing information is as follows:

(4) Test summary

So far, we have successfully debugged the functional programming of CAN message receiving and sending.

13.5 application of CAN bus in automobile industry

13.5. CAN bus requirements of 1 Depot

The most widely used CAN bus should be in the automotive field. Almost all vehicles support CAN bus. Here is a brief introduction to some automotive related CAN bus requirements.

13.5. 1.1 network topology

The following network topology is roughly consistent with most of the actual vehicle topologies I have developed. It is generally provided by automobile manufacturers to parts suppliers.

As shown in the figure below:

Figure 13.5 1. Vehicle network topology

The general body network is divided into the following 6 local area CAN networks:

Vehicle topology grouping

describe

PT CAN (PowerTrain CAN) powertrain CAN bus

It is mainly responsible for ECU networking related to vehicle power, which is a CAN network with the highest transmission rate required by the whole vehicle; Generally, it includes the following relevant ECU units: ECM(Engine Control Module), engine control module, SRS (supplementary restraint system), electronic airbag, BMS (battery management system), EPB, electronic park brake and electronic parking system

CH CAN (Chassis CAN) chassis control CAN bus

CH CAN is responsible for braking / stabilizing / steering of vehicle chassis and four wheels. As it involves vehicle braking / power steering, its network signal priority is also high. Generally, it includes the following relevant ECU units: ABS (antilock brake system), ESP(Electronic Stability Program), EPS (electronic power steering)

Body CAN body control bus

Body CAN is responsible for the management and control of some intelligent hardware on the body to improve comfort / safety. Its network signal priority is low because the above devices are auxiliary devices. Generally, it includes the following relevant ECU units: AC (air condition) air conditioning AVM(Around View Monitor) 360, BCM(Body Control Module), sunroof, window, fog lamp, steering lamp, wiper... IMMO(Immobilizer) engine anti-theft system TPMS(Tire Pressure Monitoring System) tire pressure monitoring system

Info can entertainment system bus

Info CAN is an optional auxiliary device, so its priority is also low. It is mainly responsible for the management and control of some intelligent hardware on the body to improve entertainment. Generally, it includes the following relevant ECU units: vaes (video audio entertainment system), vehicle entertainment system (central control), IP(Instrument Pack) combination instrument, and today's digital instrument, which basically has entertainment functions such as music, map, call and so on

Diagcan diagnostic control bus

DiagCAN bus mainly provides remote diagnosis function. There is only one ECU: Tbox (telematics box) remote control module

OBD CAN

OBD generally provides an external diagnostic instrument, which is basically connected to the whole vehicle gateway ECU.

13.5.1.2 CAN message classification

In automobile CAN network, CAN message is mainly divided into three types: application message, network message and diagnosis message.

Both network message and diagnostic message are divided according to different functional requirements, and different protocols for CAN message data are formulated according to different requirements.

(1) CAN application message

CAN application message is mainly used for sending and receiving data information between different ECU nodes in body network, which is related to specific application functions;

Automobile CAN application message shall be defined and released by the vehicle factory, "signal matrix table (excel format)" and "signal matrix (DBC format)".

See "14.5.2 application analysis and examples of can application message" for details.

(2) CAN network management message

The process of configuration management and coordination of all ECU s by automotive electronic system through on-board network is called network management.

Network management CAN control each ECU on the network and issue some command rules to realize the cooperative sleep and wake-up of each ECU. The CAN message used for cooperative control is the network management message.

Network management includes OSEK network management and AUTOSAR network management. Generally, network management is required for front loading plant projects.

(3) CAN diagnostic message

CAN diagnosis mainly realizes vehicle function monitoring, fault detection, recording / storing fault information, storing / reading data, EOL offline detection, ECU upgrade and other functions.

CAN based communication layered model:

OSI layering

Depot diagnostic criteria

OBD standard

Diagnostic application

User defined

ISO15031-5

application layer

ISO15765-3 / ISO14229-1

ISO15031-5

Presentation layer

nothing

nothing

Session layer

ISO15765-3

ISO15765-4

Transport layer

nothing

nothing

network layer

ISO15765-2

ISO15765-4

data link layer

ISO11898-1

ISO15765-4

physical layer

User defined

ISO15765-4

Figure CAN diagnostic service OSI model

13.5. 2 Application Analysis and example of can application message

13.5.2.1 CAN application message definition

After a depot project is started, the depot will provide CAN signal matrix (excel) and DBC signal matrix database according to the needs of the project.

(1) CAN signal matrix excel format

For the file format of signal matrix (excel) provided by the depot, see Chapter 14 code directory: CAN_Signal_Matrix.xlsx,

From can_ Signal_ Matrix. The definition of intercepted message in xlsx is as follows:

ECU_TX_MSG1: (send message periodically, ID: 0x123)

ECU_TX_MSG2: (event sending message, ID: 0x124)

ECU_TX_MSG3: (cycle & event sending message, ID: 0x125)

ECU_RX_MSG1: (event receiving message, ID: 0X201)

It can be seen from the above message definition that the depot will define many attributes of the message, such as message name, message ID, message length, message cycle, message transmission type, signal name, signal start byte, signal length, arrangement format (Intel or Motorola), value range of the signal, signal transmission mode, etc.

(2) CAN signal matrix DBC

The DBC file corresponding to the example CAN matrix "CAN_Signal_Matrix.xlsx" provided in this chapter, which is edited by vector CANdb+ Editor; As shown in the figure below, the message information content displayed in DBC file is consistent with that displayed in excel table. The file format is not the most critical, as long as you understand the requirements of the depot for CAN signal.

Figure DBC of CAN signal matrix

13.5.2.2 CAN application message sending rules

We mentioned that the depot will provide can signal matrix table and define periodic message, event message and periodic event mixed message. Where are the general rules for defining these signals? Generally, the depot will provide the communication specification of CAN bus, and the depot will define the can signal matrix according to the communication specification.

The following is the communication specification XXX Communication Requirement Specification.pdf of a vehicle factory. Its specification directory is shown in the figure below. It CAN be seen from the directory that it mainly introduces the relevant rules of CAN physical layer, data link layer, communication interaction layer and so on.

In this section, we mainly introduce the content related to "4 Interaction Layer" of communication interaction layer related to application message: CAN Message Send Type.

The sending types of CAN messages are introduced one by one as shown in the previous matrix table as follows:

(1) Periodic message

Periodic message is sent periodically and regularly, and the period is T.

As shown in the figure below:

When the system runs, ECU sends CAN message regularly according to cycle T.

(2) Event Message

Send an event type message when an event is triggered, as shown in the following figure:

When the system is running, ECU does not actively send Event type message, but when ECU is triggered by a certain condition (Event), ECU will send three frames of Event message continuously.

Of course, the requirements of the car factory are not only that, but also more other requirements,

For example,

Requirement 1: after triggering the sending of three frame message, the signal is required to be restored to the default value;

Requirement 2: trigger to send three frames, and the interval between frames shall be 50ms;

(3) Periodic and event message

Periodic event hybrid message (CE for short), when there is no event trigger, the message is sent regularly according to cycle T. when there is event trigger, the message is sent according to event trigger mode.

As shown in the figure below:

The CAN message sending types defined by the actual depot are not only the above three, but these three are the most important sending methods.

14.5. 2.3 Application examples of automobile CAN application message sending

Through the description in the previous section, we have learned about the three application message sending types in the depot specification. Now we start at 100ask_ Test on imx6 development board to meet the requirements of application message of depot.

We have explained the application programming framework of linux socketcan in detail in "14.4 basic application programming of linux socketcan". Now we will carry out the case application programming of this chapter based on "14.4.5 receiving and sending examples of socketcan", focusing on app_can.c programming, can_controller.c can be completely used.

For the following application programming, we use 14.5 CAN message in CAN message matrix introduced in 2.1.

(1) Preparation of linux can programming framework

Use the code "04_socketcan_recv_send" in the case, and rename the copied folder "06_socketcan_ecu_application".

In app_ can. Message ID defined in C file:

30 /**************Macro definition**************************************************/
31 /* CAN message ID sent in test cycle in this routine */
32 #define TX_CAN_CYCLIC_ID    0X123
33 #define TX_CAN_EVENT_ID     0X124
34 #define TX_CAN_CE_ID        0X125
35 
36 /* Test the received CAN message ID in this routine */
37 #define RX_CAN_ID           0x201   

(2) Implementation of periodic message

Implementation functions:

A. Program to realize periodic sending message ID:0x123, and cycle T is 1000ms.

The code implementation is as follows:

136 /**********************************************************************
137 * Function name: void app_can_cyclicmsg_test(void)
138 * Function Description: CAN application layer test sends periodic message (ID:0X123)
139 * Input parameters: None
140 * Output parameters: None
141 * Return value: None
142 * Modification date version number modified by
143 * -----------------------------------------------
144 * 2020/05/13         V1.0             bert            establish
145 ***********************************************************************/
146 void app_can_cyclicmsg_test(void)
147 {
148     // Run the CAN test program based on 10ms
149     
150     unsigned char i=0;
151     
152     /* Send message definition */
153     CanTxMsg TxMessage;
154     
155     /* A byte is used as a counter in the sent message */
156     static unsigned char tx_counter = 0;
157     
158     /* Taking 10ms as the benchmark, set the period of running code after the processing function to 1 second through the timer counter*/  
159     static unsigned int timer =0;
160     if(timer++>100)
161     {
162         timer = 0;
163     }
164     else
165     {
166         return ;
167     }
168     
169     /* Send message data filling, and the message cycle is 1 second */
170     TxMessage.StdId = TX_CAN_CYCLIC_ID;	  /* The standard identifier is 0x000~0x7FF */
171     TxMessage.ExtId = 0x0000;             /* Extension identifier 0x0000 */
172     TxMessage.IDE   = CAN_ID_STD;         /* Use standard identifier */
173     TxMessage.RTR   = CAN_RTR_DATA;       /* Set as data frame  */
174     TxMessage.DLC   = 8;                  /* Data length: the maximum data length specified in can message is 8 bytes */
175     
176     /* Fill data, which can be filled according to the actual application */
177     TxMessage.Data[0] = tx_counter++;       /* Counter used to identify message sending */
178     for(i=1; i<TxMessage.DLC; i++)
179     {
180         TxMessage.Data[i] = i;            
181     }
182     
183     /*  Call can_write send CAN message */
184     gCAN_COMM_STRUCT.can_write(gCAN_COMM_STRUCT.can_port, TxMessage);
185     
186 }

(3) Implementation of event message

Implementation functions:

A. When the signal ECU_RX_MSG1_signal1=1 of a frame message (ID: 0x201) is received by programming, the event message (ID:0x124) is triggered to send, so that ECU_MSG2_signal2 (Byte1 byte) = 2 and the time interval between two frames of messages is 50ms.

B. Event triggering condition: message (ID:0x201) is received and ECU_RX_MSG1_signal1 (Byte0 byte bit0) is 1

The code implementation is as follows:

188 /**********************************************************************
189 * Function name: void app_can_eventmsg_test(void)
190 * Function Description: CAN application layer test sends event message (ID:0X124)
191 * Input parameters: None
192 * Output parameters: None
193 * Return value: None
194 * Modification date version number modified by
195 * -----------------------------------------------
196 * 2020/05/13         V1.0             bert            establish
197 ***********************************************************************/
198 void app_can_eventmsg_test(void)
199 {
200     unsigned char i=0;
201 
202     /* A byte is used as the event trigger counter in the sent message */
203     static unsigned char tx_counter = 0;
204 
205     /* Send message definition */
206     CanTxMsg TxMessage;
207 
208     if( g_CAN1_Rx_Event_Flag == 1 )
209     {
210 	g_CAN1_Rx_Event_Flag = 0;
211 	printf("Message:0x124 is Triggered!\n");
212 
213         /* Send message data filling, and the message cycle is 1 second */
214         TxMessage.StdId = TX_CAN_EVENT_ID;	  /* The standard identifier is 0x000~0x7FF */
215         TxMessage.ExtId = 0x0000;             /* Extension identifier 0x0000 */
216         TxMessage.IDE   = CAN_ID_STD;         /* Use standard identifier */
217         TxMessage.RTR   = CAN_RTR_DATA;       /* Set as data frame  */
218         TxMessage.DLC   = 8;                  /* Data length: the maximum data length specified in can message is 8 bytes */
219         
220         /* Fill data, which can be filled according to the actual application */
221         for(i=0; i<TxMessage.DLC; i++)
222         {
223             TxMessage.Data[i] = 0x00;            
224         }
225         /* Fill data, which can be filled according to the actual application */
226 	tx_counter = 0;
227 	
228 	/*Update frame 1 data*/
229 	TxMessage.Data[1] = 0x02;
230 	TxMessage.Data[7] = (++tx_counter);
231         /*  Call can_write send CAN message, frame 1 */
232         gCAN_COMM_STRUCT.can_write(gCAN_COMM_STRUCT.can_port, TxMessage);
233 	/*Delay 50ms as event message interval*/
234 	usleep(50000);
235 
236 	/*Update frame 2 data*/
237 	TxMessage.Data[1] = 0x02;
238 	TxMessage.Data[7] = (++tx_counter);
239 	/*  Call can_write send CAN message, frame 2 */
240         gCAN_COMM_STRUCT.can_write(gCAN_COMM_STRUCT.can_port, TxMessage);
241 	/*Delay 50ms as event message interval*/
242 	usleep(50000);
243 
244 	/*Update frame 3 data*/
245 	TxMessage.Data[1] = 0x02;
246 	TxMessage.Data[7] = (++tx_counter);
247 	/*  Call can_write send CAN message, frame 3 */
248         gCAN_COMM_STRUCT.can_write(gCAN_COMM_STRUCT.can_port, TxMessage);
249 	/*Delay 50ms as event message interval*/
250 	usleep(50000);
251     }
252 }

(4) Implementation of periodic event message

Implementation functions:

A. Program to realize periodic sending message (ID: 0x125);

B. When the signal ECU_RX_MSG1_signal2=1 of one frame message (ID: 0x201) is received, it triggers the sending of periodic event message (ID:0x125), so that ECU_MSG3_signal9 (Byte1 byte bit0) = 1, and three frames are sent continuously, and the time interval between two frames is 50ms. After three frames are sent, it is restored to ECU_MSG3_signal5=0;

A. Event triggering condition: message (ID:0x201) is received and ECU_RX_MSG1_signal2 (Byte0 byte bit1) is 1

The code implementation is as follows:

255 /**********************************************************************
256 * Function name: void app_can_cycliceventmsg_test(void)
257 * Function Description: CAN application layer test sends periodic event mixed message (ID:0X125)
258 * Input parameters: None
259 * Output parameters: None
260 * Return value: None
261 * Modification date version number modified by
262 * -----------------------------------------------
263 * 2020/05/13         V1.0             bert            establish
264 ***********************************************************************/
265 void app_can_cycliceventmsg_test(void)
266 {
267     unsigned char i=0;
268     
269     /* Send message definition */
270     CanTxMsg TxMessage;
271     
272     /* A byte is used as the event trigger counter in the sent message */
273     static unsigned char tx_counter = 0;
274 
275     /* Taking 10ms as the benchmark, set the period of running code after the processing function to 1 second through the timer counter*/  
276     static unsigned int timer =0;
277 
278     if( g_CAN1_Rx_CE_Flag == 1)
279     {
280 	g_CAN1_Rx_CE_Flag = 0;
281 	printf("Message:0x125 is Triggered!\n");
282 
283 	/* Send message data filling, and the message cycle is 1 second */
284         TxMessage.StdId = TX_CAN_CE_ID;	     /* The standard identifier is 0x000~0x7FF */
285         TxMessage.ExtId = 0x0000;             /* Extension identifier 0x0000 */
286         TxMessage.IDE   = CAN_ID_STD;         /* Use standard identifier */
287         TxMessage.RTR   = CAN_RTR_DATA;       /* Set as data frame  */
288         TxMessage.DLC   = 8;                  /* Data length: the maximum data length specified in can message is 8 bytes */
289         
290         /* Clear data area */
291         for(i=0; i<TxMessage.DLC; i++)
292         {
293             TxMessage.Data[i] = 0x00;            
294         }
295 	/* Fill data, which can be filled according to the actual application */
296 	tx_counter = 0;
297 
298         /*Update frame 1 data*/
299 	TxMessage.Data[1] = 0x01;
300 	TxMessage.Data[7] = (++tx_counter);
301         /*  Call can_write send CAN message, frame 1 */
302         gCAN_COMM_STRUCT.can_write(gCAN_COMM_STRUCT.can_port, TxMessage);
303 	/*Delay 50ms as event message interval*/
304 	usleep(50000);
305 
306 	/*Update frame 2 data*/
307 	TxMessage.Data[1] = 0x01;
308 	TxMessage.Data[7] = (++tx_counter);
309 	/*  Call can_write send CAN message, frame 2 */
310         gCAN_COMM_STRUCT.can_write(gCAN_COMM_STRUCT.can_port, TxMessage);
311 	/*Delay 50ms as event message interval*/
312 	usleep(50000);
313 
314 	/*Update frame 3 data*/
315 	TxMessage.Data[1] = 0x01;
316 	TxMessage.Data[7] = (++tx_counter);
317 	/*  Call can_write send CAN message, frame 3 */
318         gCAN_COMM_STRUCT.can_write(gCAN_COMM_STRUCT.can_port, TxMessage);
319 	/*Delay 50ms as event message interval*/
320 	usleep(50000);
321     }
322 
323     /* Taking 10ms as the benchmark, set the period of running code after the processing function to 1 second through the timer counter*/  
324     if(timer++>100)
325     {
326         timer = 0;
327     }
328     else
329     {
330         return ;
331     }
332 
333     /* Send message data filling, and the message cycle is 1 second */
334     TxMessage.StdId = TX_CAN_CE_ID;	  /* The standard identifier is 0x000~0x7FF */
335     TxMessage.ExtId = 0x0000;             /* Extension identifier 0x0000 */
336     TxMessage.IDE   = CAN_ID_STD;         /* Use standard identifier */
337     TxMessage.RTR   = CAN_RTR_DATA;       /* Set as data frame  */
338     TxMessage.DLC   = 8;                  /* Data length: the maximum data length specified in can message is 8 bytes */
339         
340     /* Fill data, which can be filled according to the actual application */
341     for(i=1; i<TxMessage.DLC; i++)
342     {
343 	TxMessage.Data[i] = 0x00;            
344     }
345      
346     /*  Call can_write send CAN message */
347     gCAN_COMM_STRUCT.can_write(gCAN_COMM_STRUCT.can_port, TxMessage);
348 }

(4) Case test

Step 1: test cycle message

Run socket_ecu_test, the serial port print information is as follows:

Then observe the message trace obtained by Vehicle Spy3 software, as shown below:

Message ID:0x123,0x125 both messages are sent in 1000ms cycle;

Step 2: test event message

On the Vehicle Spy3 software, the message ID:0X201,0X124 is filtered out in Messages

Then manually click the message with ID:0X201 on the Tx Panel on the right, and the record of Messages on the left is 100ask_imx6 development board sends 3 Messages with frame ID:0x124.

It can be seen from the serial port printing information of the development board: "Message:0x124 is Triggered!", After this print message, there are three frames of messages with ID:0x124.

Observe the trace of Messages on the left, as shown in the following figure:

Step 3: Test periodic event message

On the Vehicle Spy3 software, the message ID:0X201,0X125 is filtered out in Messages

Then manually click the message with ID:0X201 on the Tx Panel on the right, and the record of Messages on the left is 100ask_imx6 development board sends three Messages with frame ID:0x125, but the message data is different from the default data. The data content Byte7 is 0x01, 0x02 and 0x03 in turn.

It can be seen from the serial port printing information of the development board: "Message:0x125 is Triggered!", After this print message, there are three frames of messages with ID:0x124.

Observe the trace of Messages on the left, as shown in the following figure:

ID:0X125 normally sends the default message in a cycle of 1000ms. When the message of ID:201 triggers an event, it causes ID:0X125 to send an event message.

(5) Improvement of event message sending

Through the previous steps, we have learned about the sending types of application messages and the ways to realize different sending types, but there is a defect in the above event processing, that is, when the event is triggered, the message interval is realized through the ucsleep() function during sending. This delay will make the cycle of periodic messages longer, which CAN be found by observing the CAN message trace.

Here, a small improvement is made to the case "06_socketcan_ecu_application". The trigger event is processed by cycle counting. For details, please see the case code "07_socketcan_ecu_application_new".