Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: MBED_LIN_RGB_Master_Example
LinMaster.cpp
00001 /* 00002 * Master device LIN communication library for mbed 00003 * 00004 * Copyright (C) 2015 Bollen Nico 00005 * 00006 * Released under GPL v2 00007 * 00008 * Other licensing models might apply at the sole discretion of the copyright holders. 00009 * 00010 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00011 * and associated documentation files (the "Software"), to deal in the Software without restriction, 00012 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 00013 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 00014 * furnished to do so, subject to the following conditions: 00015 * 00016 * The above copyright notice and this permission notice shall be included in all copies or 00017 * substantial portions of the Software. 00018 * 00019 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 00020 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00021 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 00022 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00023 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00024 */ 00025 00026 #include "LinMaster.h" 00027 00028 const uint8_t breakPeriodMessage = 40; /* number of timer overflows in the break field during normal LIN messages */ 00029 const uint8_t breakPeriodAcfg = 74; /* number of timer overflows in the break field during autoconfig messages */ 00030 00031 LinMaster::LinMaster(PinName InPin, PinName OutPin) : LinOutPin(OutPin), LinInPin(InPin, PullUp) 00032 { 00033 this->DriverState = INIT; 00034 this->LastError = NoError; 00035 00036 this->LinOutPin.write(1); 00037 00038 this->LinInPin.disable_irq(); 00039 this->LinInPin.fall(NULL); 00040 00041 this->DriverState = IDLE; 00042 00043 (void)this->baudrate(9600); 00044 } 00045 00046 LinMaster::~LinMaster() 00047 { 00048 this->LinInPin.disable_irq(); 00049 this->LinInPin.fall(NULL); 00050 this->HalfbitTicker.detach(); 00051 this->TimeoutTicker.detach(); 00052 } 00053 00054 bool LinMaster::init(void) 00055 { 00056 this->LinOutPin.write(1); 00057 00058 this->LinInPin.enable_irq(); 00059 this->LinInPin.fall(NULL); 00060 00061 this->DriverState = IDLE; 00062 00063 return ( true ); 00064 } 00065 00066 bool LinMaster::baudrate(uint16_t uBaud) 00067 { 00068 bool blReturn = false; 00069 00070 if ((uBaud > 0) && (uBaud <= 20000)) 00071 { 00072 this->u16HalfBitPeriod = std::chrono::microseconds(1000000 / ( 2 * uBaud)); 00073 blReturn = true; 00074 } 00075 00076 return ( blReturn ); 00077 } 00078 00079 uint16_t LinMaster::baudrate(void) 00080 { 00081 return ( 1000000 / (2 * this->u16HalfBitPeriod.count()) ); 00082 } 00083 00084 bool LinMaster::send_frame(Frame_t * ptrFrame) 00085 { 00086 bool blReturn = false; 00087 00088 if ( (this->DriverState == IDLE) && (this->LinInPin.read() == 1) ) 00089 { 00090 /* Clear and initialize all registers */ 00091 memset(this->RXbuf, 0, 11); 00092 00093 /* Disable ticker interrupt */ 00094 this->HalfbitTicker.detach(); 00095 this->TimeoutTicker.detach(); 00096 00097 this->LinInPin.fall(NULL); 00098 00099 this->LinOutPin.write(1); 00100 00101 this->DriverState = TRANSMIT; /* State of the LIN bus is transceiving a frame */ 00102 this->LastError = NoError; 00103 this->FrameStatus = FStart; 00104 this->ByteStatus = BStart; 00105 this->RXbufIndex = 0; /* Reset index in the receiver buffer */ 00106 this->TXbufIndex = 0; /* Reset index in the transmit buffer */ 00107 00108 /* Set the correct brake-length */ 00109 if (ptrFrame->Brake == AutoConfig) 00110 { 00111 this->breakLength = breakPeriodAcfg; 00112 } 00113 else 00114 { 00115 this->breakLength = breakPeriodMessage; 00116 } 00117 00118 this->FrameLength = 1 + 1 + ptrFrame->DataLen + 1; /* Frame length = Sync + Frame ID + Data Len + CRC */ 00119 this->linMessageType = ptrFrame->FrameType; 00120 00121 /* Create the correct frame buffer */ 00122 this->TXbuf[0] = 0x55; /* Sync field */ 00123 this->TXbuf[1] = this->parity(ptrFrame->FrameID); /* Frame ID */ 00124 00125 if (this->linMessageType == M2S) 00126 { 00127 uint16_t u16Crc; 00128 uint8_t i; 00129 00130 if (ptrFrame->CrcType == Enhanced) 00131 { 00132 u16Crc = TXbuf[1]; 00133 } 00134 else 00135 { 00136 u16Crc = 0; 00137 } 00138 00139 for (i = 0; i < ptrFrame->DataLen; i++) 00140 { 00141 this->TXbuf[i + 2] = ptrFrame->Data[i]; /* Data */ 00142 u16Crc += ptrFrame->Data[i]; 00143 if (u16Crc >= 256) 00144 { 00145 u16Crc -= 255; 00146 } 00147 } 00148 this->TXbuf[ptrFrame->DataLen + 2] = (uint8_t)(~u16Crc); 00149 } 00150 else 00151 { 00152 /* S2M message */ 00153 00154 /* Calculate RX timeout */ 00155 this->FrameTimeout = std::chrono::microseconds(((ptrFrame->DataLen + 1) * 14) * 2 * this->u16HalfBitPeriod); 00156 } 00157 00158 /* Configure and start the half bit timer */ 00159 this->HalfbitTicker.attach(callback(this, &LinMaster::TickEventHndl), this->u16HalfBitPeriod); 00160 00161 blReturn = true; 00162 } 00163 00164 return ( blReturn ); 00165 } 00166 00167 bool LinMaster::get_rx_data(Frame_t &ptrFrame) 00168 { 00169 uint16_t u16Crc; 00170 uint8_t i; 00171 00172 if ( (this->DriverState != IDLE) || (this->LastError != NoError)) 00173 { 00174 return (false); 00175 } 00176 00177 /* Copy data and check RX frame CRC */ 00178 if (ptrFrame.CrcType == Enhanced) 00179 { 00180 u16Crc = RXbuf[1]; 00181 } 00182 else 00183 { 00184 u16Crc = 0; 00185 } 00186 00187 for (i = 0; i < ptrFrame.DataLen; i++) 00188 { 00189 ptrFrame.Data[i] = RXbuf[1 + 1 + i]; 00190 u16Crc += RXbuf[1 + 1 + i]; 00191 if (u16Crc >= 256) 00192 { 00193 u16Crc -= 255; 00194 } 00195 } 00196 00197 if (this->RXbuf[ptrFrame.DataLen + 2] == (uint8_t)(~u16Crc)) 00198 { 00199 return (true); 00200 } 00201 else 00202 { 00203 return (false); 00204 } 00205 } 00206 00207 void LinMaster::TickEventHndl(void) 00208 { 00209 int PinLevel = this->LinInPin.read(); 00210 00211 if (this->FrameStatus < Break_OK) 00212 { 00213 /* Do break field transmission */ 00214 if (this->breakLength > 2) 00215 { 00216 /* Dominant Level */ 00217 this->LinOutPin.write(0); 00218 } 00219 else 00220 { 00221 /* Recessive Level */ 00222 this->LinOutPin.write(1); 00223 } 00224 00225 if (this->breakLength > 0) 00226 { 00227 this->breakLength--; 00228 } 00229 else 00230 { 00231 this->FrameStatus = Break_OK; 00232 } 00233 } 00234 else 00235 { 00236 /* Break field was transmitted */ 00237 if (this->FrameLength == 0) 00238 { 00239 /* No data needs to be transmitted */ 00240 00241 /* Disable ticker interrupt */ 00242 this->HalfbitTicker.detach(); 00243 this->TimeoutTicker.detach(); 00244 00245 /* Disable LIN bus level interrupt */ 00246 this->LinInPin.fall(NULL); 00247 } 00248 else 00249 { 00250 /* Data needs to be transmitted or received */ 00251 if ( (this->linMessageType == S2M) && 00252 (this->FrameStatus >= ID_OK)) 00253 { 00254 if (this->ByteStatus > BStart) 00255 { 00256 /* Not waiting for start bit */ 00257 this->ByteStatus = static_cast<ByteStatus_t>(static_cast<int>(this->ByteStatus)+1); 00258 } 00259 00260 /* S2M message data receiving */ 00261 switch (this->ByteStatus) 00262 { 00263 case StartbitSample: 00264 if (PinLevel == 0) 00265 { 00266 /* OK */ 00267 } 00268 else 00269 { 00270 /* TODO error */ 00271 } 00272 00273 break; 00274 00275 case Databit0Sample: 00276 case Databit1Sample: 00277 case Databit2Sample: 00278 case Databit3Sample: 00279 case Databit4Sample: 00280 case Databit5Sample: 00281 case Databit6Sample: 00282 case Databit7Sample: 00283 /* Mid of single bit time, do sampling */ 00284 this->RXbuf[RXbufIndex] >>= 1; 00285 this->RXbuf[RXbufIndex] |= (PinLevel << 7); 00286 break; 00287 00288 case StopbitSample: 00289 /* End of stop bit, stop Timer IRQ */ 00290 00291 /* Enable LIN bus level interrupt */ 00292 this->LinInPin.fall(callback(this, &LinMaster::PinEventHndl)); 00293 00294 /* Disable half bit interrupt */ 00295 this->HalfbitTicker.detach(); 00296 00297 /* Check the current bus level */ 00298 if (PinLevel == 0) 00299 { 00300 this->LastError = FramingErr; /* stop bit not valid => framing error */ 00301 } 00302 00303 this->RXbufIndex++; 00304 this->FrameStatus = static_cast<FrameStatus_t>(static_cast<int>(this->FrameStatus)+1); 00305 this->ByteStatus = BStart; 00306 00307 if ((this->RXbufIndex >= this->FrameLength) || 00308 (this->LastError != NoError)) 00309 { 00310 /* All requested data bytes are received or an error occurred */ 00311 this->DriverState = IDLE; 00312 00313 /* Disable LIN bus level interrupt */ 00314 this->LinInPin.fall(NULL); 00315 00316 /* Disable timeout ticker */ 00317 this->TimeoutTicker.detach(); 00318 } 00319 else 00320 { 00321 /* Wait for a new data byte */ 00322 } 00323 break; 00324 00325 case Databit0Edge: 00326 case Databit1Edge: 00327 case Databit2Edge: 00328 case Databit3Edge: 00329 case Databit4Edge: 00330 case Databit5Edge: 00331 case Databit6Edge: 00332 case Databit7Edge: 00333 case StopbitEdge: 00334 case BDone: 00335 case BStart: 00336 default: 00337 /* Do nothing */ 00338 break; 00339 } 00340 } 00341 else 00342 { 00343 /* Transmission of Sync + Frame ID and M2S frame data */ 00344 this->ByteStatus = static_cast<ByteStatus_t>(static_cast<int>(this->ByteStatus)+1); 00345 00346 switch (this->ByteStatus) 00347 { 00348 case StartbitEdge: 00349 /* Start bit : start */ 00350 this->LinOutPin.write(0); 00351 break; 00352 00353 case StartbitSample: 00354 /* Start bit : mid */ 00355 break; 00356 00357 case Databit0Edge: 00358 case Databit1Edge: 00359 case Databit2Edge: 00360 case Databit3Edge: 00361 case Databit4Edge: 00362 case Databit5Edge: 00363 case Databit6Edge: 00364 case Databit7Edge: 00365 /* Start of new bit time */ 00366 if (this->TXbuf[this->TXbufIndex] & 0x01) 00367 { 00368 /* Recessive Level */ 00369 this->LinOutPin.write(1); 00370 } 00371 else 00372 { 00373 /* Dominant Level */ 00374 this->LinOutPin.write(0); 00375 } 00376 00377 this->TXbuf[this->TXbufIndex] >>= 1; 00378 break; 00379 00380 case Databit0Sample: 00381 case Databit1Sample: 00382 case Databit2Sample: 00383 case Databit3Sample: 00384 case Databit4Sample: 00385 case Databit5Sample: 00386 case Databit6Sample: 00387 case Databit7Sample: 00388 /* Odd overflow, mid of bit time ==> sample the bus for RX */ 00389 this->RXbuf[this->RXbufIndex] >>= 1; 00390 this->RXbuf[this->RXbufIndex] |= ((PinLevel << 7) & 0x80); 00391 break; 00392 00393 case StopbitEdge: 00394 /* Stop bit : start */ 00395 this->LinOutPin.write(1); 00396 break; 00397 00398 case StopbitSample: 00399 /* Stop bit : mid / level check */ 00400 if (PinLevel == 0) 00401 { 00402 /* Stop bit not valid => framing error */ 00403 this->LastError = FramingErr; 00404 this->DriverState = IDLE; 00405 00406 /* Disable ticker interrupt */ 00407 this->HalfbitTicker.detach(); 00408 this->TimeoutTicker.detach(); 00409 00410 /* Disable LIN bus level interrupt */ 00411 this->LinInPin.fall(NULL); 00412 } 00413 00414 this->FrameStatus = static_cast<FrameStatus_t>(static_cast<int>(this->FrameStatus)+1); 00415 this->TXbufIndex++; 00416 this->RXbufIndex++; 00417 00418 if ((this->linMessageType == S2M) && (this->FrameStatus == ID_OK)) 00419 { 00420 /* Stop bit of header is sent, now start receiving data bytes */ 00421 00422 /* Enable LIN bus level interrupt */ 00423 this->LinInPin.fall(callback(this, &LinMaster::PinEventHndl)); 00424 00425 /* Disable half bit interrupt */ 00426 this->HalfbitTicker.detach(); 00427 00428 /* Enable frame timeout interrupt */ 00429 this->TimeoutTicker.attach(callback(this, &LinMaster::RXtimeoutEventHndl), this->FrameTimeout); 00430 } 00431 break; 00432 00433 case BDone: 00434 /* Stop bit : finished */ 00435 this->ByteStatus = BStart; 00436 00437 if (this->TXbufIndex >= this->FrameLength) 00438 { 00439 /* M2S frame, Last byte is sent */ 00440 this->LastError = NoError; 00441 this->DriverState = IDLE; 00442 00443 /* Disable LIN bus level interrupt */ 00444 this->LinInPin.fall(NULL); 00445 00446 /* Disable ticker interrupts */ 00447 this->TimeoutTicker.detach(); 00448 this->HalfbitTicker.detach(); 00449 } 00450 break; 00451 00452 default: 00453 break; 00454 } 00455 } 00456 } 00457 } 00458 } 00459 00460 void LinMaster::RXtimeoutEventHndl(void) 00461 { 00462 /* Disable LIN bus level interrupt */ 00463 this->LinInPin.fall(NULL); 00464 00465 /* Disable half bit interrupt */ 00466 this->HalfbitTicker.detach(); 00467 this->TimeoutTicker.detach(); 00468 00469 this->DriverState = IDLE; 00470 this->LastError = NoSlaveResp; 00471 } 00472 00473 void LinMaster::PinEventHndl(void) 00474 { 00475 switch (this->DriverState) 00476 { 00477 case TRANSMIT: 00478 case RECEIVE: 00479 { 00480 this->ByteStatus = StartbitSample; /* Set status of the received byte */ 00481 00482 /* Reset ticker */ 00483 this->HalfbitTicker.attach(callback(this, &LinMaster::TickEventHndl), this->u16HalfBitPeriod); 00484 00485 /* Disable LIN bus level interrupt */ 00486 this->LinInPin.fall(NULL); 00487 break; 00488 } 00489 00490 case IDLE: 00491 case DOMINANT: 00492 case TXWAKEUP: 00493 break; 00494 00495 case RXWAKEUP: 00496 default: 00497 this->DriverState = RXWAKEUP; /* It's a wake up pulse */ 00498 break; 00499 } 00500 } 00501 00502 /** Calculate the parity bits 00503 * 00504 * @param u8BYTE original byte 00505 * @return BYTE including parity bits 00506 */ 00507 uint8_t LinMaster::parity(uint8_t u8BYTE) 00508 { 00509 uint8_t P0 = 0; 00510 uint8_t P1 = 0; 00511 00512 /* P0 = ID0 + ID1 + ID2 + ID4 00513 * P1 = ~(ID1 + ID3 + ID4 + ID5) 00514 */ 00515 if ((u8BYTE & (1 << 0)) != 0) 00516 { 00517 P0 = ~P0; 00518 } 00519 00520 if ((u8BYTE & (1 << 1)) != 0) 00521 { 00522 P0 = ~P0; 00523 } 00524 00525 if ((u8BYTE & (1 << 2)) != 0) 00526 { 00527 P0 = ~P0; 00528 } 00529 00530 if ((u8BYTE & (1 << 4)) != 0) 00531 { 00532 P0 = ~P0; 00533 } 00534 00535 if ((u8BYTE & (1 << 1)) != 0) 00536 { 00537 P1 = ~P1; 00538 } 00539 00540 if ((u8BYTE & (1 << 3)) != 0) 00541 { 00542 P1 = ~P1; 00543 } 00544 00545 if ((u8BYTE & (1 << 4)) != 0) 00546 { 00547 P1 = ~P1; 00548 } 00549 00550 if ((u8BYTE & (1 << 5)) != 0) 00551 { 00552 P1 = ~P1; 00553 } 00554 00555 P1 = ~P1; 00556 00557 u8BYTE &= 0x3f; /* Delete MSB's */ 00558 00559 if (P0 != 0) 00560 { 00561 u8BYTE |= (1 << 6); 00562 } 00563 00564 if (P1 != 0) 00565 { 00566 u8BYTE |= (1 << 7); 00567 } 00568 00569 return (u8BYTE); 00570 } 00571 00572 /* EOF */
Generated on Tue Jul 12 2022 18:16:45 by
1.7.2