From 0bab98c838437a8c9e80148284b63d94323d3b66 Mon Sep 17 00:00:00 2001 From: MicroBahner Date: Mon, 18 Jul 2016 10:57:54 +0200 Subject: [PATCH 1/2] 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 ) --- NmraDcc.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/NmraDcc.cpp b/NmraDcc.cpp index 5b479e5..f350adf 100644 --- a/NmraDcc.cpp +++ b/NmraDcc.cpp @@ -20,6 +20,7 @@ // Experimental Version to support 14 speed steps // and new signature of notifyDccSpeed and notifyDccFunc // 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----->| // DCC 1: _________XXXXXXXXX_________XXXXXXXXX_________ -// |<--------138us------>| +// |<--------146us------>| // ^-INTx ^-INTx // less than 138us: its a one-Bit // // // |<-----------------232us----------->| // DCC 0: _________XXXXXXXXXXXXXXXXXX__________________XXXXXXXX__________ -// |<--------138us------->| +// |<--------146us------->| // ^-INTx ^-INTx // greater than 138us: its a zero bit // @@ -76,8 +77,12 @@ // //------------------------------------------------------------------------ #define MAX_ONEBITFULL 146 -#define MAX_PRAEAMBEL 146 //138 +#define MAX_PRAEAMBEL 146 #define MAX_ONEBITHALF 82 +#define MIN_ONEBITFULL 82 +#define MIN_ONEBITHALF 35 +#define MAX_BITDIFF 18 + // Debug-Ports //#define debug // Testpulse for logic analyser @@ -192,7 +197,7 @@ struct countOf_t countOf; #endif static byte ISREdge; // RISING or FALLING -static word bitMax; +static word bitMax, bitMin; typedef enum { @@ -228,6 +233,7 @@ typedef struct #ifdef DCC_DEBUG uint8_t IntCount; uint8_t TickCount; + uint8_t NestedIrqCount; #endif } DCC_PROCESSOR_STATE ; @@ -240,19 +246,38 @@ void ExternalInterruptHandler(void) uint8_t DccBitVal; static int8_t bit1, bit2 ; static word lastMicros; - static byte halfBit; + static byte halfBit, DCC_IrqRunning; 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; actMicros = micros(); 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 ); lastMicros = actMicros; //#ifdef debug - if(DccBitVal) {SET_TP2} else {CLR_TP2}; + if(DccBitVal) {SET_TP2;} else {CLR_TP2;}; //#endif + DCC_IrqRunning = true; sei(); // time critical is only the micros() command,so allow nested irq's #ifdef DCC_DEBUG - DccProcState.TickCount++; + DccProcState.TickCount++; #endif switch( DccRx.State ) @@ -269,6 +294,7 @@ void ExternalInterruptHandler(void) attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, CHANGE); halfBit = 0; bitMax = MAX_ONEBITHALF; + bitMin = MIN_ONEBITHALF; CLR_TP1; } } else { @@ -299,12 +325,13 @@ void ExternalInterruptHandler(void) halfBit = 0; bit2=bitMicros; DccRx.BitCount++; - if( abs(bit2-bit1) > 14 ) { - // the length of the 2 halbits differ too much -> wrong protokoll + if( abs(bit2-bit1) > MAX_BITDIFF ) { + // the length of the 2 halfbits differ too much -> wrong protokoll CLR_TP2; CLR_TP3; DccRx.State = WAIT_PREAMBLE; bitMax = MAX_PRAEAMBEL; + bitMin = MIN_ONEBITFULL; DccRx.BitCount = 0; attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge ); SET_TP3; @@ -320,6 +347,7 @@ void ExternalInterruptHandler(void) // its a '1' halfbit -> we got only a half '0' bit -> cannot be DCC DccRx.State = WAIT_PREAMBLE; bitMax = MAX_PRAEAMBEL; + bitMin = MIN_ONEBITFULL; DccRx.BitCount = 0; } else { // we got two '0' halfbits -> it's the startbit @@ -327,6 +355,7 @@ void ExternalInterruptHandler(void) if ( ISREdge == RISING ) ISREdge = FALLING; else ISREdge = RISING; DccRx.State = WAIT_DATA ; bitMax = MAX_ONEBITFULL; + bitMin = MIN_ONEBITFULL; DccRx.PacketBuf.Size = 0; DccRx.PacketBuf.PreambleBits = 0; for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ ) @@ -345,11 +374,13 @@ void ExternalInterruptHandler(void) // second halfbit is 1 -> unknown protokoll DccRx.State = WAIT_PREAMBLE; bitMax = MAX_PRAEAMBEL; + bitMin = MIN_ONEBITFULL; DccRx.BitCount = 0; } else { // we got the startbit DccRx.State = WAIT_DATA ; bitMax = MAX_ONEBITFULL; + bitMin = MIN_ONEBITFULL; DccRx.PacketBuf.Size = 0; DccRx.PacketBuf.PreambleBits = 0; for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ ) @@ -378,6 +409,7 @@ void ExternalInterruptHandler(void) { DccRx.State = WAIT_PREAMBLE ; bitMax = MAX_PRAEAMBEL; + bitMin = MIN_ONEBITFULL; DccRx.BitCount = 0 ; } else @@ -395,6 +427,7 @@ void ExternalInterruptHandler(void) CLR_TP3; DccRx.State = WAIT_PREAMBLE ; bitMax = MAX_PRAEAMBEL; + bitMin = MIN_ONEBITFULL; DccRx.PacketCopy = DccRx.PacketBuf ; DccRx.DataReady = 1 ; SET_TP3; @@ -407,6 +440,7 @@ void ExternalInterruptHandler(void) } CLR_TP1; CLR_TP3; + DCC_IrqRunning = false; } void ackCV(void) @@ -955,6 +989,7 @@ void NmraDcc::init( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, ui MODE_TP4; ISREdge = RISING; bitMax = MAX_ONEBITFULL; + bitMin = MIN_ONEBITFULL; attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, RISING); DccProcState.Flags = Flags ; @@ -1005,6 +1040,11 @@ uint8_t NmraDcc::getTickCount(void) return DccProcState.TickCount; } +uint8_t NmraDcc::getNestedIrqCount(void) +{ + return DccProcState.NestedIrqCount; +} + uint8_t NmraDcc::getState(void) { return DccRx.State; From e0d46ff9b9819add63f3969938a1dcd756c00d69 Mon Sep 17 00:00:00 2001 From: MicroBahner Date: Mon, 18 Jul 2016 16:21:20 +0200 Subject: [PATCH 2/2] DCC_DEBUG: new function getNestedIrqCount() getNestedIrqCount() returns how often the DCC-Irq interrupted itself. This is a hint that the DCC Signal is not clean and there are glitches. --- NmraDcc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/NmraDcc.h b/NmraDcc.h index 87d83c5..7dee736 100644 --- a/NmraDcc.h +++ b/NmraDcc.h @@ -203,6 +203,7 @@ class NmraDcc uint8_t getTickCount(void); uint8_t getBitCount(void); uint8_t getState(void); + uint8_t getNestedIrqCount(void); #endif };