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