LIN-BUS Implementation on Frame, Transportation and Node-Configuration Level
- Send and request data by compiling a LIN Frame and transmitting via Serial-Interface (as a Bus Master)
- Transportation Layer using Packet Data Unit (PDU)
- Node Configuration using Service Identifier (SID) and handling negative resposne codes
The HardwareSerial UART of an ESP32 is used. (But in the past I used a software serial and therefore I derived this class in a prior version from the class SoftwareSerial.)
I've used a TJA1020 Transceiver on HW side in my project. The chip contains a statemachine, which needs to be controlled before you will be able to write or receive data. To keep things easy, I created a derived class (from this one) which consider the statemachine every time using the bus: https://github.com/mestrode/Lin-Transceiver-Library
Remark: Current Example uses v.0.0.2. The interface was modified in in Version 1.0.0.
Need a basic example: Take a look into the example folder.
More complex example: Take a look into this repo to see, how this works: https://github.com/mestrode/IBS-Sensor-Library
This code calls some methods of BatSensor which utilizes the Lin-Interface
// LIN Bus Interface provided viy TJA1020 #include "TJA1020.hpp" // IBS Batterie Sensor #include "IBS_Sensor.hpp" #define LIN_SERIAL_SPEED LIN_BAUDRATE_IBS_SENSOR /* Required by IBS Sensor */ #define lin_NSLP_Pin 32 // utilize the TJA1020 by using UART2 for writing and reading frames // but keep in mind: the Lin_TJA1020 is only an extension of this library. Lin_TJA1020 LinBus(2, LIN_SERIAL_SPEED, lin_NSLP_Pin); // UART_nr, Baudrate, /SLP // Hella IBS 200x "Sensor 2" IBS_Sensor BatSensor(2); void setup() { // tell the BatSensor object which LinBus to be used BatSensor.LinBus = &LinBus; } void showSensorData() { // read data from sensor (method request data by using several // Lin-Frames) BatSensor.readFrames(); // may you using a Bus-Transceiver like the TJA1020 which should // go to sleep after transmission (depends on your HW) LinBus.setMode(LinBus.Sleep); // use received data Serial.printf("Calibration done: %d &\n", BatSensor.CalibrationDone); Serial.printf("Voltage: %.3f Volt\n", BatSensor.Ubat); Serial.printf("Current: %.3f Ampere\n", BatSensor.Ibat); Serial.printf("State of Charge: %.1f %\n", BatSensor.SOC); Serial.printf("State of Health: %.1f &\n", BatSensor.SOH); Serial.printf("Available Capacity: %.1f &\n", BatSensor.Cap_Available); }
The LinBus is provided to the BatSensor and is used internally.
The actual data handling looks like this:
bool IBS_Sensor::readFrameCapacity() { bool chkSumValid = LinBus->readFrame(IBS_FrameID[_SensorNo][IBS_FRM_CAP]); if (chkSumValid) { // decode some bytes (incl. rescaling) Cap_Max = (float((LinBus->LinMessage[1] << 8) + LinBus->LinMessage[0])) / 10; Cap_Available = (float((LinBus->LinMessage[3] << 8) + LinBus->LinMessage[2])) / 10; // receive a single byte Cap_Configured = LinBus->LinMessage[4]; // decode flags within a byte CalibByte = LinBus->LinMessage[5]; CalibrationDone = bitRead(LinBus->LinMessage[5], 0); } return chkSumValid; }
See description of Frame 0x3C and 0x3D in the doc folder of this project.
Don't know if this is valid in general, but at least in the Project IBS-Sensor-Library it worked.
Remember that we use gnu++17 in the compiler flags
LIN Specification 2.2A provides by lin-cia.org https://www.lin-cia.org/fileadmin/microsites/lin-cia.org/resources/documents/LIN_2.2A.pdf
IBS-Sensor-Library https://github.com/mestrode/IBS-Sensor-Library
LIN-Transceiver-Library (TJA1020) https://github.com/mestrode/Lin-Transceiver-Library