4 Commits

Author SHA1 Message Date
Alex Shepherd
4b175e9229 Merge branch 'AdvancedCVAck' into ESP32-IRAM_ATTR
* AdvancedCVAck:
  split out ServiceMode ackCV from Ops Mode AdvancedCVAck as doing a ackCV in Ops Mode is wrong and adds 6ms busy delay add cache of CV29 value
  bumped version to 2.0.2
  reverted changes around lastMicros
  added conditional compilation for ESP8266 to add ICACHE_RAM_ATTR to ExternalInterruptHandler changed storage for Micros to unsigned long
  changed the version to 201 in the header

# Conflicts:
#	NmraDcc.cpp
reverted to unsigned int
2019-08-06 01:23:12 +12:00
Franz-Peter
71bb657e3a Esp32 iram attr (#26)
* changed the version to 201 in the header

* added conditional compilation for ESP8266 to add ICACHE_RAM_ATTR to ExternalInterruptHandler
changed storage for Micros to unsigned long

* some tuning to bit recognition and nested IRQ (STM32)
2019-08-06 01:14:58 +12:00
Alex Shepherd
f3a2b87693 split out ServiceMode ackCV from Ops Mode AdvancedCVAck as doing a ackCV in Ops Mode is wrong and adds 6ms busy delay
add cache of CV29 value
2019-08-06 00:22:04 +12:00
Alex Shepherd
e06f6b3bce bumped version to 2.0.2 2019-08-05 21:34:48 +12:00
3 changed files with 62 additions and 32 deletions

View File

@@ -93,7 +93,7 @@
#define MAX_ONEBITHALF 82
#define MIN_ONEBITFULL 82
#define MIN_ONEBITHALF 35
#define MAX_BITDIFF 18
#define MAX_BITDIFF 24
// Debug-Ports
@@ -217,18 +217,12 @@
#define MODE_TP2
#define SET_TP2
#define CLR_TP2
//#define MODE_TP2 DDRC |= (1<<2) // A2
//#define SET_TP2 PORTC |= (1<<2)
//#define CLR_TP2 PORTC &= ~(1<<2)
#define MODE_TP3
#define SET_TP3
#define CLR_TP3
#define MODE_TP4
#define SET_TP4
#define CLR_TP4
//#define MODE_TP4 DDRC |= (1<<4) //A4
//#define SET_TP4 PORTC |= (1<<4)
//#define CLR_TP4 PORTC &= ~(1<<4)
#endif
#ifdef DEBUG_PRINT
@@ -295,7 +289,8 @@ typedef struct
uint8_t ExtIntNum;
uint8_t ExtIntPinNum;
int16_t myDccAddress; // Cached value of DCC Address from CVs
uint8_t inAccDecDCCAddrNextReceivedMode;
uint8_t inAccDecDCCAddrNextReceivedMode;
uint8_t cv29Value;
#ifdef DCC_DEBUG
uint8_t IntCount;
uint8_t TickCount;
@@ -342,9 +337,10 @@ void ExternalInterruptHandler(void)
// Bit evaluation without Timer 0 ------------------------------
uint8_t DccBitVal;
static int8_t bit1, bit2 ;
static word lastMicros = 0;
static unsigned int lastMicros = 0;
static byte halfBit, DCC_IrqRunning;
unsigned int actMicros, bitMicros;
#ifdef ALLOW_NESTED_IRQ
if ( DCC_IrqRunning ) {
// nested DCC IRQ - obviously there are glitches
// ignore this interrupt and increment glitchcounter
@@ -355,6 +351,7 @@ void ExternalInterruptHandler(void)
SET_TP3;
return; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> abort IRQ
}
#endif
SET_TP3;
actMicros = micros();
bitMicros = actMicros-lastMicros;
@@ -366,11 +363,12 @@ void ExternalInterruptHandler(void)
}
DccBitVal = ( bitMicros < bitMax );
lastMicros = actMicros;
#ifdef debug
if(DccBitVal) {SET_TP2;} else {CLR_TP2;};
#endif
#ifdef ALLOW_NESTED_IRQ
DCC_IrqRunning = true;
interrupts(); // time critical is only the micros() command,so allow nested irq's
#endif
#ifdef DCC_DEBUG
DccProcState.TickCount++;
#endif
@@ -431,13 +429,10 @@ void ExternalInterruptHandler(void)
DccRx.BitCount++;
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;
SET_TP4;
#if defined ( __STM32F1__ )
detachInterrupt( DccProcState.ExtIntNum );
@@ -564,6 +559,7 @@ void ExternalInterruptHandler(void)
{
CLR_TP3;
DccRx.State = WAIT_PREAMBLE ;
DccRx.BitCount = 0 ;
bitMax = MAX_PRAEAMBEL;
bitMin = MIN_ONEBITFULL;
#ifdef ESP32
@@ -593,9 +589,11 @@ void ExternalInterruptHandler(void)
DccRx.TempByte = 0 ;
}
}
#ifdef ALLOW_NESTED_IRQ
DCC_IrqRunning = false;
#endif
CLR_TP1;
CLR_TP3;
DCC_IrqRunning = false;
}
void ackCV(void)
@@ -604,6 +602,13 @@ void ackCV(void)
notifyCVAck() ;
}
void ackAdvancedCV(void)
{
if( notifyAdvancedCVAck && (DccProcState.cv29Value & CV29_ADV_ACK) )
notifyAdvancedCVAck() ;
}
uint8_t readEEPROM( unsigned int CV ) {
return EEPROM.read(CV) ;
}
@@ -663,6 +668,7 @@ uint8_t writeCV( unsigned int CV, uint8_t Value)
{
case CV_29_CONFIG:
// copy addressmode Bit to Flags
DccProcState.cv29Value = Value;
DccProcState.Flags = ( DccProcState.Flags & ~FLAGS_CV29_BITS) | (Value & FLAGS_CV29_BITS);
// no break, because myDccAdress must also be reset
case CV_ACCESSORY_DECODER_ADDRESS_LSB: // Also same CV for CV_MULTIFUNCTION_PRIMARY_ADDRESS
@@ -691,23 +697,19 @@ uint8_t writeCV( unsigned int CV, uint8_t Value)
uint16_t getMyAddr(void)
{
uint8_t CV29Value ;
if( DccProcState.myDccAddress != -1 ) // See if we can return the cached value
return( DccProcState.myDccAddress );
CV29Value = readCV( CV_29_CONFIG ) ;
if( CV29Value & CV29_ACCESSORY_DECODER ) // Accessory Decoder?
if( DccProcState.cv29Value & CV29_ACCESSORY_DECODER ) // Accessory Decoder?
{
if( CV29Value & CV29_OUTPUT_ADDRESS_MODE )
if( DccProcState.cv29Value & CV29_OUTPUT_ADDRESS_MODE )
DccProcState.myDccAddress = ( readCV( CV_ACCESSORY_DECODER_ADDRESS_MSB ) << 8 ) | readCV( CV_ACCESSORY_DECODER_ADDRESS_LSB );
else
DccProcState.myDccAddress = ( ( readCV( CV_ACCESSORY_DECODER_ADDRESS_MSB ) & 0b00000111) << 6 ) | ( readCV( CV_ACCESSORY_DECODER_ADDRESS_LSB ) & 0b00111111) ;
}
else // Multi-Function Decoder?
{
if( CV29Value & CV29_EXT_ADDRESSING ) // Two Byte Address?
if( DccProcState.cv29Value & CV29_EXT_ADDRESSING ) // Two Byte Address?
DccProcState.myDccAddress = ( ( readCV( CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB ) - 192 ) << 8 ) | readCV( CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB ) ;
else
@@ -728,7 +730,7 @@ void processDirectOpsOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value )
if( validCV( CVAddr, 1 ) )
{
if( writeCV( CVAddr, Value ) == Value )
ackCV();
ackAdvancedCV();
}
}
@@ -737,7 +739,7 @@ void processDirectOpsOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value )
if( validCV( CVAddr, 0 ) )
{
if( readCV( CVAddr ) == Value )
ackCV();
ackAdvancedCV();
}
}
}
@@ -762,7 +764,7 @@ void processDirectOpsOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value )
tempValue &= ~BitMask ; // Turn the Bit Off
if( writeCV( CVAddr, tempValue ) == tempValue )
ackCV() ;
ackAdvancedCV() ;
}
}
@@ -774,12 +776,12 @@ void processDirectOpsOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value )
if( BitValue )
{
if( tempValue & BitMask )
ackCV() ;
ackAdvancedCV() ;
}
else
{
if( !( tempValue & BitMask) )
ackCV() ;
ackAdvancedCV() ;
}
}
}
@@ -873,7 +875,7 @@ void processMultiFunctionMessage( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t
case 0b01100000:
//TODO should we cache this info in DCC_PROCESSOR_STATE.Flags ?
#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
speedSteps = (readCV( CV_29_CONFIG ) & CV29_F0_LOCATION) ? SPEED_STEP_28 : SPEED_STEP_14 ;
speedSteps = (DccProcState.cv29Value & CV29_F0_LOCATION) ? SPEED_STEP_28 : SPEED_STEP_14 ;
#else
speedSteps = SPEED_STEP_28 ;
#endif
@@ -1357,6 +1359,17 @@ 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;
// because STM32F1 has a NVIC we must set interuptpriorities
const nvic_irq_num irqNum2nvic[] = { NVIC_EXTI0, NVIC_EXTI1, NVIC_EXTI2, NVIC_EXTI3, NVIC_EXTI4,
NVIC_EXTI_9_5, NVIC_EXTI_9_5, NVIC_EXTI_9_5, NVIC_EXTI_9_5, NVIC_EXTI_9_5,
NVIC_EXTI_15_10, NVIC_EXTI_15_10, NVIC_EXTI_15_10, NVIC_EXTI_15_10, NVIC_EXTI_15_10, NVIC_EXTI_15_10 };
exti_num irqNum = (exti_num)(PIN_MAP[ExtIntPinNum].gpio_bit);
// DCC-Input IRQ must be able to interrupt other long low priority ( level15 ) IRQ's
nvic_irq_set_priority ( irqNum2nvic[irqNum], PRIO_DCC_IRQ);
// Systic must be able to interrupt DCC-IRQ to always get correct micros() values
nvic_irq_set_priority(NVIC_SYSTICK, PRIO_SYSTIC);
#else
DccProcState.ExtIntNum = ExtIntNum;
#endif
@@ -1409,7 +1422,7 @@ void NmraDcc::init( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, ui
// Set the Bits that control Multifunction or Accessory behaviour
// and if the Accessory decoder optionally handles Output Addressing
// we need to peal off the top two bits
writeCV( CV_29_CONFIG, ( readCV( CV_29_CONFIG ) & ~FLAGS_CV29_BITS ) | (Flags & FLAGS_CV29_BITS) ) ;
DccProcState.cv29Value = writeCV( CV_29_CONFIG, ( readCV( CV_29_CONFIG ) & ~FLAGS_CV29_BITS ) | (Flags & FLAGS_CV29_BITS) ) ;
uint8_t doAutoFactoryDefault = 0;
if((Flags & FLAGS_AUTO_FACTORY_DEFAULT) && (readCV(CV_VERSION_ID) == 255) && (readCV(CV_MANUFACTURER_ID) == 255))

View File

@@ -53,6 +53,8 @@
#define MAX_DCC_MESSAGE_LEN 6 // including XOR-Byte
//#define ALLOW_NESTED_IRQ // uncomment to enable nested IRQ's ( only for AVR! )
typedef struct
{
uint8_t Size ;
@@ -97,7 +99,7 @@ typedef struct
#define CV_29_CONFIG 29
#if defined(ESP32)
#include <esp_log.h>
#include <esp_spi_flash.h>
#define MAXCV SPI_FLASH_SEC_SIZE
#elif defined(ESP8266)
#include <spi_flash.h>
@@ -105,6 +107,9 @@ typedef struct
#elif defined( __STM32F1__)
#define MAXCV (EEPROM_PAGE_SIZE/4 - 1) // number of storage places (CV address could be larger
// because STM32 uses virtual adresses)
#undef ALLOW_NESTED_IRQ // This is done with NVIC on STM32
#define PRIO_DCC_IRQ 9
#define PRIO_SYSTIC 8 // MUST be higher priority than DCC Irq
#else
#define MAXCV E2END // the upper limit of the CV value currently defined to max memory.
#endif
@@ -698,6 +703,18 @@ extern void notifyCVResetFactoryDefault(void) __attribute__ ((weak));
* None
*/
extern void notifyCVAck(void) __attribute__ ((weak));
/*+
* notifyAdvancedCVAck() Called when a CV write must be acknowledged.
* This callback must increase the current drawn by this
* decoder by at least 60mA for 6ms +/- 1ms.
*
* Inputs:
* None
* *
* Returns:
* None
*/
extern void notifyAdvancedCVAck(void) __attribute__ ((weak));
/*+
* notifyServiceMode(bool) Called when state of 'inServiceMode' changes
*

View File

@@ -1,5 +1,5 @@
name=NmraDcc
version=2.0.1
version=2.0.2
author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky, Franz-Peter Müller, Sven (littleyoda), Hans Tanner
maintainer=Alex Shepherd <kiwi64ajs@gmail.com>
sentence=Enables NMRA DCC Communication