11 Commits

Author SHA1 Message Date
Alex Shepherd
828b1feaba corrected method description 2019-08-09 08:19:53 +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
Alex Shepherd
6a7e206032 reverted changes around lastMicros 2019-08-05 21:30:39 +12:00
Alex Shepherd
6d12e6cd3f added conditional compilation for ESP8266 to add ICACHE_RAM_ATTR to ExternalInterruptHandler
changed storage for Micros to unsigned long
2019-05-25 15:52:55 +12:00
Alex Shepherd
b249762550 changed the version to 201 in the header 2019-05-02 21:42:59 +12:00
Alex Shepherd
5cee0d28ed Merge branch 'master' into ESP32-IRAM_ATTR 2019-05-02 19:11:05 +12:00
Alex Shepherd
5ba1ee3e8e added another example of s simple DCC Multifunction (Locomotive) decoder 2019-05-02 11:13:22 +12:00
Franz-Peter
bb2a659ebe Esp32 processor specific (#23)
* outputaddressing corrected

declared notifyDccAccState for backward compatibility

* version define in NmraDcc.h

* DB_PRINT introduced

Changed debug printing to a macro.
Added cv29 to CV-addresses that reset caching of myAddress

* Corrections regarding Outputaddressing

OutputAddress must be a signed variable

* Changes/additions regarding output addressing and CVChange callback
Change Flag FLAGS_OUTPUT_ADDRESS_MODE accordingly, when CV29 Bit 6 (output addressing) is changed.
New callback 'notifyDccCVChange' which is NOT called if the CV is changed by means of the setCV() method

* Shorten Debug Messages

Because of Buffer overrun in the serial output. This leads to blocking
Serial.write() calls

* notifyDccSigState restored

Restore the old callback notifyDccSigState for compatibiltity to version
1.4.2

* switch off debug printing

* ESP32 specific changes

insert ESP32 specific changes reagarding the ISR by Hans Tanner
2019-02-22 08:42:34 +13:00
Alex Shepherd
865d919802 Added IRAM_ATTR changes for the ESP32 from Hans Tanner
bumped version to 2.0.1
2019-02-16 22:09:19 +13:00
Thierry Paris
ff3e24dff4 Add ESP32 support (#21)
* Update README.md

* Added ESP32 support.
2019-01-23 14:15:46 +13:00
4 changed files with 1891 additions and 1459 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -32,7 +32,7 @@
// Uncomment the following Line to Enable Service Mode CV Programming
#define NMRA_DCC_PROCESS_SERVICEMODE
// Uncomment the following line to Enable MutliFunction Decoder Operations
// Uncomment the following line to Enable MultiFunction Decoder Operations
#define NMRA_DCC_PROCESS_MULTIFUNCTION
// Uncomment the following line to Enable 14 Speed Step Support
@@ -49,7 +49,7 @@
#ifndef NMRADCC_IS_IN
#define NMRADCC_IS_IN
#define NMRADCC_VERSION 200 // Version 2.0.0
#define NMRADCC_VERSION 201 // Version 2.0.1
#define MAX_DCC_MESSAGE_LEN 6 // including XOR-Byte
@@ -96,14 +96,17 @@ typedef struct
#define CV_MANUFACTURER_ID 8
#define CV_29_CONFIG 29
#if defined(ESP8266)
#include <spi_flash.h>
#define MAXCV SPI_FLASH_SEC_SIZE
#if defined(ESP32)
#include <esp_spi_flash.h>
#define MAXCV SPI_FLASH_SEC_SIZE
#elif defined(ESP8266)
#include <spi_flash.h>
#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
#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 {
@@ -651,7 +654,7 @@ extern uint8_t notifyIsSetCVReady(void) __attribute__ ((weak));
* notifyCVChange() Called when a CV value is changed.
* This is called whenever a CV's value is changed.
* notifyDccCVChange() Called only when a CV value is changed by a Dcc packet or a internal lib function.
* it is NOT called if the CV is chaged by means of the setCV() method.
* it is NOT called if the CV is changed by means of the setCV() method.
* Note: It is not called if notifyCVWrite() is defined
* or if the value in the EEPROM is the same as the value
* in the write command.
@@ -695,6 +698,17 @@ extern void notifyCVResetFactoryDefault(void) __attribute__ ((weak));
* None
*/
extern void notifyCVAck(void) __attribute__ ((weak));
/*+
* notifyAdvancedCVAck() Called when a CV write must be acknowledged via Advanced Acknowledgement.
* This callback must send the Advanced Acknowledgement via RailComm.
*
* Inputs:
* None
* *
* Returns:
* None
*/
extern void notifyAdvancedCVAck(void) __attribute__ ((weak));
/*+
* notifyServiceMode(bool) Called when state of 'inServiceMode' changes
*

View File

@@ -0,0 +1,314 @@
// NMRA Dcc Multifunction Motor Decoder Demo
//
// Author: Alex Shepherd 2019-03-30
//
// This example requires these Arduino Libraries:
//
// 1) The NmraDcc Library from: http://mrrwa.org/download/
//
// These libraries can be found and installed via the Arduino IDE Library Manager
//
// This is a simple demo of how to drive and motor speed and direction using PWM and a motor H-Bridge
// It uses vStart and vHigh CV values to customise the PWM values to the motor response
// It also uses the Headling Function to drive 2 LEDs for Directional Headlights
// Apart from that there's nothing fancy like Lighting Effects or a function matrix or Speed Tables - its just the basics...
//
#include <NmraDcc.h>
// Uncomment any of the lines below to enable debug messages for different parts of the code
//#define DEBUG_FUNCTIONS
//#define DEBUG_SPEED
//#define DEBUG_PWM
//#define DEBUG_DCC_ACK
//#define DEBUG_DCC_MSG
#if defined(DEBUG_FUNCTIONS) or defined(DEBUG_SPEED) or defined(DEBUG_PWM) or defined(DEBUG_DCC_ACK) or defined(DEBUG_DCC_MSG)
#define DEBUG_PRINT
#endif
// This is the default DCC Address
#define DEFAULT_DECODER_ADDRESS 3
// This section defines the Arduino UNO Pins to use
#ifdef __AVR_ATmega328P__
#define DCC_PIN 2
#define LED_PIN_FWD 5
#define LED_PIN_REV 6
#define MOTOR_DIR_PIN 12
#define MOTOR_PWM_PIN 3
// This section defines the Arduino ATTiny85 Pins to use
#elif ARDUINO_AVR_ATTINYX5
#define DCC_PIN 2
#define LED_PIN_FWD 0
#define LED_PIN_REV 1
#define MOTOR_DIR_PIN 3
#define MOTOR_PWM_PIN 4
#else
#error "Unsupported CPU, you need to add another configuration section for your CPU"
#endif
// Some global state variables
uint8_t newLedState = 0;
uint8_t lastLedState = 0;
uint8_t newDirection = 0;
uint8_t lastDirection = 0;
uint8_t newSpeed = 0;
uint8_t lastSpeed = 0;
uint8_t numSpeedSteps = SPEED_STEP_128;
uint8_t vStart;
uint8_t vHigh;
// Structure for CV Values Table
struct CVPair
{
uint16_t CV;
uint8_t Value;
};
// CV Addresses we will be using
#define CV_VSTART 2
#define CV_VHIGH 5
// Default CV Values Table
CVPair FactoryDefaultCVs [] =
{
// The CV Below defines the Short DCC Address
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, DEFAULT_DECODER_ADDRESS},
// Three Step Speed Table
{CV_VSTART, 120},
{CV_VHIGH, 255},
// These two CVs define the Long DCC Address
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, DEFAULT_DECODER_ADDRESS},
// ONLY uncomment 1 CV_29_CONFIG line below as approprate
// {CV_29_CONFIG, 0}, // Short Address 14 Speed Steps
{CV_29_CONFIG, CV29_F0_LOCATION}, // Short Address 28/128 Speed Steps
// {CV_29_CONFIG, CV29_EXT_ADDRESSING | CV29_F0_LOCATION}, // Long Address 28/128 Speed Steps
};
NmraDcc Dcc ;
uint8_t FactoryDefaultCVIndex = 0;
// This call-back function is called when a CV Value changes so we can update CVs we're using
void notifyCVChange( uint16_t CV, uint8_t Value)
{
switch(CV)
{
case CV_VSTART:
vStart = Value;
break;
case CV_VHIGH:
vHigh = Value;
break;
}
}
void notifyCVResetFactoryDefault()
{
// Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset
// to flag to the loop() function that a reset to Factory Defaults needs to be done
FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
};
// This call-back function is called whenever we receive a DCC Speed packet for our address
void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps )
{
#ifdef DEBUG_SPEED
Serial.print("notifyDccSpeed: Addr: ");
Serial.print(Addr,DEC);
Serial.print( (AddrType == DCC_ADDR_SHORT) ? "-S" : "-L" );
Serial.print(" Speed: ");
Serial.print(Speed,DEC);
Serial.print(" Steps: ");
Serial.print(SpeedSteps,DEC);
Serial.print(" Dir: ");
Serial.println( (Dir == DCC_DIR_FWD) ? "Forward" : "Reverse" );
#endif
newDirection = Dir;
newSpeed = Speed;
numSpeedSteps = SpeedSteps;
};
// This call-back function is called whenever we receive a DCC Function packet for our address
void notifyDccFunc(uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState)
{
#ifdef DEBUG_FUNCTIONS
Serial.print("notifyDccFunc: Addr: ");
Serial.print(Addr,DEC);
Serial.print( (AddrType == DCC_ADDR_SHORT) ? 'S' : 'L' );
Serial.print(" Function Group: ");
Serial.print(FuncGrp,DEC);
#endif
if(FuncGrp == FN_0_4)
{
newLedState = (FuncState & FN_BIT_00) ? 1 : 0;
#ifdef DEBUG_FUNCTIONS
Serial.print(" FN 0: ");
Serial.print(newLedState);
#endif
}
#ifdef DEBUG_FUNCTIONS
Serial.println();
#endif
}
// This call-back function is called whenever we receive a DCC Packet
#ifdef DEBUG_DCC_MSG
void notifyDccMsg( DCC_MSG * Msg)
{
Serial.print("notifyDccMsg: ") ;
for(uint8_t i = 0; i < Msg->Size; i++)
{
Serial.print(Msg->Data[i], HEX);
Serial.write(' ');
}
Serial.println();
}
#endif
// This call-back function is called by the NmraDcc library when a DCC ACK needs to be sent
// Calling this function should cause an increased 60ma current drain on the power supply for 6ms to ACK a CV Read
// So we will just turn the motor on for 8ms and then turn it off again.
void notifyCVAck(void)
{
#ifdef DEBUG_DCC_ACK
Serial.println("notifyCVAck") ;
#endif
digitalWrite(MOTOR_DIR_PIN, HIGH);
digitalWrite(MOTOR_PWM_PIN, HIGH);
delay( 8 );
digitalWrite(MOTOR_DIR_PIN, LOW);
digitalWrite(MOTOR_PWM_PIN, LOW);
}
void setup()
{
#ifdef DEBUG_PRINT
Serial.begin(115200);
Serial.println("NMRA Dcc Multifunction Motor Decoder Demo");
#endif
// Setup the Pins for the Fwd/Rev LED for Function 0 Headlight
pinMode(LED_PIN_FWD, OUTPUT);
pinMode(LED_PIN_REV, OUTPUT);
// Setup the Pins for the Motor H-Bridge Driver
pinMode(MOTOR_DIR_PIN, OUTPUT);
pinMode(MOTOR_PWM_PIN, OUTPUT);
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
Dcc.pin(DCC_PIN, 0);
Dcc.init( MAN_ID_DIY, 10, FLAGS_MY_ADDRESS_ONLY | FLAGS_AUTO_FACTORY_DEFAULT, 0 );
// Uncomment to force CV Reset to Factory Defaults
// notifyCVResetFactoryDefault();
// Read the current CV values for vStart and vHigh
vStart = Dcc.getCV(CV_VSTART);
vHigh = Dcc.getCV(CV_VHIGH);
}
void loop()
{
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
Dcc.process();
// Handle Speed changes
if(lastSpeed != newSpeed)
{
lastSpeed = newSpeed;
// Stop if speed = 0 or 1
if(newSpeed <= 1)
digitalWrite(MOTOR_PWM_PIN, LOW);
// Calculate PWM value in the range 1..255
else
{
uint8_t vScaleFactor;
if((vHigh > 1) && (vHigh > vStart))
vScaleFactor = vHigh - vStart;
else
vScaleFactor = 255 - vStart;
uint8_t modSpeed = newSpeed - 1;
uint8_t modSteps = numSpeedSteps - 1;
uint8_t newPwm = (uint8_t) vStart + modSpeed * vScaleFactor / modSteps;
#ifdef DEBUG_PWM
Serial.print("New Speed: vStart: ");
Serial.print(vStart);
Serial.print(" vHigh: ");
Serial.print(vHigh);
Serial.print(" modSpeed: ");
Serial.print(modSpeed);
Serial.print(" vScaleFactor: ");
Serial.print(vScaleFactor);
Serial.print(" modSteps: ");
Serial.print(modSteps);
Serial.print(" newPwm: ");
Serial.println(newPwm);
#endif
analogWrite(MOTOR_PWM_PIN, newPwm);
}
}
// Handle Direction and Headlight changes
if((lastDirection != newDirection) || (lastLedState != newLedState))
{
lastDirection = newDirection;
lastLedState = newLedState;
digitalWrite(MOTOR_DIR_PIN, newDirection);
if(newLedState)
{
#ifdef DEBUG_FUNCTIONS
Serial.println("LED On");
#endif
digitalWrite(LED_PIN_FWD, newDirection ? LOW : HIGH);
digitalWrite(LED_PIN_REV, newDirection ? HIGH : LOW);
}
else
{
#ifdef DEBUG_FUNCTIONS
Serial.println("LED Off");
#endif
digitalWrite(LED_PIN_FWD, LOW);
digitalWrite(LED_PIN_REV, LOW);
}
}
// Handle resetting CVs back to Factory Defaults
if( FactoryDefaultCVIndex && Dcc.isSetCVReady())
{
FactoryDefaultCVIndex--; // Decrement first as initially it is the size of the array
Dcc.setCV( FactoryDefaultCVs[FactoryDefaultCVIndex].CV, FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
}
}

View File

@@ -1,6 +1,6 @@
name=NmraDcc
version=2.0.0
author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky, Franz-Peter Müller, Sven (littleyoda)
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
paragraph=This library allows you to interface to a NMRA DCC track signal and receive DCC commands. The library has been tested on AVR ATTiny84/85 & ATMega88/168/328/32u4, ESP8266 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.