Consider glitches on DCC line
Glitches on the DCC line could make the decoding Irq hang in an dead lock state. ( if it interrupts itself - this is now recognized )
This commit is contained in:
56
NmraDcc.cpp
56
NmraDcc.cpp
@@ -20,6 +20,7 @@
|
|||||||
// Experimental Version to support 14 speed steps
|
// Experimental Version to support 14 speed steps
|
||||||
// and new signature of notifyDccSpeed and notifyDccFunc
|
// and new signature of notifyDccSpeed and notifyDccFunc
|
||||||
// 2015-12-16 Version without use of Timer0 by Franz-Peter Müller
|
// 2015-12-16 Version without use of Timer0 by Franz-Peter Müller
|
||||||
|
// 2016-07-16 handle glitches on DCC line
|
||||||
//
|
//
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
@@ -60,14 +61,14 @@
|
|||||||
//
|
//
|
||||||
// |<-----116us----->|
|
// |<-----116us----->|
|
||||||
// DCC 1: _________XXXXXXXXX_________XXXXXXXXX_________
|
// DCC 1: _________XXXXXXXXX_________XXXXXXXXX_________
|
||||||
// |<--------138us------>|
|
// |<--------146us------>|
|
||||||
// ^-INTx ^-INTx
|
// ^-INTx ^-INTx
|
||||||
// less than 138us: its a one-Bit
|
// less than 138us: its a one-Bit
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// |<-----------------232us----------->|
|
// |<-----------------232us----------->|
|
||||||
// DCC 0: _________XXXXXXXXXXXXXXXXXX__________________XXXXXXXX__________
|
// DCC 0: _________XXXXXXXXXXXXXXXXXX__________________XXXXXXXX__________
|
||||||
// |<--------138us------->|
|
// |<--------146us------->|
|
||||||
// ^-INTx ^-INTx
|
// ^-INTx ^-INTx
|
||||||
// greater than 138us: its a zero bit
|
// greater than 138us: its a zero bit
|
||||||
//
|
//
|
||||||
@@ -76,8 +77,12 @@
|
|||||||
//
|
//
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
#define MAX_ONEBITFULL 146
|
#define MAX_ONEBITFULL 146
|
||||||
#define MAX_PRAEAMBEL 146 //138
|
#define MAX_PRAEAMBEL 146
|
||||||
#define MAX_ONEBITHALF 82
|
#define MAX_ONEBITHALF 82
|
||||||
|
#define MIN_ONEBITFULL 82
|
||||||
|
#define MIN_ONEBITHALF 35
|
||||||
|
#define MAX_BITDIFF 18
|
||||||
|
|
||||||
|
|
||||||
// Debug-Ports
|
// Debug-Ports
|
||||||
//#define debug // Testpulse for logic analyser
|
//#define debug // Testpulse for logic analyser
|
||||||
@@ -192,7 +197,7 @@ struct countOf_t countOf;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static byte ISREdge; // RISING or FALLING
|
static byte ISREdge; // RISING or FALLING
|
||||||
static word bitMax;
|
static word bitMax, bitMin;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -228,6 +233,7 @@ typedef struct
|
|||||||
#ifdef DCC_DEBUG
|
#ifdef DCC_DEBUG
|
||||||
uint8_t IntCount;
|
uint8_t IntCount;
|
||||||
uint8_t TickCount;
|
uint8_t TickCount;
|
||||||
|
uint8_t NestedIrqCount;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
DCC_PROCESSOR_STATE ;
|
DCC_PROCESSOR_STATE ;
|
||||||
@@ -240,16 +246,35 @@ void ExternalInterruptHandler(void)
|
|||||||
uint8_t DccBitVal;
|
uint8_t DccBitVal;
|
||||||
static int8_t bit1, bit2 ;
|
static int8_t bit1, bit2 ;
|
||||||
static word lastMicros;
|
static word lastMicros;
|
||||||
static byte halfBit;
|
static byte halfBit, DCC_IrqRunning;
|
||||||
unsigned int actMicros, bitMicros;
|
unsigned int actMicros, bitMicros;
|
||||||
|
if ( DCC_IrqRunning ) {
|
||||||
|
// nested DCC IRQ - obviously there are glitches
|
||||||
|
// ignore this interrupt and increment glitchcounter
|
||||||
|
CLR_TP3;
|
||||||
|
#ifdef DCC_DEBUG
|
||||||
|
DccProcState.NestedIrqCount++;
|
||||||
|
#endif
|
||||||
|
SET_TP3;
|
||||||
|
return; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> abort IRQ
|
||||||
|
}
|
||||||
SET_TP3;
|
SET_TP3;
|
||||||
actMicros = micros();
|
actMicros = micros();
|
||||||
bitMicros = actMicros-lastMicros;
|
bitMicros = actMicros-lastMicros;
|
||||||
|
if ( bitMicros < bitMin ) {
|
||||||
|
// too short - my be false interrupt due to glitch or false protocol -> ignore
|
||||||
|
CLR_TP3;
|
||||||
|
SET_TP4;
|
||||||
|
SET_TP4;
|
||||||
|
CLR_TP4;
|
||||||
|
return; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> abort IRQ
|
||||||
|
}
|
||||||
DccBitVal = ( bitMicros < bitMax );
|
DccBitVal = ( bitMicros < bitMax );
|
||||||
lastMicros = actMicros;
|
lastMicros = actMicros;
|
||||||
//#ifdef debug
|
//#ifdef debug
|
||||||
if(DccBitVal) {SET_TP2} else {CLR_TP2};
|
if(DccBitVal) {SET_TP2;} else {CLR_TP2;};
|
||||||
//#endif
|
//#endif
|
||||||
|
DCC_IrqRunning = true;
|
||||||
sei(); // time critical is only the micros() command,so allow nested irq's
|
sei(); // time critical is only the micros() command,so allow nested irq's
|
||||||
#ifdef DCC_DEBUG
|
#ifdef DCC_DEBUG
|
||||||
DccProcState.TickCount++;
|
DccProcState.TickCount++;
|
||||||
@@ -269,6 +294,7 @@ void ExternalInterruptHandler(void)
|
|||||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, CHANGE);
|
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, CHANGE);
|
||||||
halfBit = 0;
|
halfBit = 0;
|
||||||
bitMax = MAX_ONEBITHALF;
|
bitMax = MAX_ONEBITHALF;
|
||||||
|
bitMin = MIN_ONEBITHALF;
|
||||||
CLR_TP1;
|
CLR_TP1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -299,12 +325,13 @@ void ExternalInterruptHandler(void)
|
|||||||
halfBit = 0;
|
halfBit = 0;
|
||||||
bit2=bitMicros;
|
bit2=bitMicros;
|
||||||
DccRx.BitCount++;
|
DccRx.BitCount++;
|
||||||
if( abs(bit2-bit1) > 14 ) {
|
if( abs(bit2-bit1) > MAX_BITDIFF ) {
|
||||||
// the length of the 2 halbits differ too much -> wrong protokoll
|
// the length of the 2 halfbits differ too much -> wrong protokoll
|
||||||
CLR_TP2;
|
CLR_TP2;
|
||||||
CLR_TP3;
|
CLR_TP3;
|
||||||
DccRx.State = WAIT_PREAMBLE;
|
DccRx.State = WAIT_PREAMBLE;
|
||||||
bitMax = MAX_PRAEAMBEL;
|
bitMax = MAX_PRAEAMBEL;
|
||||||
|
bitMin = MIN_ONEBITFULL;
|
||||||
DccRx.BitCount = 0;
|
DccRx.BitCount = 0;
|
||||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
||||||
SET_TP3;
|
SET_TP3;
|
||||||
@@ -320,6 +347,7 @@ void ExternalInterruptHandler(void)
|
|||||||
// its a '1' halfbit -> we got only a half '0' bit -> cannot be DCC
|
// its a '1' halfbit -> we got only a half '0' bit -> cannot be DCC
|
||||||
DccRx.State = WAIT_PREAMBLE;
|
DccRx.State = WAIT_PREAMBLE;
|
||||||
bitMax = MAX_PRAEAMBEL;
|
bitMax = MAX_PRAEAMBEL;
|
||||||
|
bitMin = MIN_ONEBITFULL;
|
||||||
DccRx.BitCount = 0;
|
DccRx.BitCount = 0;
|
||||||
} else {
|
} else {
|
||||||
// we got two '0' halfbits -> it's the startbit
|
// we got two '0' halfbits -> it's the startbit
|
||||||
@@ -327,6 +355,7 @@ void ExternalInterruptHandler(void)
|
|||||||
if ( ISREdge == RISING ) ISREdge = FALLING; else ISREdge = RISING;
|
if ( ISREdge == RISING ) ISREdge = FALLING; else ISREdge = RISING;
|
||||||
DccRx.State = WAIT_DATA ;
|
DccRx.State = WAIT_DATA ;
|
||||||
bitMax = MAX_ONEBITFULL;
|
bitMax = MAX_ONEBITFULL;
|
||||||
|
bitMin = MIN_ONEBITFULL;
|
||||||
DccRx.PacketBuf.Size = 0;
|
DccRx.PacketBuf.Size = 0;
|
||||||
DccRx.PacketBuf.PreambleBits = 0;
|
DccRx.PacketBuf.PreambleBits = 0;
|
||||||
for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ )
|
for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ )
|
||||||
@@ -345,11 +374,13 @@ void ExternalInterruptHandler(void)
|
|||||||
// second halfbit is 1 -> unknown protokoll
|
// second halfbit is 1 -> unknown protokoll
|
||||||
DccRx.State = WAIT_PREAMBLE;
|
DccRx.State = WAIT_PREAMBLE;
|
||||||
bitMax = MAX_PRAEAMBEL;
|
bitMax = MAX_PRAEAMBEL;
|
||||||
|
bitMin = MIN_ONEBITFULL;
|
||||||
DccRx.BitCount = 0;
|
DccRx.BitCount = 0;
|
||||||
} else {
|
} else {
|
||||||
// we got the startbit
|
// we got the startbit
|
||||||
DccRx.State = WAIT_DATA ;
|
DccRx.State = WAIT_DATA ;
|
||||||
bitMax = MAX_ONEBITFULL;
|
bitMax = MAX_ONEBITFULL;
|
||||||
|
bitMin = MIN_ONEBITFULL;
|
||||||
DccRx.PacketBuf.Size = 0;
|
DccRx.PacketBuf.Size = 0;
|
||||||
DccRx.PacketBuf.PreambleBits = 0;
|
DccRx.PacketBuf.PreambleBits = 0;
|
||||||
for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ )
|
for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ )
|
||||||
@@ -378,6 +409,7 @@ void ExternalInterruptHandler(void)
|
|||||||
{
|
{
|
||||||
DccRx.State = WAIT_PREAMBLE ;
|
DccRx.State = WAIT_PREAMBLE ;
|
||||||
bitMax = MAX_PRAEAMBEL;
|
bitMax = MAX_PRAEAMBEL;
|
||||||
|
bitMin = MIN_ONEBITFULL;
|
||||||
DccRx.BitCount = 0 ;
|
DccRx.BitCount = 0 ;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -395,6 +427,7 @@ void ExternalInterruptHandler(void)
|
|||||||
CLR_TP3;
|
CLR_TP3;
|
||||||
DccRx.State = WAIT_PREAMBLE ;
|
DccRx.State = WAIT_PREAMBLE ;
|
||||||
bitMax = MAX_PRAEAMBEL;
|
bitMax = MAX_PRAEAMBEL;
|
||||||
|
bitMin = MIN_ONEBITFULL;
|
||||||
DccRx.PacketCopy = DccRx.PacketBuf ;
|
DccRx.PacketCopy = DccRx.PacketBuf ;
|
||||||
DccRx.DataReady = 1 ;
|
DccRx.DataReady = 1 ;
|
||||||
SET_TP3;
|
SET_TP3;
|
||||||
@@ -407,6 +440,7 @@ void ExternalInterruptHandler(void)
|
|||||||
}
|
}
|
||||||
CLR_TP1;
|
CLR_TP1;
|
||||||
CLR_TP3;
|
CLR_TP3;
|
||||||
|
DCC_IrqRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ackCV(void)
|
void ackCV(void)
|
||||||
@@ -955,6 +989,7 @@ void NmraDcc::init( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, ui
|
|||||||
MODE_TP4;
|
MODE_TP4;
|
||||||
ISREdge = RISING;
|
ISREdge = RISING;
|
||||||
bitMax = MAX_ONEBITFULL;
|
bitMax = MAX_ONEBITFULL;
|
||||||
|
bitMin = MIN_ONEBITFULL;
|
||||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, RISING);
|
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, RISING);
|
||||||
|
|
||||||
DccProcState.Flags = Flags ;
|
DccProcState.Flags = Flags ;
|
||||||
@@ -1005,6 +1040,11 @@ uint8_t NmraDcc::getTickCount(void)
|
|||||||
return DccProcState.TickCount;
|
return DccProcState.TickCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t NmraDcc::getNestedIrqCount(void)
|
||||||
|
{
|
||||||
|
return DccProcState.NestedIrqCount;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t NmraDcc::getState(void)
|
uint8_t NmraDcc::getState(void)
|
||||||
{
|
{
|
||||||
return DccRx.State;
|
return DccRx.State;
|
||||||
|
Reference in New Issue
Block a user