diff --git a/NmraDcc.cpp b/NmraDcc.cpp index dfb9420..51920c0 100644 --- a/NmraDcc.cpp +++ b/NmraDcc.cpp @@ -21,7 +21,8 @@ // 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) +// 2016-08-20 added ESP8266 support by Sven (littleyoda) +// 2017-01-19 added STM32F1 support by Franz-Peter // //------------------------------------------------------------------------ // @@ -32,12 +33,6 @@ #include "NmraDcc.h" -#if defined(ESP8266) - #include -#else -#include -#endif - //------------------------------------------------------------------------ // DCC Receive Routine // @@ -146,20 +141,34 @@ #define MODE_TP4 pinMode( A4,OUTPUT ) // A4 = PortB Bit3 #define SET_TP4 GPIOB_PSOR = 0x08 #define CLR_TP4 GPIOB_PCOR = 0x08 - #elif defined (__SAM3X8E__) - // Arduino Due - #define MODE_TP1 pinMode( A1,OUTPUT ) // A1= PA24 - #define SET_TP1 REG_PIOA_SODR = (1<<24) - #define CLR_TP1 REG_PIOA_CODR = (1<<24) - #define MODE_TP2 pinMode( A2,OUTPUT ) // A2= PA23 - #define SET_TP2 REG_PIOA_SODR = (1<<23) - #define CLR_TP2 REG_PIOA_CODR = (1<<23) - #define MODE_TP3 pinMode( A3,OUTPUT ) // A3 = PA22 - #define SET_TP3 REG_PIOA_SODR = (1<<22) - #define CLR_TP3 REG_PIOA_CODR = (1<<22) - #define MODE_TP4 pinMode( A4,OUTPUT ) // A4 = PA6 - #define SET_TP4 REG_PIOA_SODR = (1<<6) - #define CLR_TP4 REG_PIOA_CODR = (1<<6) + #elif defined (__STM32F1__) + // STM32F103... + #define MODE_TP1 pinMode( PB12,OUTPUT ) // TP1= PB12 + #define SET_TP1 gpio_write_bit( GPIOB,12, HIGH ); + #define CLR_TP1 gpio_write_bit( GPIOB,12, LOW ); + #define MODE_TP2 pinMode( PB13,OUTPUT ) // TP2= PB13 + #define SET_TP2 gpio_write_bit( GPIOB,13, HIGH ); + #define CLR_TP2 gpio_write_bit( GPIOB,13, LOW ); + #define MODE_TP3 pinMode( PB14,OUTPUT ) // TP3 = PB14 + #define SET_TP3 gpio_write_bit( GPIOB,14, HIGH ); + #define CLR_TP3 gpio_write_bit( GPIOB,14, LOW ); + #define MODE_TP4 pinMode( PB15,OUTPUT ) // TP4 = PB15 + #define SET_TP4 gpio_write_bit( GPIOB,15, HIGH ); + #define CLR_TP4 gpio_write_bit( GPIOB,15, LOW ); + #elif defined(ESP8266) + #define MODE_TP1 pinMode( D5,OUTPUT ) ; // GPIO 14 + #define SET_TP1 GPOS = (1 << D5); + #define CLR_TP1 GPOC = (1 << D5); + #define MODE_TP2 pinMode( D6,OUTPUT ) ; // GPIO 12 + #define SET_TP2 GPOS = (1 << D6); + #define CLR_TP2 GPOC = (1 << D6); + #define MODE_TP3 pinMode( D7,OUTPUT ) ; // GPIO 13 + #define SET_TP3 GPOS = (1 << D7); + #define CLR_TP3 GPOC = (1 << D7); + #define MODE_TP4 pinMode( D7,OUTPUT ); // GPIO 15 + #define SET_TP4 GPOC = (1 << D8); + #define CLR_TP4 GPOC = (1 << D8); + //#elif defined(__AVR_ATmega128__) ||defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__) #else @@ -202,7 +211,11 @@ struct countOf_t countOf; #endif +#if defined ( __STM32F1__ ) +static ExtIntTriggerMode ISREdge; +#else static byte ISREdge; // RISING or FALLING +#endif static word bitMax, bitMin; typedef enum @@ -270,9 +283,7 @@ void ExternalInterruptHandler(void) if ( bitMicros < bitMin ) { // too short - my be false interrupt due to glitch or false protocol -> ignore CLR_TP3; - SET_TP4; - SET_TP4; - CLR_TP4; + SET_TP4; CLR_TP4; return; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> abort IRQ } DccBitVal = ( bitMicros < bitMax ); @@ -281,7 +292,7 @@ void ExternalInterruptHandler(void) if(DccBitVal) {SET_TP2;} else {CLR_TP2;}; //#endif DCC_IrqRunning = true; - sei(); // time critical is only the micros() command,so allow nested irq's + interrupts(); // time critical is only the micros() command,so allow nested irq's #ifdef DCC_DEBUG DccProcState.TickCount++; #endif @@ -297,6 +308,9 @@ void ExternalInterruptHandler(void) DccRx.State = WAIT_START_BIT ; // While waiting for the start bit, detect halfbit lengths. We will detect the correct // sync and detect whether we see a false (e.g. motorola) protocol + #if defined ( __STM32F1__ ) + detachInterrupt( DccProcState.ExtIntNum ); + #endif attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, CHANGE); halfBit = 0; bitMax = MAX_ONEBITHALF; @@ -321,12 +335,13 @@ void ExternalInterruptHandler(void) bit1=bitMicros; } else { // was "0" half bit, maybe the startbit + SET_TP1; halfBit = 4; + CLR_TP1; } break; case 1: //SET_TP1; // previous halfbit was '1' if ( DccBitVal ) { - CLR_TP1; // its a '1' halfBit -> we are still in the preamble halfBit = 0; bit2=bitMicros; @@ -339,13 +354,20 @@ void ExternalInterruptHandler(void) bitMax = MAX_PRAEAMBEL; bitMin = MIN_ONEBITFULL; DccRx.BitCount = 0; + SET_TP4; + #if defined ( __STM32F1__ ) + detachInterrupt( DccProcState.ExtIntNum ); + #endif attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge ); - SET_TP3; + SET_TP3; + CLR_TP4; } } else { // first '0' half detected in second halfBit // wrong sync or not a DCC protokoll + CLR_TP3; halfBit = 3; + SET_TP3; } break; case 3: //SET_TP1; // previous halfbit was '0' in second halfbit @@ -371,8 +393,13 @@ void ExternalInterruptHandler(void) DccRx.BitCount = 0 ; DccRx.TempByte = 0 ; } - attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge ); + SET_TP4; + #if defined ( __STM32F1__ ) + detachInterrupt( DccProcState.ExtIntNum ); + #endif + attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge ); CLR_TP1; + CLR_TP4; break; case 4: SET_TP1; // previous (first) halfbit was 0 // if this halfbit is 0 too, we got the startbit @@ -396,8 +423,14 @@ void ExternalInterruptHandler(void) DccRx.BitCount = 0 ; DccRx.TempByte = 0 ; } - attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge ); + CLR_TP1; + SET_TP4; + #if defined ( __STM32F1__ ) + detachInterrupt( DccProcState.ExtIntNum ); + #endif + attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge ); + CLR_TP4; break; } @@ -456,28 +489,18 @@ void ackCV(void) } 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) ; + #if defined(ESP8266) EEPROM.commit(); - #else - eeprom_write_byte( (uint8_t*) CV, Value ) ; #endif } bool readyEEPROM() { - #if defined(ESP8266) return true; - #else - return eeprom_is_ready(); - #endif } @@ -996,7 +1019,12 @@ NmraDcc::NmraDcc() void NmraDcc::pin( uint8_t ExtIntNum, uint8_t ExtIntPinNum, uint8_t EnablePullup) { +#if defined ( __STM32F1__ ) + // with STM32F1 the interuptnumber is equal the pin number + DccProcState.ExtIntNum = ExtIntPinNum; +#else DccProcState.ExtIntNum = ExtIntNum; +#endif DccProcState.ExtIntPinNum = ExtIntPinNum; pinMode( ExtIntPinNum, INPUT ); @@ -1103,10 +1131,10 @@ uint8_t NmraDcc::process() { // We need to do this check with interrupts disabled //SET_TP4; - cli(); + noInterrupts(); Msg = DccRx.PacketCopy ; DccRx.DataReady = 0 ; - sei(); + interrupts(); #ifdef DCC_DBGVAR countOf.Tel++; #endif @@ -1115,20 +1143,15 @@ uint8_t NmraDcc::process() for(uint8_t i = 0; i < DccRx.PacketCopy.Size; i++) xorValue ^= DccRx.PacketCopy.Data[i]; - //CLR_TP4; if(xorValue) { - SET_TP4; #ifdef DCC_DBGVAR countOf.Err++; #endif - CLR_TP4; return 0 ; } else { - //SET_TP4; if( notifyDccMsg ) notifyDccMsg( &Msg ); execDccProcessor( &Msg ); - //CLR_TP4; } return 1 ; } diff --git a/NmraDcc.h b/NmraDcc.h index 3e1fbaa..a97ad0e 100644 --- a/NmraDcc.h +++ b/NmraDcc.h @@ -42,6 +42,8 @@ #include "WProgram.h" #endif +#include "EEPROM.h" + #ifndef NMRADCC_IS_IN #define NMRADCC_IS_IN @@ -93,8 +95,11 @@ typedef struct #if defined(ESP8266) #include #define MAXCV SPI_FLASH_SEC_SIZE +#elif defined( __STM32F1__) +#define MAXCV (EEPROM_PAGE_SIZE/4 - 1) // number of storage places (CV address could be larger + // because STM32 uses virtual adresses) #else -#define MAXCV E2END // the upper limit of the CV value currently defined to max memory. +#define MAXCV E2END // the upper limit of the CV value currently defined to max memory. #endif typedef enum { diff --git a/library.properties b/library.properties index 2d702bb..6019e10 100644 --- a/library.properties +++ b/library.properties @@ -6,4 +6,4 @@ 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,esp8266 \ No newline at end of file +architectures=avr,esp8266,STM32F1