8 Commits
1.3.0 ... 1.4.1

Author SHA1 Message Date
Alex Shepherd
4c1d5fd6e4 changed version to 1.4.1 as a bug fix as something changed in the ESP8266 Core 2016-11-16 10:03:36 +13:00
Alex Shepherd
3a5986d10d added esp8266 to supported architectures
added addition #include file for esp8266 to resolve missing SPI_FLASH_SEC_SIZE symbol
2016-11-16 10:01:36 +13:00
Alex Shepherd
9035e55930 Added Sven to contributors and incremented the version 2016-08-20 17:46:29 +12:00
Alex Shepherd
3eee73f6cd replaced '4096' with definition SPI_FLASH_SEC_SIZE from header file 2016-08-20 17:36:47 +12:00
Sven Bursch-Osewold
d3059d2f4e ESP8266 Support 2016-08-18 19:57:47 +02:00
Alex Shepherd
0c3385b27d Merge pull request #4 from MicroBahner/master
Update DCC bit decoding
2016-07-23 19:48:42 +12:00
MicroBahner
e0d46ff9b9 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.
2016-07-18 16:21:20 +02:00
MicroBahner
0bab98c838 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 )
2016-07-18 10:57:54 +02:00
3 changed files with 100 additions and 20 deletions

View File

@@ -20,6 +20,8 @@
// 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
// 2016-08-20 added ESP8266 support by Sven (littleyoda)
//
//------------------------------------------------------------------------
//
@@ -29,7 +31,12 @@
//------------------------------------------------------------------------
#include "NmraDcc.h"
#if defined(ESP8266)
#include <EEPROM.h>
#else
#include <avr/eeprom.h>
#endif
//------------------------------------------------------------------------
// DCC Receive Routine
@@ -60,14 +67,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 +83,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 +203,7 @@ struct countOf_t countOf;
#endif
static byte ISREdge; // RISING or FALLING
static word bitMax;
static word bitMax, bitMin;
typedef enum
{
@@ -228,6 +239,7 @@ typedef struct
#ifdef DCC_DEBUG
uint8_t IntCount;
uint8_t TickCount;
uint8_t NestedIrqCount;
#endif
}
DCC_PROCESSOR_STATE ;
@@ -240,19 +252,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 +300,7 @@ void ExternalInterruptHandler(void)
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, CHANGE);
halfBit = 0;
bitMax = MAX_ONEBITHALF;
bitMin = MIN_ONEBITHALF;
CLR_TP1;
}
} else {
@@ -299,12 +331,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 +353,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 +361,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 +380,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 +415,7 @@ void ExternalInterruptHandler(void)
{
DccRx.State = WAIT_PREAMBLE ;
bitMax = MAX_PRAEAMBEL;
bitMin = MIN_ONEBITFULL;
DccRx.BitCount = 0 ;
}
else
@@ -395,6 +433,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 +446,7 @@ void ExternalInterruptHandler(void)
}
CLR_TP1;
CLR_TP3;
DCC_IrqRunning = false;
}
void ackCV(void)
@@ -415,6 +455,32 @@ void ackCV(void)
notifyCVAck() ;
}
uint8_t readEEPROM( unsigned int CV ) {
#if defined(ESP8266)
return EEPROM.read(CV) ;
#else
return eeprom_read_byte( (uint8_t*) CV );
#endif
}
void writeEEPROM( unsigned int CV, uint8_t Value ) {
#if defined(ESP8266)
EEPROM.write(CV, Value) ;
EEPROM.commit();
#else
eeprom_write_byte( (uint8_t*) CV, Value ) ;
#endif
}
bool readyEEPROM() {
#if defined(ESP8266)
return true;
#else
return eeprom_is_ready();
#endif
}
uint8_t validCV( uint16_t CV, uint8_t Writable )
{
if( notifyCVResetFactoryDefault && (CV == CV_MANUFACTURER_ID ) && Writable )
@@ -425,7 +491,7 @@ uint8_t validCV( uint16_t CV, uint8_t Writable )
uint8_t Valid = 1 ;
if( CV > E2END )
if( CV > MAXCV )
Valid = 0 ;
if( Writable && ( ( CV ==CV_VERSION_ID ) || (CV == CV_MANUFACTURER_ID ) ) )
@@ -441,8 +507,7 @@ uint8_t readCV( unsigned int CV )
if( notifyCVRead )
return notifyCVRead( CV ) ;
Value = eeprom_read_byte( (uint8_t*) CV ) ;
Value = readEEPROM(CV);
return Value ;
}
@@ -451,14 +516,14 @@ uint8_t writeCV( unsigned int CV, uint8_t Value)
if( notifyCVWrite )
return notifyCVWrite( CV, Value ) ;
if( eeprom_read_byte( (uint8_t*) CV ) != Value )
if( readEEPROM( CV ) != Value )
{
eeprom_write_byte( (uint8_t*) CV, Value ) ;
writeEEPROM( CV, Value ) ;
if( notifyCVChange )
notifyCVChange( CV, Value) ;
}
return eeprom_read_byte( (uint8_t*) CV ) ;
return readEEPROM( CV ) ;
}
uint16_t getMyAddr(void)
@@ -946,6 +1011,9 @@ void NmraDcc::initAccessoryDecoder( uint8_t ManufacturerId, uint8_t VersionId, u
void NmraDcc::init( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV )
{
#if defined(ESP8266)
EEPROM.begin(MAXCV);
#endif
// Clear all the static member variables
memset( &DccRx, 0, sizeof( DccRx) );
@@ -955,6 +1023,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 ;
@@ -990,8 +1059,7 @@ uint8_t NmraDcc::isSetCVReady(void)
{
if(notifyIsSetCVReady)
return notifyIsSetCVReady();
return eeprom_is_ready();
return readyEEPROM();
}
#ifdef DCC_DEBUG
@@ -1005,6 +1073,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;

View File

@@ -89,7 +89,13 @@ typedef struct
#define CV_VERSION_ID 7
#define CV_MANUFACTURER_ID 8
#define CV_29_CONFIG 29
#if defined(ESP8266)
#include <spi_flash.h>
#define MAXCV SPI_FLASH_SEC_SIZE
#else
#define MAXCV E2END // the upper limit of the CV value currently defined to max memory.
#endif
typedef enum {
CV29_LOCO_DIR = 0b00000001, /** bit 0: Locomotive Direction: "0" = normal, "1" = reversed */
@@ -203,6 +209,7 @@ class NmraDcc
uint8_t getTickCount(void);
uint8_t getBitCount(void);
uint8_t getState(void);
uint8_t getNestedIrqCount(void);
#endif
};

View File

@@ -1,9 +1,9 @@
name=NmraDcc
version=1.3.0
author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky, Franz-Peter Müller
version=1.4.1
author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky, Franz-Peter Müller, Sven (littleyoda)
maintainer=Alex Shepherd <kiwi64ajs@gmail.com>
sentence=Enables NMRA DCC Communication
paragraph=This library allows you to interface to a NMRA DCC track signal and receive DCC commands. The library currently supports the AVR ATTiny84/85 & ATMega88/168/328/32u4 and Teensy 3.x using the INT0/1 Hardware Interrupt and micros() ONLY and no longer uses Timer0 Compare Match B, which makes it much more portable to other platforms
category=Communication
url=http://mrrwa.org/dcc-decoder-interface/
architectures=avr
architectures=avr,esp8266