mrrwa / nmradcc Goto Github PK
View Code? Open in Web Editor NEWNMRA Digital Command Control (DCC) Library
License: GNU Lesser General Public License v2.1
NMRA Digital Command Control (DCC) Library
License: GNU Lesser General Public License v2.1
I'm trying to use an Adafruit Metro M0 (ARM Cortex M0 SAMD21blah based), and this device's Arduino library does not provide the EEPROM interface.
I've noodled up a generic CV database interface, and written one implementation that uses EEPROM and another that uses a file within the local filesystem (since I've got more than just N NMRA DCC CVs to store for my persistence needs).
My first plan was to set this up as a required reference argument to the NmraDcc constructor, and then use the generic interfaces within the NmraDcc code. This could probably even be done without a user sketch code change, where the NmraDcc() constructor would create an EEPROM object, and the NmraDccc(NmraCVDB &) constructor would allow the user to provide their own.
However, in putting the pieces together, I find that parts of the NmraDcc module are member functions within the object, and other parts are just standalone functions (which don't have access to the object internals).
Is there a fundamental reason for this separation of code between methods and functions?
Would you be interested in changes that move the "external" functions inside of the NmraDcc class, which would also permit the "externalization" of the EEPROM interface?
Alternately, I could try to rig this up using a separate standalone CV DB class, but that's doing even more to limit this code to only ever supporting a single DCC interface (which I think is already the case). And I think these changes would do more to break all existing code (or more specifically, require additions to existing sketches to add the declaration of the EEPROM (or other) based CV DB object.
I have a very big interest in this example. My hardware is a bit different though. I have my dcc interface going to my arduino uno, along with a TB6600 stepper motor driver. When I load the sketch for this, and open the serial monitor. I can see that the arduino is getting the dcc responses. However mo stepper is not moving. I can feel that it's on. It just doesnt move. Ideas?
For my project, I want to receive DDCFunc, DDCSpeed and DDCTurnout.
Depending on the Parameter for the Constructor, I got DCCFunc and DDCSpeed or just DDCTurnout.
But I wasn't able to receive all three information. Is there an way to accomplish this?
Have used the library somewhat on and off for experiments.
Added functions, fixed some things, debugged others. Nothing major.
Want to know if you guys/gals need any help with the code? or if there is any way I can help.
Hi. i'm using the NmraDCC lib. on an Attiny85 (tried several different Attiny85 boards), to control 2 relays as a reverse loop module. I'm using the turnout function of the NmraDCC lib. and it works flawlessly for like an hour, where after the module stops responding to the DCC commands (it may stop all commands / codehandling im not sure). A powercycle of the Attiny85, solves the problem, again for some time. As a quick powercycle helps, I don't think it's a heat issue. As mentioned I have tried several types om presoldered/preassembled Attiny85 boards and the result is the same. Has any of You experienced anything similar ? Is there a way of maybe resetting the Attiny85 codewise like every 30 min, or maybe every time the relays have been switched off ? (i know this is not elegant).
I think the Attiny85 has a perfect formfactor and handling cap. for a reverse loop module, so would really like to stay on this small platform.
I developed NMRADCC based on EPS32 and added NMRADCC in Platfromio (version:2.0.15) library, but during compilation, it was discovered that the EEPROM library could not be found.
I found a lot of EEPROM related libraries in the PlatformIO library manager, and I 'm not sure which one to choose.
Verbose mode can be enabled via -v, --verbose
option
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/denky_d4.html
PLATFORM: Espressif 32 (4.1.0) > Denky D4 (PICO-V3-02)
HARDWARE: ESP32 240MHz, 320KB RAM, 8MB Flash
DEBUG: Current (esp-prog) External (esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
PACKAGES:
#include "EEPROM.h"
^~~~~~~~~~
compilation terminated.
*** [.pio\build\denky_d4\lib2a9\NmraDcc\NmraDcc.cpp.o] Error 1
Is the library compatible/works correctly with chinese clone of AtMega - LGT8F328P?
Hi
testing my framework for a esp8266, I found three problems in ExternalInterruptHandler.
Because I'm not sure how to fix the problems platform independent, I have not created a Pull Request.
=>
ICACHE_RAM_ATTR void ExternalInterruptHandler(void)
static word lastMicros;
unsigned int actMicros, bitMicros;
=>
static unsigned long lastMicros = 0;
unsigned long actMicros, bitMicros;
Hello,
if I try to compile a sketch (e.g. one of the examples delivered with the lib) using the current release of the NmraDcc lib I get the following error message in the Arduino IDE:
Arduino: 1.6.12 (Windows 7), Board: "NodeMCU 1.0 (ESP-12E Module), 80 MHz, 921600, 4M (3M SPIFFS)"
In file included from C:\Users\x\Documents\Arduino\libraries\NmraDcc\NmraDcc.cpp:33:0:
C:\Users\x\Documents\Arduino\libraries\NmraDcc\NmraDcc.cpp: In function 'uint8_t validCV(uint16_t, uint8_t)':
C:\Users\x\Documents\Arduino\libraries\NmraDcc\NmraDcc.h:94:21: error: 'SPI_FLASH_SEC_SIZE' was not declared in this scope
#define MAXCV SPI_FLASH_SEC_SIZE
^
C:\Users\x\Documents\Arduino\libraries\NmraDcc\NmraDcc.cpp:494:12: note: in expansion of macro 'MAXCV'
if( CV > MAXCV )
^
C:\Users\x\Documents\Arduino\libraries\NmraDcc\NmraDcc.cpp: In member function 'void NmraDcc::init(uint8_t, uint8_t, uint8_t, uint8_t)':
C:\Users\x\Documents\Arduino\libraries\NmraDcc\NmraDcc.h:94:21: error: 'SPI_FLASH_SEC_SIZE' was not declared in this scope
#define MAXCV SPI_FLASH_SEC_SIZE
^
C:\Users\x\Documents\Arduino\libraries\NmraDcc\NmraDcc.cpp:1015:18: note: in expansion of macro 'MAXCV'
EEPROM.begin(MAXCV);
^
exit status 1
Should this be defined somewhere in the nmradcc.cpp or nmradcc.h file? Or am I missing something else?
Thanks for any help
I use ESP32 as the decoder. IDF architecture +Arduino components. DCC++ EX for command station, and UART serial port for command input monitoring.
I plugged the decoder into the PROG track and tried to respond to the ACK using the motor drive (motor works fine)
` void notifyCVAck(void)
{ ESP_LOGI(LOGTAG_DCC, "notifyCVAck");
MOTOR_Ack();
}
void MOTOR_Ack(void)
{
ledcWrite(MOTOR_PWM_CH_B, 0);
ledcWrite(MOTOR_PWM_CH_A, 240); vTaskDelay(6 / portTICK_PERIOD_MS);
ledcWrite(MOTOR_PWM_CH_A, 0);
}
`
No response, no output from ESP_LOG
I tried to read the DCC package again:
`void notifyDccMsg(DCC_MSG *Msg)
{
ESP_LOG_BUFFER_HEXDUMP("DCC_MSG",Msg->Data,Msg->Size,ESP_LOG_INFO);
}
`
Power on PROG (EX command<1>), with result:
I (165159) DCC_MSG: 0x3ffb2e22 ff 00 ff |...| I (165169) DCC_MSG: 0x3ffb2e22 ff 00 ff |...| I (165179) DCC_MSG: 0x3ffb2e22 ff 00 ff |...| I (165189) DCC_MSG: 0x3ffb2e22 ff 00 ff |...| I (165199) DCC_MSG: 0x3ffb2e22 ff 00 ff |...|
Feel like NMRA DCC can receive DCC signal, but can't process it, or am I wrong? Please advise.
Enabling pullup for ExtIntPin fails with ESP32.
Seems that old way to enable pullup by writing a 1 to the port doesn't work with ESP.
Changed code from
pinMode( ExtIntPinNum, INPUT );
if( EnablePullup )
digitalWrite(ExtIntPinNum, HIGH);
to
pinMode( ExtIntPinNum, EnablePullup ? INPUT_PULLUP : INPUT );
then it works.
Hi Alex,
I open a new issue, so we can discuss the acknowledgement problem here separately.
As I wrote already, with the actual version of 'master' reading of CV values in servicemode is no longer possible.
Some further thoughts to RailCom - as it is defined in NMRA S-9.3.2.
RailCom is a really big extension to standard DCC. It is far more than an 'advanced acknowledge'.
Bit 3 in CV29 should be named as what it really is: CV29_RailCom_ENABLE . If this bit is set in CV29 the decoder must conform to NMRA S-9.3.2 . I don't think you can build such a decoder with the lib so far. I am even not sure if it is possible with an AVR UNO/Nano at all. The timing in the RailCom cutout ist quite critical. In my opinion you need a free HW UART and maybe a HW Timer too. We should inhibit setting this bit.
With a standard Decoder (without RailCom) and programming in ops mode (POM) there is no acknowledgement at all. Programming in system mode requires the 6ms current pulse as acknowlegement. The most easiest way to accomplish this is to call notifyCVAck() only if we are in servicemode. I implemented this in my fork of the lib and can make a pull request if you agree with this solution.
Hello,
I'm trying to run this library on ESP8266 which is stated to be compatible, but I get errors.
I've hooked up the DCC signal on D3 pin and uploaded the example "NmraDccMultiFunctionDecoder_1", after changing DCC_PIN to D3.
The sketch is working, I see the speed and function changes displayed in the serial monitor, but as soon as I try to send a write CV from the MultiMaus, I get an exception : " ets Jan 8 2013,rst cause:2, boot mode:(3,6)".
Then I tried "NmraDccMultiFunctionMotorDecoder" example, uncommented the DEBUG defines and defined the DCC_PIN to D3 (and LED and MOTOR pins even if nothing is hooked up on the physical pins).
Uploaded this sketch and I constantly get wdt reset errors in the serial monitor followed by the line "NMRA Dcc Multifunction Motor Decoder Demo" :
ets Jan 8 2013,rst cause:4, boot mode:(3,6)
wdt reset
load 0x4010f000, len 3584, room 16
tail 0
chksum 0xb0
csum 0xb0
v2843a5ac
~ld
NMRA Dcc Multifunction Motor Decoder Demo
This error shows even when DCC signal is turned off.
Can someone point me out why this happens?
Hi,
I'm building my own signal (as in railway signal) decoder using your library. For this to work correctly, I need to persist the signal state to EEPROM, so that signals still show the same value after a reboot.
Hence, I have two questions:
Thanks!
Hello,
i have the problem that in my project the notifyDccSpeed callback never gets raised.
Further the decoder doesn#t set its address correctly. I did help out with Flag FLAGS_AUTO_FACTORY_DEFAULT. But if I don't set this flag, any random value will be returned from CV 1.
Can anyone help me?
My project is hosted here: https://github.com/christianloesel/Messwagen-NMRADCC/tree/master/Neigungsmesswagen
Thanks
According to the Arduino IDE, when installing NmraDcc, the package supports ESP8266. Now trying to run on an ESP8266, Lolin Wemos D1R2, we fail to get any DCC messages decoded. The program and shield works fine on an UNO. Can you assist?
There an error is in NmraDccMultiFunctionMotorDecoder, lines 295-296
It should be
digitalWrite(LED_PIN_FWD, newDirection ? HIGH : LOW);
digitalWrite(LED_PIN_REV, newDirection ? LOW : HIGH);
instead of
digitalWrite(LED_PIN_FWD, newDirection ? LOW : HIGH);
digitalWrite(LED_PIN_REV, newDirection ? HIGH : LOW);
Forward corresponds to newDirection == HIGH.
Hello. What is the difference between the two branches? Can you tell me how you are doing the ACK? What function is creating a current draw or is it only for Railcom where some piece of hardware does this? A standard Arduino had no ability to generate a 60mA pulse that I know of so for a decoder not attached to other hardware, have you thought of a way to send an ACK?
Dear all,
I very much appreciate your work. This also why I took your driver and ported it in the NodeMCU Lua a Lua based interactive firmware for ESP8266, ESP8285 and ESP32. It has been merged already in the dev
branch of the project. It works very well and I'm glad I can play with NMRA DCC in Lua.
However one of the senior developpers has recently raised an issue (#3025) pointing out that your code is distributed under GPL license. The NodeMCU Lua project is distributed under MIT license which I understand is a bit wider. Including GPL code would require the project to be under GPL which not something that is on the table.
Therefore I would like to ask you to consider relicensing your great project under MIT license ๐. It would allow spreading it further into the world ๐.
Thank you. Best regads,
After successfully running the Accessory test program that is part of the library I started using the code in a larger program. It started crashing as soon as the DCC signal was present, which pointed my look closer into the ISR.
In the process I think I have discovered some problems with the ISR:
a) for ESP32, it should be compiled with the IRAM_ATTR attribute like this: void IRAM_ATTR ExternalInterruptHandler(void)
For more information see here: https://techtutorialsx.com/2017/09/30/esp32-arduino-external-interrupts/
and here: espressif/arduino-esp32#489
b) I also added the MUX line: portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; and secured the access to the shard data in the ISR and the process routing:
portENTER_CRITICAL_ISR(&mux); DccRx.PacketCopy = DccRx.PacketBuf ; DccRx.DataReady = 1 ; portEXIT_CRITICAL_ISR(&mux);
Unfortunately, while all this is good, it was still crashing as soon as my program tried to access the file system (SPIFFS), eg. for loading config files or a serving a web page.
c) It turns out the real problem is the reattachment of interrupts within the IRS. As soon as I commented those lines out, the program stopped crashing, but unfortunately, it would no longer decode the DCC signals. So I found a workaround and defined a variable ISRWatch which holds the type of interrupt to look for, either falling, raising, or change. Then I replaced all attach interrupt functions by just changing the content of the ISRWatch variable and changed the attacheinterrupt call in the init function to CHANGE. Finally, I added a filter to the beginning of the ISR where I would check the type of interrupt and either return or proceed:
void IRAM_ATTR ExternalInterruptHandler(void)
{
switch (ISRWatch)
{
case CHANGE: break;
case RISING: if (digitalRead(DccProcState.ExtIntPinNum)) break;
case FALLING: if (digitalRead(DccProcState.ExtIntPinNum)) return; break;
}
In this quick fix I did not care about support for other processors etc. So maybe someone with good knowledge of the entire could make the proper adjustments so it works with all processors.
Hi Alex,
I detected, that the actual version 1.4.4 is no longer compatible to previous releases regarding the accessory decoder. The callback functions changed, and the old one is no longer available. Now sketches don't work anymore without any error message.
Is this really intended to be so?
Regards
Franz-Peter
Your extension to CV29 could be better documented!
As far as I can see it just changes two things:
Neither of which is very clear - which mode should an accessory implementor use and why?
Hi,
Great library you all created. Thanks!
My question is, can I use other pins than the 'standard' one (D2 on the Arduino) for inputting a DCC signal. F.i. the ATMega328P has a max of 23 programmable I/O pins all with the possibility of making them generate an interrupt. Say I want to use PD6 as input; this pin generates PCINT22 which would generate a jump to the PCI2 vector (and back). Is this already implemented in the library?
Thanks for reading/answering this,
Willem.
I am using an Uno to decode the DCC signal using a custom shield, but my code will randomly stop working. This is pretty easy for me to tell, since I blink LEDs on the board as long as DCC packets are incoming. The DCC signal is routed through an isolator and then to D2 on the Uno. Even if there are no packets coming across(DCC is not plugged in) it still seems to randomly stop after a few seconds.
Is there something to look at in order to debug this?
I understand ESP32's NMRADCC to write CVs to a flash block, I'm worried that frequent reads and writes will drastically shorten the RAM life. For this, I would like to be able to create an external EEPROM storage space for storing CVs via SPI
How does this require adjusting the code?
Hello is there a way to use and enter more than 28 functions?
I would like to use more than the currently available functions 28 for a sound module, according to the RCN-212 DCC protocol
Operating commands for vehicle decoders Edition 01.12.2019 R
http://normen.railcommunity.de/RCN-212.pdf
Can be used max F68.
2.3.4 Function control F13-F68
These commands are two bytes long and have the following formats:
๏ท Function control F13-F20: 1101-1110 DDDD-DDDD
๏ท Function control F21-F28: 1101-1111 DDDD-DDDD
๏ท Function control F29-F36: 1101-1000 DDDD-DDDD
๏ท Function control F37-F44: 1101-1001 DDDD-DDDD
๏ท Function control F45-F52: 1101-1010 DDDD-DDDD
๏ท Function control F53-F60: 1101-1011 DDDD-DDDD
๏ท Function control F61-F68: 1101-1100 DDDD-DDDD
Is there any way to extend it?
Thank you for an info
Olaf Reis
Hello
I'm experimenting with some new ATMega processors (4808, 4809, 128DA), originally for my own DCC decoding libraries (still following the OpenDecoder approach of using a timer) but 9as comparison and check) also with the NmraDcc library.
The good news is that the NmraDcc library compiles and runs on the Nano Every. However, like my own decoding library, performance on these new processors turns out to be considerably slower than that on the 328. There are several reasons for that, the most important one being the overhead created by attachInterrupt(). On the UNO is takes roughly 3,5 microseconds after the pin change until the "user code" within the ISR starts. On the Nano Every this time is twice as long, around 7 microseconds 9depending if the standard Arduino boards of the MegaCoreX is used). See also my earlier post in the Arduino forum: https://forum.arduino.cc/t/difference-in-time-between-interrupt-start-on-mega-2560-and-nano-every-4809/897591/15
Unfortunately, not only attachInterrupt() is considerably slower, but also micros() (you can find several discussions of that in the various fora).
My question is therefore whether others observe the same performance problems of NmraDcc on these new ATMega processors. I understand that the NmraDcc library will run on lightly loaded Nano Every boards, but I'm running into problems if I include (my own) RS_Bus feedback library. Also the RS-Bus raises an Interrupt roughly every 100 microseconds, and two of these libraries together don't work reliably.
For my own DCC decoder library I decided to make a drastic change, and add some of the new features that these new 480X and 128DA processors offer. Basically I connect the DCC input signal to the Event system, which triggers a timer as output. This saves me the (overhead of the) DCC input ISR, and the timer gives me a very stable reading of the DCC signal.
I would be interested in what others think of this.
Aiko
DCC supports a decoder having a temporary secondary "consist" address in CV 19.
Would it be reasonable for the FLAGS_MY_ADDRESS_ONLY
check around NmraDcc.cpp:966 to also check against this consist address? You might need a new method similar to the existing getMyAddr()
that looked at an extra cv19 field in the DccProcState
.
I am using the Arduino IDE level 1.8.19 and trying to compile sketch named NmraDccAccessoryDecoder_1 from the Accessory folder of the NmraDcc-master library. The error is 'DEFAULT_ACCESSORY_DECODER_ADDRESS' was not declared in this scope
I get the a similar error compiling sketch NmraDccMultifunctionDecoder_1 'DEFAULT_MULTIFUNCTION_DECODER_ADDRESS' was not declared in this scope
I have not made any changes to either sketch. I have used them as distributed.
Can you please explain how to correct this error.
Thank you,
Dale Gloer
Hello i trying to get it runing on My Pi Pico. i head read a fiew times "ARDUINO_ARCH_RP2040" so i thinked it wud work. but as i uploaded my simple sniffer sketch it just output "Sniffer Start". and dhat's it.
I tried also on an Arduino Nano and it worked.
#include <NmraDcc.h>
#define DCC_PIN 2
#define DCC_DECODER_VERSION_NUM 11 // Set the Decoder Version - Used by JMRI to Identify the decoder
NmraDcc Dcc ;
DCC_MSG Packet ;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Dcc.pin(0, DCC_PIN, 1);
Dcc.init( MAN_ID_DIY, DCC_DECODER_VERSION_NUM, FLAGS_DCC_ACCESSORY_DECODER , 0 );
while (!Serial) {
}
Serial.println("Sniffer Start");
}
void loop() {
// put your main code here, to run repeatedly:
Dcc.process();
}
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();
}
On the Hardware side i used bridge rectifier for Ground and a voltage devider that converts the rail voltage to 3.3V clamped with a zener diode and feed it through an schmittrigger. than into my Controller.
Can somone help me pleas?
(It feels a bit awkward to ask questions in GitHub. If there is a better place, please let me know.)
I'm trying to build a turn-out decoder with an ATTiny85. I couldn't find a servo library that doesn't interfere with NmraDcc. So I decided to create the pulses in the code. However, while there is a DCC signal on the tracks, the servo becomes jittery. I guess that is because the interrupt has more priority than the delayMicroseconds() function. So, i thought about turning DCC reading off while the servo is moving. My idea basically is:
I'm aware that I would miss packets during the time DCC reading is turned off, but I don't have a need to switch turn-outs in quick succession.
So, is there a way to disable DCC reading termporarily? Or is there another way to get jitterless servo control?
This is the code I'm currently using, which disables the pulse after switching so that the servo stops trembling. It works, but it would be nice if I could move the servo slowly and steadily:
#include "NmraDcc.h"
NmraDcc Dcc ;
DCC_MSG Packet ;
const int adresse = 25;
const int LED = 4;
const int relay = 3;
const int servo = 1;
int pos = 90;
unsigned long last_update;
unsigned long now;
void servo_pulse(int pin, int pos){
int pulse = map(pos,0, 180, 850, 2050);
digitalWrite(pin, HIGH);
delayMicroseconds(pulse);
digitalWrite(pin, LOW);
delay(20);
}
void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower )
{
switch(Addr){
case adresse:
if(Direction < 1){
digitalWrite(LED, LOW);
digitalWrite(relay, LOW);
pos = 65;
}else{
digitalWrite(LED, HIGH);
digitalWrite(relay, HIGH);
pos = 115;
}
last_update = millis();
break;
default:
break;
}
}
void setup()
{
Dcc.pin(0, 2, 1);
Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 );
pinMode(LED, OUTPUT);
pinMode(relay, OUTPUT);
pinMode(servo, OUTPUT);
}
void loop()
{
Dcc.process();
now = millis();
if ((now - last_update) < 65){
servo_pulse(servo, pos);
}
}
sometimes ESP32 runs into the problem, that no DCC data are processed anymore.
I found out that in error state we have
so this code
if ( bitMicros < bitMin || ( DccRx.State != WAIT_START_BIT && digitalRead( DccProcState.ExtIntPinNum ) != (ISRLevel) ) ) {
will always detect a short bit, because when interrupt filter is RISING the ExtIntPinNum will never be 0.
This fault situation needs a reboot.
It seems that the problems comes from this code
#ifdef ESP32
ISRWatch = ISREdge;
#else
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
// enable level checking ( with direct port reading @ AVR )
ISRChkMask = DccProcState.ExtIntMask;
ISRLevel = (ISREdge==RISING)? DccProcState.ExtIntMask : 0 ;
#endif
because ISRChkMask and ISRLevel are not set correctly (in ESP32 case)
The fixed code could look like this - but maybe it's not the only location where levels aren't set correctly.
#ifdef ESP32
ISRWatch = ISREdge;
#else
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
#endif
// enable level checking ( with direct port reading @ AVR )
ISRChkMask = DccProcState.ExtIntMask;
ISRLevel = (ISREdge==RISING)? DccProcState.ExtIntMask : 0 ;
As described in the title when running the unmodified library and example on an ESP32C3 system, core 0 panics on EEPROM.commit.
I can get around this by moving the commit outside the noInterrupts() <-> interrupts() but I am unsure what other impact this may have on the system.
I am using release JMRI 4.18 and DCC++ Basestation to generate Extended Accessory packets. With NmraDccAccessoryDecoder_1 example it appears that notifyDccSigOutputState is not called.
The JMRI seems to generate correct packet:
JMRI:
[TX: M 0 80 71 02 F3] Write DCC Packet Main Cmd:
Register: 0
Packet: 80 71 02 F3
The packet seems to be received just fine, except for the last byte (perhaps the checksum gets zeroed while checking). Number '5' in debug output is the received message length:
NMRA DCC Example 1
Init Done
notifyDccMsg: 5:80 71 2 F3 0
notifyDccMsg: 5:80 71 2 F3 0
notifyDccMsg: 5:80 71 2 F3 0
Yet the notifyDccSigOutputState is never called.
I have a version where I ported the code to Seeed Studio XIAO. I have implemented a conditional compile so the EEPROM code works for getting and setting CVs. Attached are files. I also made changes to FlashStorage.h so that the read operations would be very efficient. The XIAO only has emulated storage. If can be backwards compatible so only one library is needed.
NmraDcc.h.txt
NmraDcc.cpp.txt
FlashStorage.h.txt
Originally posted by @billswartz7 in #38 (comment)
I have a version where I ported the code to Seeed Studio XIAO. The XIAO only has emulated storage. I have implemented a conditional compile so the EEPROM code works for getting and setting CVs. Attached are files. I also made changes to FlashStorage.h so that the read operations would be very efficient. Other MCUs can be added using a similar technique.
Hi there,
the library works awesome and I love it. I managed to build my turnout controller using it.
The only issue I am facing is that the address seem to be interpreted incorrectly.
If I use my Roco 10764 Base Station with multiMouse and send accessory enable / disable to an address. Then by sniffing within notifyDccAccState method by printing out the Addr (as DEC), I am getting values lower by 4 ... for example sending the command to Addr 5 prints out Addr=1, etc.
I can certainly fix it by adding 4 to it, but I would rather have this sorted out at the library level.
Any idea?
Thanks in advance!
On resetting the decoder, CV8 -> 8, notifyCVResetFactoryDefault() is triggered seven times. It is probably not a good idea for EEPROM to be rewritten too many times.
As a patch, I used if (FactoryDefaultCVIndex == 0) in front of FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
This reduces seven EEPROM writes to "only" three.
I am using PiSPROG DCC controller/programmer and ATmega328.
Best regards!
notifyDccAccTurnoutBoard() and notifyDccAccTurnoutOutput() both seem to have the same cut and pasted comments. Shouldn't the former be for when CV29_OUTPUT_ADDRESS_MODE is 0 and the latter for when it is 1 (set)? I can't link I guess without being a member of this repo, but it is this PR: #53
Lines 523 to 527 in 681b362
Hello,
I am new to DCC world, but do enjoy programming microcontrollers to control trains and track accessories. However, I do not know how to connect the signal pin of the Arduino to the tracks (e.g. where the ground and the pin input go and if there are any electrical components needed). I saw a schematic on-line that involved a resistor and and a diode, but I am not sure if that is universally applicable.
Hallo,,
is there a possibility that you can use more than one locomotive address. e.g. Address 100 is configured, the second address is then address 101 and possibly a third one with address 102 etc.
Thanks for your Info.
Olaf
I try to build an ESP32 DCC based on NMRADCC, it seems that there are some problems in the interrupt definition part, how should I solve it?
src\NmraDcc.cpp: In function 'void ExternalInterruptHandler()':
src\NmraDcc.cpp:369:26: warning: unused variable 'DCC_IrqRunning' [-Wunused-variable]
static byte halfBit, DCC_IrqRunning, preambleBitCount;
^
src\motor_ctrl.cpp: In function 'int MOTOR_GetBEMF()':
src\motor_ctrl.cpp:367:15: warning: suggest parentheses around '+' inside '>>' [-Wparentheses]
aAve = aAve + analogRead(MOTOR_READ) >> 2;
^
src\motor_ctrl.cpp:388:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
I've tried running the various examples with no luck at all. I don't have an oscilloscope, so I can't be quite sure that I'm actually getting a DCC signal to the Arduino. Any pointers?
I have been been looking into various DCC options for accessory signal/turnout control & would like to see if I can get an Arduino to do this. From what I have read etc. it all looks possible but I cannot make sense of the example files I have download so can someone provide some info on what will work?
I have looked at the 'NmraDccAccessoryDecoder_1' file which I presume works with no modification, would be nice to find some more explanation on what sections/code does what if there is such a thing anywhere?
Also is there any way of outputting the DCC signal from a Arduino without a motor shield to test or is the signal not true enough to DCC?
Thanks
I am compiling in EPS-IDF environment and mentioned a warning
D:/Esp-Doc/ESP-decoder/components/NmraDcc/NmraDcc.cpp: In function 'uint8_t writeCV(uint16_t, uint8_t)': D:/Esp-Doc/ESP-decoder/components/NmraDcc/NmraDcc.cpp:616:28: warning: this statement may fall through [-Wimplicit-fallthrough=] DccProcState.Flags = (DccProcState.Flags & ~FLAGS_CV29_BITS) | (Value & FLAGS_CV29_BITS); ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ D:/Esp-Doc/ESP-decoder/components/NmraDcc/NmraDcc.cpp:618:5: note: here case CV_ACCESSORY_DECODER_ADDRESS_LSB: // Also same CV for CV_MULTIFUNCTION_PRIMARY_ADDRESS
I found that there is no "break" at the end of each case of switch (CV). Is this intentional? Is there a problem if we do not deal with this warning?
I'll start with a description of the situation as I see it - NmraDCC's documentation is sparse, so I had to "learn" from the examples.
Unlike multifunction decoders, it seems that accessory decoders are not supposed to be programmed via the command track. I found that using the FLAGS_DCC_ACCESSORY_DECODER flag tells NmraDCC not to change the CVs on the command track and to ignore CV1, CV9, CV17 and CV18.
However, there is a loophole: two additional CVs can be defined and given as an argument during initialization, so that an accessory decoder can also be programmed on the command track. However, most likely you want to have the same decoder address on both the programming and command track, which means that the same address is in three places: CV1/CV9, CV17/DV18, and additional CV pair. (You also need to put the address in CV17/DV18 so that the DCC controller can communicate with it as a virtual multifunction decoder).
Is what I have written so far correct?
This is a very clumsy solution. I know that by default the accessory decoder should ignore CV change requests on the command track. But it would be easier to control this directly from CV17/CV18. If those two values are 0x00 (or 0xC0 and 0x00), the decoder should ignore changes to CV, while the NmraDCC library should listen to CV change requests if those two values would specify a viable address.
Best regards
Hi,
I found out, that the SMB Examples lose packets. The reason is that the Dcc.process() function isn't called often enough.
The Dcc.process() function must be called at least once for every received packet. A DCC accessory packet may be around 6ms long ( including the preamble ). Therefore the Dcc.process() must be called more than once every 6ms. Because of the delay(8) in the loop of the examples this is not possible.
Normally this will not be apparent, because the central station repeats the packets several times.
But I think especially the examples should be programmed to not lose packets under normal conditions.
I want the multi-function decoder to support a 28-step speedometer, so I store 28 steps of speed values in CV67 to CV94, and set value 16 in CV29.
I noticed that the void notifyDccSpeed() function is used to define a specific speedometer value. But there is no such setting in any of the examples, so I'm not sure about it.
Is it understood like this:
void notifyDccSpeed(uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps)
{
uint16_t aSpeedRef = 0;
if (Speed >= 1)
{
aSpeedRef = Dcc.getCV(67+Speed-1);
}
else
{
#ifdef DCC_DEBUG
Serial.println("***** Emagency STOP **** ");
#endif
aSpeedRef = 0;
}
.........
Another: I looked at a lot of documentation on CV29(Bit 4), and it was all about CV25. But I don't understand that CV25 is associated with the curve table. Please advise.
I'm using this Wonderfull library to build out an accessory decoder for my layout. I wanted the ability to use OPS mode programming to change some of my custom defined CV's. I'm not sure if I really understand the NMRA standard for handing accessory addressing. It seem both NCE and JRMI systems use extended addressing.
At line 1409 there is this code....
else if(pDccMsg->Size == 6) // Accessory Decoder OPS Mode Programming
{
DB_PRINT("eDP: OPS Mode CV Programming Command");
// Check for unsupported OPS Mode Addressing mode
if(((pDccMsg->Data[1] & 0b10001001) != 1) && ((pDccMsg->Data[1] & 0b10001111) != 0x80))
{
DB_PRINT("eDP: Unsupported OPS Mode CV Addressing Mode");
return;
}
// Check if this command is for our address or the broadcast address
if(DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE)
{
DB_PRINT("eDP: Check Output Address:%d", OutputAddress);
if((OutputAddress != getMyAddr()) && ( OutputAddress < 2045 ))
{
DB_PRINT("eDP: Output Address Not Matched");
return;
}
}
Both NCE and JMRI seems to send extended addresses for OPS Accessory Decoder programing.
If I make the following changes it seems to work, but I'm not sure if I understand the addressing completely
else if(pDccMsg->Size == 6) // Accessory Decoder OPS Mode Programming
{
DB_PRINT("eDP: OPS Mode CV Programming Command");
// Check for unsupported OPS Mode Addressing mode JMS seems like we dont support extended addr
if((pDccMsg->Data[1] & 0b10001100) == 0b00001100) // JMS enabled extended addresses
{
myDB_PRINT("eDP: Unsupported OPS Mode CV Addressing Mode");
return;
}
// Check if this command is for our address or the broadcast address
if(DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE)
{
//JMS new code to fix address if CDDD = 0
if((pDccMsg->Data[1] & 0b10001111) == 0x80) // JMS NEW
{ // JMS NEW
OutputAddress = BoardAddress; // JMS NEW
DB_PRINT("eDP: Updated Address"); // JMS NEW
} // JMS NEW
Are my changes correct? I can only test with NCE and JMRI with SPROG but so far seems to work as expected.
Hello,
Is it possible to have a multifuctionmotordecoder example working with ESP32
thanks
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.