├── library.properties ├── keywords.txt ├── examples ├── APGRD004_RGB_LED │ └── APGRD004_RGB_LED.ino ├── APGRD004_TYPICAL_COMMAND_FRAMES │ └── APGRD004_TYPICAL_COMMAND_FRAMES.ino ├── NCV7430_RGB_demo │ └── NCV7430_RGB_demo.ino └── NCV7430_Get_Full_Status │ └── NCV7430_Get_Full_Status.ino ├── src ├── lin_bus.h └── lin_bus.cpp └── README.md /library.properties: -------------------------------------------------------------------------------- 1 | name=Teensy_3.x_LIN_Master 2 | version=0.0.1 3 | author=MarkusLange 4 | maintainer=Markus 5 | sentence=LIN Master 6 | paragraph= 7 | category=Communication 8 | url= 9 | architectures=* -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For OneWire 3 | ####################################### 4 | 5 | ####################################### 6 | # DataTypes (KEYWORD1) 7 | ####################################### 8 | 9 | LIN KEYWORD1 10 | lin KEYWORD1 11 | 12 | ####################################### 13 | # Methods and Functions (KEYWORD2) 14 | ####################################### 15 | 16 | send_break KEYWORD2 17 | order KEYWORD2 18 | response KEYWORD2 19 | addrParity KEYWORD2 20 | dataChecksum KEYWORD2 21 | write KEYWORD2 22 | read KEYWORD2 23 | 24 | ####################################### 25 | # Instances (KEYWORD2) 26 | ####################################### 27 | 28 | 29 | 30 | ####################################### 31 | # Constants (LITERAL1) 32 | ####################################### 33 | 34 | lin1x LITERAL1 35 | lin2x LITERAL1 -------------------------------------------------------------------------------- /examples/APGRD004_RGB_LED/APGRD004_RGB_LED.ino: -------------------------------------------------------------------------------- 1 | #include "lin_bus.h" 2 | 3 | // Create an IntervalTimer object 4 | IntervalTimer myTimer; 5 | 6 | int ledState = LOW; // ledState used to set the LED 7 | unsigned long interval = 200000; // interval at which to blinkLED to run every 0.2 seconds 8 | 9 | #define Ambient_Light_ID 0x23 10 | 11 | LIN lin(&Serial1, 19200); 12 | 13 | int lin_cs = 23; 14 | 15 | // Intense G R B Zone 16 | uint8_t lin_data_r[] = {0x1F, 0x80, 0x00, 0x00, 0x0f}; 17 | uint8_t lin_data_g[] = {0x1F, 0x00, 0x80, 0x00, 0x0f}; 18 | uint8_t lin_data_b[] = {0x1F, 0x00, 0x00, 0x80, 0x0f}; 19 | 20 | void setup() { 21 | pinMode(LED_BUILTIN, OUTPUT); 22 | pinMode(lin_cs, OUTPUT); 23 | digitalWrite(lin_cs, HIGH); 24 | 25 | Serial.begin(11520); 26 | Serial.print("APGRD004 RGB demo"); 27 | 28 | myTimer.begin(blinkLED, interval); 29 | } 30 | 31 | void loop() { 32 | // Red 33 | Serial.println("red"); 34 | lin.order(Ambient_Light_ID, lin_data_r, 5); 35 | delay(1000); 36 | 37 | // Green 38 | Serial.println("green"); 39 | lin.order(Ambient_Light_ID, lin_data_g, 5); 40 | delay(1000); 41 | 42 | // Blue 43 | Serial.println("blue"); 44 | lin.order(Ambient_Light_ID, lin_data_b, 5); 45 | delay(1000); 46 | } 47 | 48 | void blinkLED() { 49 | ledState = !ledState; 50 | 51 | digitalWrite(LED_BUILTIN, ledState); 52 | } -------------------------------------------------------------------------------- /examples/APGRD004_TYPICAL_COMMAND_FRAMES/APGRD004_TYPICAL_COMMAND_FRAMES.ino: -------------------------------------------------------------------------------- 1 | #include "lin_bus.h" 2 | 3 | // Create an IntervalTimer object 4 | IntervalTimer myTimer; 5 | 6 | int ledState = LOW; // ledState used to set the LED 7 | unsigned long interval = 200000; // interval at which to blinkLED to run every 0.2 seconds 8 | 9 | LIN lin(&Serial1, 19200); 10 | 11 | int lin_cs = 23; 12 | 13 | void setup() { 14 | pinMode(LED_BUILTIN, OUTPUT); 15 | pinMode(lin_cs, OUTPUT); 16 | digitalWrite(lin_cs, HIGH); 17 | 18 | Serial.begin(11520); 19 | Serial.print("APGRD004 Frame demo"); 20 | 21 | myTimer.begin(blinkLED, interval); 22 | } 23 | 24 | void loop() { 25 | // White 26 | uint8_t lin_data_w[] = {0x1F, 0x80, 0x80, 0x80, 0x01}; 27 | lin.order(0x23, lin_data_w, 5); 28 | delay(1000); 29 | 30 | // Red 31 | uint8_t lin_data_r[] = {0x10, 0xFF, 0x00, 0x00, 0x02}; 32 | lin.order(0x23, lin_data_r, 5); 33 | delay(1000); 34 | 35 | // Green Ramp from 0 to 50 36 | uint8_t lin_data_g[] = {0x50, 0x00, 0xFF, 0x00, 0x04}; 37 | lin.order(0x23, lin_data_g, 5); 38 | delay(1000); 39 | 40 | // Blue Ramp from 75 to 0 41 | uint8_t lin_data_b[] = {0x98, 0x00, 0x00, 0xFF, 0x07}; 42 | lin.order(0x23, lin_data_b, 5); 43 | delay(1000); 44 | 45 | // Amber 46 | uint8_t lin_data_a[] = {0x08, 0x80, 0x80, 0x00, 0x08}; 47 | lin.order(0x23, lin_data_a, 5); 48 | delay(1000); 49 | 50 | // Cyan 51 | uint8_t lin_data_c[] = {0x1F, 0x00, 0x80, 0x80, 0x0F}; 52 | lin.order(0x23, lin_data_c, 5); 53 | delay(1000); 54 | } 55 | 56 | void blinkLED() { 57 | ledState = !ledState; 58 | 59 | digitalWrite(LED_BUILTIN, ledState); 60 | } -------------------------------------------------------------------------------- /examples/NCV7430_RGB_demo/NCV7430_RGB_demo.ino: -------------------------------------------------------------------------------- 1 | #include "lin_bus.h" 2 | 3 | // Create an IntervalTimer object 4 | IntervalTimer myTimer; 5 | 6 | int ledState = LOW; // ledState used to set the LED 7 | unsigned long interval = 200000; // interval at which to blinkLED to run every 0.2 seconds 8 | 9 | #define SET_LED_CONTROL 0x23 10 | #define SET_LED_COLOUR 0x24 11 | 12 | LIN lin(&Serial1, 19200); 13 | 14 | int lin_cs = 23; 15 | 16 | // Grp Grp Fade Intense G R B 17 | uint8_t buffer_red[] = {0xc0, 0x00, 0x00, 0x00, 0x31, 0x00, 0xff, 0x00}; 18 | uint8_t buffer_green[] = {0xc0, 0x00, 0x00, 0x00, 0x31, 0xff, 0x00, 0x00}; 19 | uint8_t buffer_blue[] = {0xc0, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0xff}; 20 | 21 | void setup() { 22 | pinMode(LED_BUILTIN, OUTPUT); 23 | pinMode(lin_cs, OUTPUT); 24 | digitalWrite(lin_cs, HIGH); 25 | 26 | Serial.begin(115200); 27 | Serial.print("NVC7430 RGB Demo"); 28 | 29 | init_ncv7430(); 30 | myTimer.begin(blinkLED, interval); 31 | } 32 | 33 | void loop() { 34 | // Red 35 | Serial.println("red"); 36 | set_nvc7430_color(buffer_red); 37 | delay(1000); 38 | 39 | // Green 40 | Serial.println("green"); 41 | set_nvc7430_color(buffer_green); 42 | delay(1000); 43 | 44 | // Blue 45 | Serial.println("blue"); 46 | set_nvc7430_color(buffer_blue); 47 | delay(1000); 48 | } 49 | 50 | void init_ncv7430(void) { 51 | uint8_t control_buffer[] = {0xc0, 0x00, 0x00, 0x7f}; 52 | 53 | lin.order(SET_LED_CONTROL, control_buffer, 4); 54 | } 55 | 56 | void set_nvc7430_color(byte* message) { 57 | lin.order(SET_LED_COLOUR, message, 8); 58 | } 59 | 60 | void blinkLED() { 61 | ledState = !ledState; 62 | 63 | digitalWrite(LED_BUILTIN, ledState); 64 | } -------------------------------------------------------------------------------- /examples/NCV7430_Get_Full_Status/NCV7430_Get_Full_Status.ino: -------------------------------------------------------------------------------- 1 | #include "lin_bus.h" 2 | 3 | // Create an IntervalTimer object 4 | IntervalTimer myTimer; 5 | 6 | int ledState = LOW; // ledState used to set the LED 7 | unsigned long interval = 200000; // interval at which to blinkLED to run every 0.2 seconds 8 | 9 | #define SET_LED_CONTROL 0x23 10 | #define DIAGNOSTIC_FRAME_MASTER 0x3c 11 | #define DIAGNOSTIC_FRAME_SLAVE 0x3d 12 | 13 | int lin_cs = 23; 14 | 15 | LIN lin(&Serial1, 19200); 16 | 17 | #define len 8 18 | uint8_t lin_data[len]; 19 | 20 | void init_ncv7430(void) { 21 | uint8_t control_buffer[] = {0xc0, 0x00, 0x00, 0x7f}; 22 | 23 | lin.order(SET_LED_CONTROL, control_buffer, 4); 24 | } 25 | 26 | void get_nvc7430_full_status(uint8_t* data, uint8_t lenght) { 27 | uint8_t rx_buffer[] = {0x80, 0x81, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff}; 28 | 29 | lin.order(DIAGNOSTIC_FRAME_MASTER, rx_buffer, 8); 30 | 31 | Serial.print("CRC: "); 32 | Serial.println(lin.response(DIAGNOSTIC_FRAME_SLAVE, data, lenght),HEX); 33 | } 34 | 35 | void setup() { 36 | pinMode(LED_BUILTIN, OUTPUT); 37 | pinMode(lin_cs, OUTPUT); 38 | digitalWrite(lin_cs, HIGH); 39 | 40 | Serial.begin(115200); 41 | Serial.print("NVC7430 Full Status Demo"); 42 | 43 | init_ncv7430(); 44 | myTimer.begin(blinkLED, interval); 45 | } 46 | 47 | void loop() { 48 | get_nvc7430_full_status(lin_data, len); 49 | frame(lin_data, len); 50 | delay(3000); 51 | } 52 | 53 | void frame(uint8_t* data, uint8_t lenght) { 54 | for (int i=0; i_stream = stream; 7 | 8 | Tbit = 1000000/baudrate; 9 | responsespace = responsedelay*Tbit; 10 | interbytespace = interbytedelay*Tbit; 11 | syncfieldPIDinterbytespace = syncfieldPIDinterbytedelay*Tbit; 12 | breakfieldinterbytespace = breakfieldinterbytedelay*Tbit; 13 | response_nominalspace = response_nominal*Tbit; 14 | response_maximalspace = response_nominalspace*response_max_factor; 15 | 16 | if (stream == &Serial1) { 17 | #if defined (__MK20DX128__) || defined(__MK20DX256__) || (__MKL26Z64__) || (__MK64FX512__) || (__MK66FX1M0__) 18 | PortRegister_C1 = &UART0_C1; 19 | PortRegister_C2 = &UART0_C2; 20 | PortRegister_C4 = &UART0_C4; 21 | PortRegister_S2 = &UART0_S2; 22 | PortRegister_BDH = &UART0_BDH; 23 | #ifdef HAS_KINETISK_UART0_FIFO 24 | UART0_RWFIFO = 1; 25 | #endif // HAS_KINETISK_UART0_FIFO 26 | #elif defined(__IMXRT1062__) // Teensy 4.0 & 4.1 27 | PortRegister_LPUART_STAT = &LPUART6_STAT; 28 | PortRegister_LPUART_BAUD = &LPUART6_BAUD; 29 | PortRegister_LPUART_CTRL = &LPUART6_CTRL; 30 | #endif 31 | } 32 | 33 | if (stream == &Serial2) { 34 | #if defined (__MK20DX128__) || defined(__MK20DX256__) || (__MKL26Z64__) || (__MK64FX512__) || (__MK66FX1M0__) 35 | PortRegister_C1 = &UART1_C1; 36 | PortRegister_C2 = &UART1_C2; 37 | PortRegister_C4 = &UART1_C4; 38 | PortRegister_S2 = &UART1_S2; 39 | PortRegister_BDH = &UART1_BDH; 40 | #ifdef HAS_KINETISK_UART1_FIFO 41 | UART1_RWFIFO = 1; 42 | #endif // HAS_KINETISK_UART0_FIFO 43 | #elif defined(__IMXRT1062__) // Teensy 4.0 & 4.1 44 | PortRegister_LPUART_STAT = &LPUART4_STAT; 45 | PortRegister_LPUART_BAUD = &LPUART4_BAUD; 46 | PortRegister_LPUART_CTRL = &LPUART4_CTRL; 47 | #endif 48 | } 49 | 50 | if (stream == &Serial3) { 51 | #if defined (__MK20DX128__) || defined(__MK20DX256__) || (__MKL26Z64__) || (__MK64FX512__) || (__MK66FX1M0__) 52 | PortRegister_C1 = &UART2_C1; 53 | PortRegister_C2 = &UART2_C2; 54 | PortRegister_C4 = &UART2_C4; 55 | PortRegister_S2 = &UART2_S2; 56 | PortRegister_BDH = &UART2_BDH; 57 | #elif defined(__IMXRT1062__) // Teensy 4.0 & 4.1 58 | PortRegister_LPUART_STAT = &LPUART2_STAT; 59 | PortRegister_LPUART_BAUD = &LPUART2_BAUD; 60 | PortRegister_LPUART_CTRL = &LPUART2_CTRL; 61 | #endif 62 | } 63 | 64 | #if defined (__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) 65 | if (stream == &Serial4) { 66 | #if defined (__MK64FX512__) || defined(__MK66FX1M0__) 67 | PortRegister_C1 = &UART3_C1; 68 | PortRegister_C2 = &UART3_C2; 69 | PortRegister_C4 = &UART3_C4; 70 | PortRegister_S2 = &UART3_S2; 71 | PortRegister_BDH = &UART3_BDH; 72 | #elif defined(__IMXRT1062__) // Teensy 4.0 & 4.1 73 | PortRegister_LPUART_STAT = &LPUART3_STAT; 74 | PortRegister_LPUART_BAUD = &LPUART3_BAUD; 75 | PortRegister_LPUART_CTRL = &LPUART3_CTRL; 76 | #endif 77 | } 78 | 79 | if (stream == &Serial5) { 80 | #if defined (__MK64FX512__) || defined(__MK66FX1M0__) 81 | PortRegister_C1 = &UART4_C1; 82 | PortRegister_C2 = &UART4_C2; 83 | PortRegister_C4 = &UART4_C4; 84 | PortRegister_S2 = &UART4_S2; 85 | PortRegister_BDH = &UART4_BDH; 86 | #elif defined(__IMXRT1062__) // Teensy 4.0 & 4.1 87 | PortRegister_LPUART_STAT = &LPUART8_STAT; 88 | PortRegister_LPUART_BAUD = &LPUART8_BAUD; 89 | PortRegister_LPUART_CTRL = &LPUART8_CTRL; 90 | #endif 91 | } 92 | 93 | if (stream == &Serial6) { 94 | #if defined (__MK64FX512__) 95 | PortRegister_C1 = &UART5_C1; 96 | PortRegister_C2 = &UART5_C2; 97 | PortRegister_C4 = &UART5_C4; 98 | PortRegister_S2 = &UART5_S2; 99 | PortRegister_BDH = &UART5_BDH; 100 | #elif defined(__MK66FX1M0__) 101 | PortRegister_LPUART_STAT = &LPUART0_STAT; 102 | PortRegister_LPUART_BAUD = &LPUART0_BAUD; 103 | PortRegister_LPUART_CTRL = &LPUART0_CTRL; 104 | #elif defined(__IMXRT1062__) // Teensy 4.0 & 4.1 105 | PortRegister_LPUART_STAT = &LPUART1_STAT; 106 | PortRegister_LPUART_BAUD = &LPUART1_BAUD; 107 | PortRegister_LPUART_CTRL = &LPUART1_CTRL; 108 | #endif 109 | } 110 | #endif 111 | 112 | #if defined(__IMXRT1062__) // Teensy 4.0 & 4.1 113 | if (stream == &Serial7) { 114 | PortRegister_LPUART_STAT = &LPUART7_STAT; 115 | PortRegister_LPUART_BAUD = &LPUART7_BAUD; 116 | PortRegister_LPUART_CTRL = &LPUART7_CTRL; 117 | } 118 | #endif 119 | 120 | #if defined(__IMXRT1062__) && defined(ARDUINO_TEENSY41) // Teensy 4.1 121 | if (stream == &Serial8) { 122 | PortRegister_LPUART_STAT = &LPUART5_STAT; 123 | PortRegister_LPUART_BAUD = &LPUART5_BAUD; 124 | PortRegister_LPUART_CTRL = &LPUART5_CTRL; 125 | } 126 | #endif 127 | 128 | #if defined (__MK20DX128__) || defined(__MK20DX256__) // Teensy 3.0 & 3.1 & 3.2 129 | breaklength(break_characters); 130 | #elif defined (__MK64FX512__) // Teensy 3.5 131 | breaklength_35(break_characters); 132 | #elif defined (__MK66FX1M0__) // Teensy 3.6 133 | if (stream == &Serial6) 134 | breaklength_LP(break_characters); 135 | else 136 | breaklength_35(break_characters); 137 | #elif defined (__MKL26Z64__) // Teensy LC 138 | breaklength_LC(break_characters, stream); 139 | #elif defined(__IMXRT1062__) // Teensy 4.0 & 4.1 140 | breaklength_LP(break_characters); 141 | #endif 142 | } 143 | 144 | void LIN::breaklength_LP(uint8_t length) { 145 | switch (length) { 146 | #if defined(__IMXRT1062__) // Teensy 4.0 & 4.1 147 | case 9: 148 | // 9 Bits transmitted 149 | (*PortRegister_LPUART_STAT) &= ~LPUART_STAT_BRK13; 150 | (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_SBNS; 151 | (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_M; 152 | (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_M10; 153 | (*PortRegister_LPUART_CTRL) |= LPUART_CTRL_M7; 154 | #endif 155 | case 10: 156 | // 10 Bits transmitted 157 | (*PortRegister_LPUART_STAT) &= ~LPUART_STAT_BRK13; 158 | (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_SBNS; 159 | (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_M; 160 | (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_M10; 161 | #if defined(__IMXRT1062__) // Teensy 4.0 & 4.1 162 | (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_M7; 163 | #endif 164 | break; 165 | case 11: 166 | // 11 Bits transmitted 167 | (*PortRegister_LPUART_STAT) &= ~LPUART_STAT_BRK13; 168 | (*PortRegister_LPUART_BAUD) |= LPUART_BAUD_SBNS; 169 | (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_M; 170 | (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_M10; 171 | #if defined(__IMXRT1062__) // Teensy 4.0 & 4.1 172 | (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_M7; 173 | #endif 174 | break; 175 | case 12: 176 | // 12 Bits transmitted 177 | (*PortRegister_LPUART_STAT) &= ~LPUART_STAT_BRK13; 178 | (*PortRegister_LPUART_BAUD) |= LPUART_BAUD_SBNS; 179 | (*PortRegister_LPUART_CTRL) |= LPUART_CTRL_M; 180 | (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_M10; 181 | break; 182 | case 13: 183 | // 13 Bits transmitted 184 | (*PortRegister_LPUART_STAT) |= LPUART_STAT_BRK13; 185 | (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_SBNS; 186 | (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_M; 187 | (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_M10; 188 | #if defined(__IMXRT1062__) // Teensy 4.0 & 4.1 189 | (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_M7; 190 | #endif 191 | break; 192 | case 14: 193 | // 14 Bits transmitted 194 | (*PortRegister_LPUART_STAT) |= LPUART_STAT_BRK13; 195 | (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_SBNS; 196 | (*PortRegister_LPUART_CTRL) |= LPUART_CTRL_M; 197 | (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_M10; 198 | break; 199 | case 15: 200 | // 15 Bits transmitted 201 | (*PortRegister_LPUART_STAT) |= LPUART_STAT_BRK13; 202 | (*PortRegister_LPUART_BAUD) |= LPUART_BAUD_SBNS; 203 | (*PortRegister_LPUART_BAUD) |= LPUART_BAUD_M10; 204 | break; 205 | } 206 | } 207 | 208 | #if defined (__MK20DX128__) || defined(__MK20DX256__) || (__MKL26Z64__) || (__MK64FX512__) || (__MK66FX1M0__) 209 | void LIN::breaklength_35(uint8_t length) { 210 | switch (length) { 211 | case 10: 212 | // 10 Bits transmitted 213 | (*PortRegister_S2) &= ~UART_S2_BRK13; 214 | (*PortRegister_BDH) &= ~UART_BDH_SBNS; 215 | (*PortRegister_C1) &= ~UART_C1_M; 216 | break; 217 | case 11: 218 | // 11 Bits transmitted 219 | (*PortRegister_S2) &= ~UART_S2_BRK13; 220 | (*PortRegister_BDH) |= UART_BDH_SBNS; 221 | (*PortRegister_C1) &= ~UART_C1_M; 222 | break; 223 | case 12: 224 | // 12 Bits transmitted 225 | (*PortRegister_S2) &= ~UART_S2_BRK13; 226 | (*PortRegister_BDH) |= UART_BDH_SBNS; 227 | (*PortRegister_C1) |= UART_C1_M; 228 | (*PortRegister_C4) &= ~UART_C4_M10; 229 | break; 230 | case 13: 231 | // 13 Bits transmitted 232 | (*PortRegister_S2) |= UART_S2_BRK13; 233 | (*PortRegister_BDH) &= ~UART_BDH_SBNS; 234 | (*PortRegister_C1) &= ~UART_C1_M; 235 | break; 236 | case 14: 237 | // 14 Bits transmitted 238 | (*PortRegister_S2) |= UART_S2_BRK13; 239 | (*PortRegister_BDH) &= ~UART_BDH_SBNS; 240 | (*PortRegister_C1) |= UART_C1_M; 241 | break; 242 | case 15: 243 | // 15 Bits transmitted 244 | (*PortRegister_S2) |= UART_S2_BRK13; 245 | (*PortRegister_BDH) |= UART_BDH_SBNS; 246 | (*PortRegister_C1) &= ~UART_C1_M; 247 | break; 248 | case 16: 249 | // 16 Bits transmitted 250 | (*PortRegister_S2) |= UART_S2_BRK13; 251 | (*PortRegister_BDH) |= UART_BDH_SBNS; 252 | (*PortRegister_C1) |= UART_C1_M; 253 | break; 254 | } 255 | } 256 | 257 | void LIN::breaklength_LC(uint8_t length, HardwareSerial* stream) { 258 | switch (length) { 259 | case 10: 260 | // 10 Bits transmitted 261 | (*PortRegister_S2) &= ~UART_S2_BRK13; 262 | (*PortRegister_C1) &= ~UART_C1_M; 263 | (*PortRegister_BDH) &= ~UART_BDH_SBNS; 264 | if (stream == &Serial1) 265 | (*PortRegister_C4) &= ~UART_C4_M10; 266 | break; 267 | case 11: 268 | // 11 Bits transmitted 269 | (*PortRegister_S2) &= ~UART_S2_BRK13; 270 | (*PortRegister_C1) &= ~UART_C1_M; 271 | (*PortRegister_BDH) |= UART_BDH_SBNS; 272 | if (stream == &Serial1) 273 | (*PortRegister_C4) &= ~UART_C4_M10; 274 | break; 275 | case 12: 276 | // 12 Bits transmitted 277 | (*PortRegister_S2) &= ~UART_S2_BRK13; 278 | (*PortRegister_C1) |= UART_C1_M; 279 | (*PortRegister_BDH) |= UART_BDH_SBNS; 280 | if (stream == &Serial1) 281 | (*PortRegister_C4) &= ~UART_C4_M10; 282 | break; 283 | case 13: 284 | // 13 Bits transmitted 285 | (*PortRegister_S2) |= UART_S2_BRK13; 286 | (*PortRegister_C1) &= ~UART_C1_M; 287 | (*PortRegister_BDH) &= ~UART_BDH_SBNS; 288 | if (stream == &Serial1) 289 | (*PortRegister_C4) &= ~UART_C4_M10; 290 | break; 291 | case 14: 292 | // 14 Bits transmitted 293 | (*PortRegister_S2) |= UART_S2_BRK13; 294 | (*PortRegister_C1) &= ~UART_C1_M; 295 | (*PortRegister_BDH) |= UART_BDH_SBNS; 296 | if (stream == &Serial1) 297 | (*PortRegister_C4) &= ~UART_C4_M10; 298 | break; 299 | case 15: 300 | // 15 Bits transmitted 301 | (*PortRegister_S2) |= UART_S2_BRK13; 302 | (*PortRegister_C1) |= UART_C1_M; 303 | (*PortRegister_BDH) |= UART_BDH_SBNS; 304 | if (stream == &Serial1) 305 | (*PortRegister_C4) &= ~UART_C4_M10; 306 | break; 307 | case 16: 308 | // 16 Bits transmitted 309 | if (stream == &Serial1) { 310 | (*PortRegister_S2) |= UART_S2_BRK13; 311 | (*PortRegister_C4) |= UART_C4_M10; 312 | (*PortRegister_BDH) |= UART_BDH_SBNS; 313 | } 314 | break; 315 | } 316 | } 317 | 318 | void LIN::breaklength(uint8_t length) { 319 | switch (length) { 320 | case 10: 321 | // 10 Bits transmitted 322 | (*PortRegister_S2) &= ~UART_S2_BRK13; 323 | (*PortRegister_C1) &= ~UART_C1_M; 324 | break; 325 | case 11: 326 | // 11 Bits transmitted 327 | (*PortRegister_S2) &= ~UART_S2_BRK13; 328 | (*PortRegister_C1) |= UART_C1_M; 329 | (*PortRegister_C4) &= ~UART_C4_M10; 330 | break; 331 | case 12: 332 | // 12 Bits transmitted 333 | (*PortRegister_S2) &= ~UART_S2_BRK13; 334 | (*PortRegister_C1) |= UART_C1_M; 335 | (*PortRegister_C4) |= UART_C4_M10; 336 | (*PortRegister_C1) |= UART_C1_PE; 337 | break; 338 | case 13: 339 | // 13 Bits transmitted 340 | (*PortRegister_S2) |= UART_S2_BRK13; 341 | (*PortRegister_C1) &= ~UART_C1_M; 342 | break; 343 | case 14: 344 | // 14 Bits transmitted 345 | (*PortRegister_S2) |= UART_S2_BRK13; 346 | (*PortRegister_C1) |= UART_C1_M; 347 | break; 348 | } 349 | } 350 | #endif 351 | 352 | int LIN::addrParity(int PID) { 353 | int P0 = ((PID>>0) + (PID>>1) + (PID>>2) + (PID>>4)) & 1; 354 | int P1 = ~((PID>>1) + (PID>>3) + (PID>>4) + (PID>>5)) & 1; 355 | return (P0 | (P1<<1)); 356 | } 357 | 358 | //sum = 0 LIN 1.X CRC, sum = PID LIN 2.X CRC Enhanced 359 | volatile byte LIN::dataChecksum(volatile byte* message, int length, uint16_t sum) { 360 | for (int i=0; i= 256) 364 | sum -= 255; 365 | } 366 | return (~sum); 367 | } 368 | 369 | void LIN::send_break() { 370 | // Toggle SBK to send Break 371 | //UART0_C2 |= UART_C2_SBK; 372 | //UART0_C2 &= ~UART_C2_SBK; 373 | 374 | #if defined(__MK66FX1M0__) // Teensy 3.6 375 | if (_stream == &Serial6) { 376 | (*PortRegister_LPUART_CTRL) |= LPUART_CTRL_SBK; 377 | (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_SBK; 378 | } else { 379 | (*PortRegister_C2) |= UART_C2_SBK; 380 | (*PortRegister_C2) &= ~UART_C2_SBK; 381 | } 382 | #elif defined (__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MKL26Z64__) || defined(__MK66FX1M0__) // Teensy 3.0 & 3.1 & 3.2 & 3.5 383 | (*PortRegister_C2) |= UART_C2_SBK; 384 | (*PortRegister_C2) &= ~UART_C2_SBK; 385 | #elif defined(__IMXRT1062__) // Teensy 4.0 & 4.1 386 | (*PortRegister_LPUART_CTRL) |= LPUART_CTRL_SBK; 387 | (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_SBK; 388 | #endif 389 | 390 | /* 391 | #if defined (__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MKL26Z64__) // Teensy 3.0 & 3.1 & 3.2 & 3.5 392 | (*PortRegister_C2) |= UART_C2_SBK; 393 | (*PortRegister_C2) &= ~UART_C2_SBK; 394 | #elif defined(__MK66FX1M0__) // Teensy 3.6 395 | // #ifdef HAS_KINETISK_UART5 396 | if (LPU == 1) { 397 | LPUART0_CTRL |= LPUART_CTRL_SBK; 398 | LPUART0_CTRL &= ~LPUART_CTRL_SBK; 399 | #pragma "Using KINETISK_LPUART0" 400 | } else { 401 | // #else 402 | (*PortRegister_C2) |= UART_C2_SBK; 403 | (*PortRegister_C2) &= ~UART_C2_SBK; 404 | #pragma "Using all other" 405 | // #endif 406 | } 407 | #endif 408 | */ 409 | 410 | _stream->write(SYNC); //Sync 0x55 411 | _stream->flush(); 412 | 413 | delayMicroseconds(syncfieldPIDinterbytespace); 414 | } 415 | 416 | void LIN::write(byte PID, byte* message, int length, int checksumtype) { 417 | byte CRC, send_pid; 418 | 419 | send_pid = ((PID&0x3F) | (addrParity(PID)<<6)); 420 | 421 | if (checksumtype == 1) 422 | CRC = dataChecksum(message, length, 0); 423 | else 424 | CRC = dataChecksum(message, length, send_pid); 425 | 426 | _stream->write(send_pid); 427 | delayMicroseconds(breakfieldinterbytespace); 428 | 429 | for (int i = 0; i < length; i++) 430 | _stream->write(message[i]); 431 | 432 | _stream->write(CRC); 433 | _stream->flush(); 434 | } 435 | 436 | void LIN::order(byte PID, byte* message, int length, int checksumtype) { 437 | send_break(); 438 | write(PID, message, length, checksumtype); 439 | } 440 | 441 | int LIN::response(byte PID, byte message[], int length, int checksumtype) { 442 | //_stream->clear(); does not exist, this does the same! 443 | while(_stream->available() > 0) { 444 | _stream->read(); 445 | } 446 | 447 | send_break(); 448 | return read(PID, message, length, checksumtype); 449 | } 450 | 451 | int LIN::read(byte PID, byte* data, int length, int checksumtype) { 452 | byte CRC, send_pid; 453 | // +4 for Break, Sync, PID and CRC after the Data 454 | byte tmp[length+4]; 455 | uint8_t i = 0; 456 | 457 | send_pid = ((PID&0x3F) | (addrParity(PID)<<6)); 458 | 459 | _stream->write(send_pid); 460 | _stream->flush(); 461 | 462 | #if defined(__IMXRT1062__) // Teensy 4.0 & 4.1 clear Uart Buffer 463 | _stream->read(); 464 | //Serial.println(_stream->read(),HEX); 465 | #endif 466 | 467 | /* 468 | unsigned long actuall = micros(); 469 | 470 | while ( i < (length+4) ) { 471 | if ( _stream->available() ) { 472 | tmp[i] = _stream->read(); 473 | Serial.println(tmp[i], HEX); 474 | i++; 475 | } 476 | if ( (actuall+response_maximalspace) > micros() ) { 477 | break; 478 | } 479 | } 480 | */ 481 | 482 | elapsedMicros waiting; 483 | //Serial.println(waiting); 484 | 485 | while ( i < (length+4) ) { 486 | if ( _stream->available() ) { 487 | tmp[i] = _stream->read(); 488 | i++; 489 | } 490 | if ( response_maximalspace < waiting ) { 491 | break; 492 | } 493 | } 494 | //Serial.println(waiting); 495 | 496 | for ( i = 3; i < (length+3); i++) 497 | data[i-3] = tmp[i]; 498 | 499 | if (checksumtype == 1) 500 | CRC = dataChecksum(data, length, 0); 501 | else 502 | CRC = dataChecksum(data, length, send_pid); 503 | 504 | /* 505 | Serial.println("--------tmp------------"); 506 | for (i = 0; i < (length+4); i++) 507 | Serial.println(tmp[i], HEX); 508 | 509 | Serial.println("--------data-----------"); 510 | for (i = 3; i < (length+3); i++) 511 | Serial.println(data[i-3],HEX); 512 | 513 | Serial.println("--------crc------------"); 514 | Serial.println(CRC,HEX); 515 | Serial.println(tmp[length+3],HEX); 516 | Serial.println("-----------------------"); 517 | */ 518 | 519 | if (CRC == tmp[length+3]) 520 | return CRC; 521 | else 522 | return -1; 523 | } 524 | --------------------------------------------------------------------------------