open-LIN/open-LIN-c implementation in ESP32.
This project implements hardware abstraction APIs of open-LIN-c
in ESP32 based on CW-B-W/ESP32-SoftwareLIN .
Besides of the implementation, there are simple examples to illustrate how to use open-LIN-c
.
Send / Receive LIN bus frames on both LIN master and LIN slave
Autobaud detection is supported by LIN slave
Use VS Code with extension PlatformIO to open the project folder
Build and upload the ESP32 firmware with PlatformIO
If this device is acting as a LIN master, copy the examples/master.cpp
to src/
If this device is acting as a LIN slave, copy the examples/slave.cpp
to src/
Connect the UART pins of the ESP32 LIN master and ESP32 LIN slave
In examples/master.cpp
, master_frame_table
is used to store the periodic frames information. open-LIN-c
keeps iterating through the table and send each frame itme.
Refer to
t_master_frame_table_item master_frame_table[] = {
{10 , 0 , {0x02 , OPEN_LIN_FRAME_TYPE_TRANSMIT, frame_data_length[0 ], master_data_buffer[0 ]}},
{10 , 0 , {0x03 , OPEN_LIN_FRAME_TYPE_RECEIVE, frame_data_length[1 ], master_data_buffer[1 ]}}
};
In examples/master.cpp
, frame_slot
is used to store the periodic frames information.
When a framed is received, open-LIN-c
searches the received frame PID in the frame_slot
and return the frame information if found.
Refer to
open_lin_frame_slot_t frame_slot[] = {
{0x02 , OPEN_LIN_FRAME_TYPE_RECEIVE, frame_data_length[0 ], slave_data_buffer[0 ]},
{0x03 , OPEN_LIN_FRAME_TYPE_TRANSMIT, frame_data_length[1 ], slave_data_buffer[1 ]}
};
Master on received frame handler
In examples/master.cpp
, function open_lin_master_dl_rx_callback
is used to handle the frames received. Refer to
void open_lin_master_dl_rx_callback (open_lin_frame_slot_t * slot)
{
Serial.printf (" [open_lin_master_dl_rx_callback] PID=%d\n\t " , (int )slot->pid );
for (int i = 0 ; i < slot->data_length ; ++i) {
Serial.printf (" 0x%02X " , slot->data_ptr [i]);
}
Serial.printf (" \n\n " );
}
In examples/master.cpp
, function open_lin_error_handler
is used to handle the errors. Refer to
void open_lin_error_handler (t_open_lin_error error_code)
{
Serial.printf (" [open_lin_error_handler] error_code = %d\n " , (int )error_code);
switch (error_code) {
case OPEN_LIN_NO_ERROR:
Serial.printf (" \t %s\n " , " OPEN_LIN_NO_ERROR" );
break ;
case OPEN_LIN_SLAVE_ERROR_INVALID_DATA_RX:
Serial.printf (" \t %s\n " , " OPEN_LIN_SLAVE_ERROR_INVALID_DATA_RX" );
break ;
case OPEN_LIN_SLAVE_ERROR_INVALID_CHECKSUM:
Serial.printf (" \t %s\n " , " OPEN_LIN_SLAVE_ERROR_INVALID_CHECKSUM" );
break ;
case OPEN_LIN_SLAVE_ERROR_PID_PARITY:
Serial.printf (" \t %s\n " , " OPEN_LIN_SLAVE_ERROR_PID_PARITY" );
break ;
case OPEN_LIN_SLAVE_ERROR_INVALID_SYNCH:
Serial.printf (" \t %s\n " , " OPEN_LIN_SLAVE_ERROR_INVALID_SYNCH" );
break ;
case OPEN_LIN_SLAVE_ERROR_INVALID_BREAK:
Serial.printf (" \t %s\n " , " OPEN_LIN_SLAVE_ERROR_INVALID_BREAK" );
break ;
case OPEN_LIN_SLAVE_ERROR_ID_NOT_FOUND:
Serial.printf (" \t %s\n " , " OPEN_LIN_SLAVE_ERROR_ID_NOT_FOUND" );
break ;
case OPEN_LIN_SLAVE_ERROR_HW_TX:
Serial.printf (" \t %s\n " , " OPEN_LIN_SLAVE_ERROR_HW_TX" );
break ;
case OPEN_LIN_MASTER_ERROR_CHECKSUM:
Serial.printf (" \t %s\n " , " OPEN_LIN_MASTER_ERROR_CHECKSUM" );
break ;
case OPEN_LIN_MASTER_ERROR_HEADER_TX:
Serial.printf (" \t %s\n " , " OPEN_LIN_MASTER_ERROR_HEADER_TX" );
break ;
case OPEN_LIN_MASTER_ERROR_DATA_TX:
Serial.printf (" \t %s\n " , " OPEN_LIN_MASTER_ERROR_DATA_TX" );
break ;
case OPEN_LIN_MASTER_ERROR_DATA_RX:
Serial.printf (" \t %s\n " , " OPEN_LIN_MASTER_ERROR_DATA_RX" );
break ;
case OPEN_LIN_MASTER_ERROR_DATA_RX_TIMEOUT:
Serial.printf (" \t %s\n " , " OPEN_LIN_MASTER_ERROR_DATA_RX_TIMEOUT" );
break ;
default :
assert (0 );
}
}
Slave on received frame handler
In examples/slave.cpp
, function open_lin_on_rx_frame
is used to handle the frames received. Refer to
void open_lin_on_rx_frame (open_lin_frame_slot_t *slot)
{
Serial.printf (" [open_lin_on_rx_frame] PID=%d\n\t " , (int )slot->pid );
for (int i = 0 ; i < slot->data_length ; ++i) {
Serial.printf (" 0x%02X " , slot->data_ptr [i]);
}
Serial.printf (" \n\n " );
}
In examples/slave.cpp
, function open_lin_error_handler
is used to handle the errors. Refer to
void open_lin_error_handler (t_open_lin_error error_code)
{
Serial.printf (" [open_lin_error_handler] error_code = %d\n " , (int )error_code);
switch (error_code) {
case OPEN_LIN_NO_ERROR:
Serial.printf (" \t %s\n " , " OPEN_LIN_NO_ERROR" );
break ;
case OPEN_LIN_SLAVE_ERROR_INVALID_DATA_RX:
Serial.printf (" \t %s\n " , " OPEN_LIN_SLAVE_ERROR_INVALID_DATA_RX" );
break ;
case OPEN_LIN_SLAVE_ERROR_INVALID_CHECKSUM:
Serial.printf (" \t %s\n " , " OPEN_LIN_SLAVE_ERROR_INVALID_CHECKSUM" );
break ;
case OPEN_LIN_SLAVE_ERROR_PID_PARITY:
Serial.printf (" \t %s\n " , " OPEN_LIN_SLAVE_ERROR_PID_PARITY" );
break ;
case OPEN_LIN_SLAVE_ERROR_INVALID_SYNCH:
Serial.printf (" \t %s\n " , " OPEN_LIN_SLAVE_ERROR_INVALID_SYNCH" );
break ;
case OPEN_LIN_SLAVE_ERROR_INVALID_BREAK:
Serial.printf (" \t %s\n " , " OPEN_LIN_SLAVE_ERROR_INVALID_BREAK" );
break ;
case OPEN_LIN_SLAVE_ERROR_ID_NOT_FOUND:
Serial.printf (" \t %s\n " , " OPEN_LIN_SLAVE_ERROR_ID_NOT_FOUND" );
break ;
case OPEN_LIN_SLAVE_ERROR_HW_TX:
Serial.printf (" \t %s\n " , " OPEN_LIN_SLAVE_ERROR_HW_TX" );
break ;
case OPEN_LIN_MASTER_ERROR_CHECKSUM:
Serial.printf (" \t %s\n " , " OPEN_LIN_MASTER_ERROR_CHECKSUM" );
break ;
case OPEN_LIN_MASTER_ERROR_HEADER_TX:
Serial.printf (" \t %s\n " , " OPEN_LIN_MASTER_ERROR_HEADER_TX" );
break ;
case OPEN_LIN_MASTER_ERROR_DATA_TX:
Serial.printf (" \t %s\n " , " OPEN_LIN_MASTER_ERROR_DATA_TX" );
break ;
case OPEN_LIN_MASTER_ERROR_DATA_RX:
Serial.printf (" \t %s\n " , " OPEN_LIN_MASTER_ERROR_DATA_RX" );
break ;
case OPEN_LIN_MASTER_ERROR_DATA_RX_TIMEOUT:
Serial.printf (" \t %s\n " , " OPEN_LIN_MASTER_ERROR_DATA_RX_TIMEOUT" );
break ;
default :
assert (0 );
}
Serial.println (" \n " );
}
Enable/Disable autobaud for LIN slave
In examples/slave.cpp
, if LIN_AUTOBAUD
is defined, autobaud is enabled, otherwise autobaud is disabled. Refer to
Testing - Microchip LIN Serial Analyzer
This project was tested with Microchip LIN Serial Analyzer and NXP TJA1021 module.
(Sleep was not used in this test)
ESP32 as Master, LIN Analyzer as Slave
Use examples/master.cpp
to do this test.
Open LIN Serial Analyzer Debug Tool
Hold ESP32 reset button (Don't release now)
Connect Debug Tool with LIN Serial Analyzer
Choose to use Enhanced Checksum Type in Debug Tool
Setup Slave Response in Debug Tool
Select the responses and click Add Slave Response Buffer
Release ESP32 reset button
LIN frames should be detected and shown on the screen
Compared with the result in logic analyzer
ESP32 as Slave, LIN Analyzer as Master
Use examples/slave.cpp
to do this test.
Open LIN Serial Analyzer Debug Tool
Connect Debug Tool with LIN Serial Analyzer
Choose to use Enhanced Checksum Type in Debug Tool
Setup Master frames in Debug Tool
Select the two frames and click Send Continuous
LIN frames should be detected and shown on the screen
Compared with the result in logic analyzer
This project was also tested with VN1611.
We can take advantages of Vector XL Driver Library to test it with VN1611.