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
Diff: LinMaster.cpp
- Revision:
- 3:3656b0de0e43
- Parent:
- 2:6d4c7f841a5d
- Child:
- 4:41b153e9a39c
--- a/LinMaster.cpp Sun May 11 13:14:16 2014 +0000 +++ b/LinMaster.cpp Tue May 26 08:33:46 2015 +0000 @@ -25,75 +25,134 @@ #include "LinMaster.h" -LinMaster::LinMaster(PinName Pin) +const uint8_t breakPeriodMessage = 40; /* number of timer overflows in the break field during normal LIN messages */ +const uint8_t breakPeriodAcfg = 74; /* number of timer overflows in the break field during autoconfig messages */ + +LinMaster::LinMaster(PinName InPin, PinName OutPin) { - DriverStat = INIT; - FrameStat = READY; - MyPin = Pin; - u8BreakLen = 20; - u8DelimLen = 4; - (void)Baudrate(9600); + this->DriverState = INIT; + this->LastError = NoError; + this->MyInPin = InPin; + this->MyOutPin = OutPin; + (void)this->baudrate(9600); } LinMaster::~LinMaster() { - + this->MyTicker.detach(); + this->MyTimer.stop(); } -bool LinMaster::Init(void) +bool LinMaster::init(void) { - DigitalInOut LinPin(MyPin); - LinPin.output(); - LinPin.write(1); + DigitalInOut LinOutPin(this->MyOutPin); + LinOutPin.output(); + LinOutPin.write(1); + DigitalInOut LinInPin(this->MyInPin); + LinInPin.input(); - DriverStat = IDLE; + this->DriverState = IDLE; return ( true ); } -bool LinMaster::Baudrate(uint16_t uBaud) +bool LinMaster::baudrate(uint16_t uBaud) { bool blReturn = false; if ((uBaud > 0) && (uBaud <= 20000)) { - u16BitPeriod = 1000000/uBaud; + this->u16HalfBitPeriod = 1000000/(2*uBaud); blReturn = true; } return ( blReturn ); } -uint16_t LinMaster::Baudrate(void) +uint16_t LinMaster::baudrate(void) { - return ( 1000000/u16BitPeriod ); + return ( 1000000 / (2 * this->u16HalfBitPeriod) ); } -bool LinMaster::SendFrame(FrameDir Dir, uint8_t u8ID, uint8_t* ptrData, uint8_t u8Len) +bool LinMaster::tx_frame(Frame_t * ptrFrame) { bool blReturn = false; - uint8_t i; + DigitalInOut LinInPin(this->MyInPin); + LinInPin.input(); - if (DriverStat == IDLE) + if ( (this->DriverState == IDLE) && (LinInPin.read() == 1) ) { - DriverStat = TRANSMIT; - FrameStat = BREAK; - u8NextBusLvl = 0; - u8TickCnt = 0; - Direction = Dir; - u8FrameID = u8ID; - u8FrameLen = u8Len; + /* Clear and initialize all registers */ + + /* Disable half bit interrupt */ + this->MyTicker.detach(); - for (i=0; i<u8Len; i++) - { - u8FrameData[i] = *ptrData++; - } + InterruptIn IntPin(this->MyInPin); + IntPin.fall(this, &LinMaster::PinEventHndl); + IntPin.disable_irq(); - DigitalInOut LinPin(MyPin); + DigitalInOut LinPin(this->MyOutPin); LinPin.output(); LinPin.write(1); - MyTicker.attach_us(this, &LinMaster::TickEventHndl, u16BitPeriod); + this->DriverState = TRANSMIT; /* State of the LIN bus is transceiving a frame */ + this->LastError = NoError; + this->FrameStatus = FStart; + this->ByteStatus = BStart; + this->RXbufIndex = 0; /* Reset index in the receiver buffer */ + this->TXbufIndex = 0; /* Reset index in the transmit buffer */ + + /* Set the correct brake-length */ + if (ptrFrame->Brake == AutoConfig) + { + this->breakLength = breakPeriodAcfg; + } + else + { + this->breakLength = breakPeriodMessage; + } + + this->FrameLength = 1 + 1 + ptrFrame->DataLen + 1; /* Frame length = Sync + Frame ID + Data Len + CRC */ + this->linMessageType = ptrFrame->FrameType; + + /* Create the correct frame buffer */ + this->TXbuf[0] = 0x55; /* Sync field */ + this->TXbuf[1] = this->parity(ptrFrame->FrameID); /* Frame ID */ + + if (this->linMessageType == M2S) + { + uint16_t u16Crc; + uint8_t i; + + if (ptrFrame->CrcType == Enhanced) + { + u16Crc = TXbuf[1]; + } + else + { + u16Crc = 0; + } + + for (i = 0; i < ptrFrame->DataLen; i++) + { + this->TXbuf[i + 2] = ptrFrame->Data[i]; /* Data */ + u16Crc += ptrFrame->Data[i]; + if (u16Crc >= 256) + { + u16Crc -= 255; + } + } + this->TXbuf[ptrFrame->DataLen + 2] = (uint8_t)(~u16Crc); + } + else + { + /* S2M message */ + this->RXtimeout = ((ptrFrame->DataLen + 1) * 14) * 2; /* Calculate RX timeout in half bit-times */ + this->RXtimeoutSubCTR = 0; + } + + /* Configure and start the half bit timer */ + this->MyTicker.attach_us(this, &LinMaster::TickEventHndl, this->u16HalfBitPeriod); blReturn = true; } @@ -101,134 +160,429 @@ return ( blReturn ); } +bool LinMaster::rx_frame(Frame_t *ptrFrame) +{ + uint16_t u16Crc; + uint8_t i; + + if (this->DriverState != IDLE) + { + return (false); + } + + /* Copy data and check RX frame CRC */ + if (ptrFrame->CrcType == Enhanced) + { + u16Crc = RXbuf[1]; + } + else + { + u16Crc = 0; + } + + for (i = 0; i < ptrFrame->DataLen; i++) + { + ptrFrame->Data[i] = RXbuf[1 + 1 + i]; + u16Crc += RXbuf[1 + 1 + i]; + if (u16Crc >= 256) + { + u16Crc -= 255; + } + } + + if (this->RXbuf[ptrFrame->DataLen + 2] == (uint8_t)(~u16Crc)) + { + return (true); + } + else + { + return (false); + } +} + void LinMaster::TickEventHndl(void) { - DigitalInOut LinPin(MyPin); - bool blByteSend = false; + DigitalInOut LinOutPin(this->MyOutPin); + LinOutPin.output(); - if (u8NextBusLvl != 0) + if (this->FrameStatus < Break_OK) { - LinPin.output(); - LinPin.write(1); + /* Do break field transmission */ + if (this->breakLength > 2) + { + /* Dominant Level */ + LinOutPin.write(0); + } + else + { + /* Recessive Level */ + LinOutPin.write(1); + } + + if (this->breakLength > 0) + { + this->breakLength--; + } + else + { + this->FrameStatus = Break_OK; + } } else { - LinPin.output(); - LinPin.write(0); - } - - u8TickCnt++; - - switch (FrameStat) - { - case BREAK: - u8NextBusLvl = 0; - if (u8TickCnt >= u8BreakLen) + /* Break field was transmitted */ + if (this->FrameLength == 0) { - u8TickCnt = 0; - FrameStat = DELIMITER; - u8NextBusLvl = 1; + /* No data needs to be transmitted */ + + /* Disable half bit interrupt */ + this->MyTicker.detach(); + + /* Disable LIN bus level interrupt */ + InterruptIn IntPin(this->MyInPin); + IntPin.disable_irq(); } - break; - - case DELIMITER: - if (u8TickCnt >= u8DelimLen) + else { - u8TickCnt = 0; - FrameStat = SYNC; - u8Byte = 0xAA; - } - break; - - case SYNC: - blByteSend = true; - if (u8TickCnt >= 10) - { - u8TickCnt = 0; - FrameStat = ID; - u8Byte = u8FrameID; - } - break; - - case ID: - blByteSend = true; - if (u8TickCnt >= 10) - { - u8TickCnt = 0; - FrameStat = DATA; - u8ByteOnLin = 0; - if (Direction == M2S) + DigitalInOut LinInPin(this->MyInPin); + LinInPin.input(); + + /* Data needs to be transmitted or received */ + if ( (this->linMessageType == S2M) && + (this->FrameStatus >= ID_OK)) { - u8Byte = u8FrameData[u8ByteOnLin]; + if (this->ByteStatus > BStart) + { + /* Not waiting for start bit */ + this->ByteStatus = static_cast<ByteStatus_t>(static_cast<int>(this->ByteStatus)+1); + } + + if (this->RXtimeout > 0) + { + this->RXtimeout--; + } + else + { + this->DriverState = IDLE; + this->LastError = NoSlaveResp; + + /* Disable half bit interrupt */ + this->MyTicker.detach(); + + /* Disable LIN bus level interrupt */ + InterruptIn IntPin(this->MyInPin); + IntPin.disable_irq(); + } + + /* S2M message data receiving */ + switch (this->ByteStatus) + { + case StartbitSample: + if (LinInPin.read() == 0) + { + /* OK */ + } + else + { + /* TODO error */ + } + + break; + + case Databit0Sample: + case Databit1Sample: + case Databit2Sample: + case Databit3Sample: + case Databit4Sample: + case Databit5Sample: + case Databit6Sample: + case Databit7Sample: + /* Mid of single bit time, do sampling */ + this->RXbuf[RXbufIndex] >>= 1; + this->RXbuf[RXbufIndex] |= (LinInPin.read() << 7); + break; + + case StopbitSample: + /* End of stop bit, stop Timer IRQ */ + this->RXbufIndex++; + this->FrameStatus = static_cast<FrameStatus_t>(static_cast<int>(this->FrameStatus)+1); + this->ByteStatus = BStart; + + /* Check the current bus level */ + if (LinInPin.read() == 0) + { + this->LastError = FramingErr; /* stop bit not valid => framing error */ + } + + if ((this->RXbufIndex >= this->FrameLength) || + (this->LastError != NoError)) + { + /* All requested data bytes are received or an error occurred */ + this->DriverState = IDLE; + + /* Disable half bit interrupt */ + this->MyTicker.detach(); + + /* Disable LIN bus level interrupt */ + InterruptIn IntPin(this->MyInPin); + IntPin.disable_irq(); + } + else + { + /* Wait for a new data byte */ + + /* Disable LIN bus level interrupt */ + this->MyTimer.start(); + InterruptIn IntPin(this->MyInPin); + IntPin.enable_irq(); + } + + break; + + case Databit0Edge: + case Databit1Edge: + case Databit2Edge: + case Databit3Edge: + case Databit4Edge: + case Databit5Edge: + case Databit6Edge: + case Databit7Edge: + case StopbitEdge: + case BDone: + case BStart: + default: + /* Do nothing */ + break; + } } else { - blByteSend = false; - } - } - break; - - case DATA: - if (Direction == M2S) - { - blByteSend = true; - } - else - { - blByteSend = false; - } - - if (u8TickCnt >= 10) - { - if (Direction == S2M) - { - u8FrameData[u8ByteOnLin] = u8Byte; - } + /* Transmission of Sync + Frame ID and M2S frame data */ + this->ByteStatus = static_cast<ByteStatus_t>(static_cast<int>(this->ByteStatus)+1); + + switch (this->ByteStatus) + { + case StartbitEdge: + /* Start bit : start */ + LinOutPin.write(0); + break; + + case StartbitSample: + /* Start bit : mid */ + break; + + case Databit0Edge: + case Databit1Edge: + case Databit2Edge: + case Databit3Edge: + case Databit4Edge: + case Databit5Edge: + case Databit6Edge: + case Databit7Edge: + /* Start of new bit time */ + if (this->TXbuf[this->TXbufIndex] & 0x01) + { + /* Recessive Level */ + LinOutPin.write(1); + } + else + { + /* Dominant Level */ + LinOutPin.write(0); + } + + this->TXbuf[this->TXbufIndex] >>= 1; + break; + + case Databit0Sample: + case Databit1Sample: + case Databit2Sample: + case Databit3Sample: + case Databit4Sample: + case Databit5Sample: + case Databit6Sample: + case Databit7Sample: + /* Odd overflow, mid of bit time ==> sample the bus for RX */ + this->RXbuf[this->RXbufIndex] >>= 1; + this->RXbuf[this->RXbufIndex] |= (LinInPin.read() << 7); + break; + + case StopbitEdge: + /* Stop bit : start */ + LinOutPin.write(1); + break; - u8ByteOnLin++; - u8TickCnt = 0; - - if (u8ByteOnLin >= u8FrameLen) - { - /* Sending/Receiving is ended */ - FrameStat = READY; - blByteSend = false; - u8NextBusLvl = 1; + case StopbitSample: + /* Stop bit : mid / level check */ + if (LinInPin.read() == 0) + { + /* Stop bit not valid => framing error */ + this->LastError = FramingErr; + this->DriverState = IDLE; + + /* Disable half bit interrupt */ + this->MyTicker.detach(); + + /* Disable LIN bus level interrupt */ + InterruptIn IntPin(this->MyInPin); + IntPin.disable_irq(); + } + + break; + + case BDone: + /* Stop bit : finished */ + this->ByteStatus = BStart; + this->FrameStatus = static_cast<FrameStatus_t>(static_cast<int>(this->FrameStatus)+1); + this->TXbufIndex++; + this->RXbufIndex++; + + if (this->linMessageType == S2M) + { + /* S2M frame */ + if (this->FrameStatus == ID_OK) + { + /* Stop bit of header is sent, now start receiving data bytes */ + this->MyTimer.start(); + InterruptIn IntPin(this->MyInPin); + IntPin.enable_irq(); + } + } + else if (this->TXbufIndex >= this->FrameLength) + { + /* M2S frame, Last byte is sent */ + this->LastError = NoError; + this->DriverState = IDLE; + + /* Disable half bit interrupt */ + this->MyTicker.detach(); + + /* Disable LIN bus level interrupt */ + InterruptIn IntPin(this->MyInPin); + IntPin.disable_irq(); + } + + break; + + default: + break; + } } - else if (Direction == M2S) - { - u8Byte = u8FrameData[u8ByteOnLin]; - } - } - break; - - case READY: - default: - u8NextBusLvl = 1; - MyTicker.detach(); - FrameStat = READY; - DriverStat = IDLE; - break; - } - - if (blByteSend == true) - { - switch (u8TickCnt) - { - case 0: - /* Start Bit */ - u8NextBusLvl = 0; - break; - case 9: - /* Stop Bit */ - u8NextBusLvl = 1; - break; - default: - u8NextBusLvl = u8Byte & 0x1; - u8Byte >>= 1; - break; } } } +void LinMaster::PinEventHndl(void) +{ + switch (this->DriverState) + { + case TRANSMIT: + case RECEIVE: + { + this->ByteStatus = StartbitEdge; /* Set status of the received byte */ + this->RXtimeoutSubCTR += this->MyTimer.read_us(); + this->MyTimer.stop(); + + /* Reset ticker */ + this->MyTicker.detach(); + this->MyTicker.attach_us(this, &LinMaster::TickEventHndl, this->u16HalfBitPeriod); + + /* Disable LIN bus level interrupt */ + InterruptIn IntPin(this->MyInPin); + IntPin.disable_irq(); + + if (this->RXtimeoutSubCTR > this->u16HalfBitPeriod) + { + this->RXtimeoutSubCTR -= this->u16HalfBitPeriod; + if (this->RXtimeout > 0) + { + this->RXtimeout--; + } + } + + break; + } + + case IDLE: + case DOMINANT: + case TXWAKEUP: + break; + + case RXWAKEUP: + default: + this->DriverState = RXWAKEUP; /* It's a wake up pulse */ + break; + } +} + +/** Calculate the parity bits + * + * @param u8BYTE original byte + * @return BYTE including parity bits + */ +uint8_t LinMaster::parity(uint8_t u8BYTE) +{ + uint8_t P0 = 0; + uint8_t P1 = 0; + + /* P0 = ID0 + ID1 + ID2 + ID4 + * P1 = ~(ID1 + ID3 + ID4 + ID5) + */ + if ((u8BYTE & (1 << 0)) != 0) + { + P0 = ~P0; + } + + if ((u8BYTE & (1 << 1)) != 0) + { + P0 = ~P0; + } + + if ((u8BYTE & (1 << 2)) != 0) + { + P0 = ~P0; + } + + if ((u8BYTE & (1 << 4)) != 0) + { + P0 = ~P0; + } + + if ((u8BYTE & (1 << 1)) != 0) + { + P1 = ~P1; + } + + if ((u8BYTE & (1 << 3)) != 0) + { + P1 = ~P1; + } + + if ((u8BYTE & (1 << 4)) != 0) + { + P1 = ~P1; + } + + if ((u8BYTE & (1 << 5)) != 0) + { + P1 = ~P1; + } + + P1 = ~P1; + + u8BYTE &= 0x3f; /* Delete MSB's */ + + if (P0 != 0) + { + u8BYTE |= (1 << 6); + } + + if (P1 != 0) + { + u8BYTE |= (1 << 7); + } + + return (u8BYTE); +} + /* EOF */ \ No newline at end of file