Railstars CmdrArduino lib help

I've been trying to get a model train DCC command station library running, but I'm having problems getting past the initialisation routine.

The lib is available from - GitHub - Railstars/CmdrArduino: CmdrArduino is an embedded library written in C++ that provides the foundation for implementing an NMRA DCC command station. CmdrArduino presents classes and methods for, among other things, setting a locomotive’s speed, activating functions, switching turnouts, and programming DCC decoders. CmdrArduino translates these commands into DCC packets. The packets are carefully prioritzed, and CmdrArduino keeps track of packets that require repeating in the background. An interrupt service routine attached to TIMER1 (AVR) or MCPWM0 (ARM) takes these packets and injects the highest priority packet into the precision DCC waveform. This signal is suitable for amplification with your favorite booster/power station (I like RAILbooster). Please note that the Arduino outputs are not themselves capable of driving trains directly. Currently, CmdrArduino supports Arduino (including the Railstars Io;duino), with ARM support (for LPC17xx processors) actively being added, making the library name something of a misnomer.

It's generating a DCC pulse train ok, but it doesn't seem to be getting past this function in DCCPacketScheduler.cpp,

void DCCPacketScheduler::setup(void) //for any post-constructor initialization
{
  setup_DCC_waveform_generator();
  
  //Following RP 9.2.4, begin by putting 20 reset packets and 10 idle packets on the rails.
  //use the e_stop_queue to do this, to ensure these packets go out first!
  
  DCCPacket p;
  byte data[] = {0x00};
  
  //reset packet: address 0x00, data 0x00, XOR 0x00; S 9.2 line 75
  p.addData(data,1);
  p.setAddress(0x00);
  p.setRepeat(20);
  p.setKind(reset_packet_kind);
  e_stop_queue.insertPacket(&p);
  
  //idle packet: address 0xFF, data 0x00, XOR 0xFF; S 9.2 line 90
  p.setAddress(0xFF);
  p.setRepeat(10);
  p.setKind(idle_packet_kind);
  e_stop_queue.insertPacket(&p); //e_stop_queue will be empty, so no need to check if insertion was OK.
}

It's almost like the setRepeat is repeating for ever.

Short pulses are 1 and long pulses a 0,

The string of 1's is a preamble, and all 0's i believe is a reset packet. This is all I ever get.

I'm using the CmdrArduino_minimum.pde example,

/********************
* Creates a minimum DCC command station from a potentiometer connected to analog pin 0,
* and a button connected to ground on one end and digital pin 4 on the other end. See this link
* http://www.arduino.cc/en/Tutorial/AnalogInput
* The DCC waveform is output on Pin 9, and is suitable for connection to an LMD18200-based booster directly,
* or to a single-ended-to-differential driver, to connect with most other kinds of boosters.
********************/

#include <DCCPacket.h>
#include <DCCPacketQueue.h>
#include <DCCPacketScheduler.h>


DCCPacketScheduler dps;
unsigned int analog_value;
char speed_byte, old_speed = 0;
byte count = 0;
byte prev_state = 1;
byte F0 = 0;

void setup() {
  dps.setup();

  //set up button on pin 4
  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH); //activate built-in pull-up resistor  
}

void loop() {
  //handle reading button, controls F0
  byte button_state = digitalRead(4); //high == not pushed; low == pushed
  if(button_state && (button_state != prev_state))
  {
    //toggle!
    F0 = (F0+1)%2;
    Serial.println(F0,BIN);
    dps.setFunctions0to4(3,F0<<4);
  }
  prev_state = button_state;

  //handle reading throttle
  analog_value = analogRead(0);
  speed_byte = (analog_value >> 2)-127; //divide by two to take a 0-1023 range number and make it 0-127 range.
  if(speed_byte != old_speed)
  {
    dps.setSpeed128(3,speed_byte);
    old_speed = speed_byte;
  }
  dps.update();
  
  ++count;
}

Any ideas guys?

Minor progress,

Commenting out a large portion of DCCPacketScheduler::setup(void) has got it to output new packets, but of course it no longer resets locos on power up, which isn't great...

void DCCPacketScheduler::setup(void) //for any post-constructor initialization
{
  setup_DCC_waveform_generator();
  
  //Following RP 9.2.4, begin by putting 20 reset packets and 10 idle packets on the rails.
  //use the e_stop_queue to do this, to ensure these packets go out first!
  
  DCCPacket p;
  byte data[] = {0x00};
  
  //reset packet: address 0x00, data 0x00, XOR 0x00; S 9.2 line 75
  /*p.addData(data,1);
  p.setAddress(0x00);
  p.setRepeat(20);
  p.setKind(reset_packet_kind);
  e_stop_queue.insertPacket(&p);*/
  
  //idle packet: address 0xFF, data 0x00, XOR 0xFF; S 9.2 line 90
  /*p.setAddress(0xFF);
  p.setRepeat(10);
  p.setKind(idle_packet_kind);
  e_stop_queue.insertPacket(&p); //e_stop_queue will be empty, so no need to check if insertion was OK.
  */
}

I'm thinking it's to do with setRepeat which is an inline in DCCPacket.h

inline void setRepeat(byte new_repeat) { size_repeat |= new_repeat&0x0F ;}//repeat = new_repeat; }

The search continues

Hello! I'm the author of this library; I've heard tell others have had this same problem, but I can't replicate it, mostly because the problem seems to crop up on Arduino Megas, and I don't own one. Are you using a Mega?

Anyway, contact me off list if you need assistance, because I need your help tracking this bug down!

Thanks!

I'm actually running your library on a Spark Fun 328 pro mini, with a Mega sending commands over serial.

I've come across another problem, possibly related. If I send an eStop the library then seems to stop responding to further commands, need to get the scope out to see whats happening there though.

Interesting. Development was all done on a '168. Don't have a booster at the moment (waiting on the newest batch of LOLbooster PCBs to be fabbed up), so I'm not currently in a position to run the code with a real, live train (and my o'scope sucks at capturing DCC packets), but I will review both the initialization code and the estop code. The initialiation code had been working for me, but it is actually within NMRA spec to elide the layout reset bit; that's optional. So if that works for you, do it for now. The estop code is less well tested, and I have a susupicion that what's happening is in fact related.

Best guess: The estop_queue, which is used primarily for holding estop packets, but is also used by the layout reset code, is not handling packet repeats correctly, looping forever.

Think I've fixed it. Found a nasty little bug in DCCPacket::setRepeat() that would prevent it from ever being set to zero! Download the latest version of the "master" branch, and try it out.

While you're at it, would you care to try out the "mega" branch on your Arduino Mega for me?

After a quick test it seems to startup just fine, allowing the loco to run, however eStop doesn't work now.
I'll do a more testing later to make sure it's not my fault.

I'll dig out the Mega from the controller and test the Mega branch too.

Apparently I never finished the e-stop code! Fixed.

After a couple of tweaks it's working!

Fixed a typo - e_stop_packet.setReepat(10); to e_stop_packet.setRepeat(10);
Changed data value - byte data[] = {0x61}; to byte data[] = {0x41};

I think DCCPacketScheduler::eStop(unsigned int address) needs a tweak too

Found a few more typos besides; all patched now; MEGA branch updated too.

That all seems to be working perfectly now, nicely done!

As to the Mega, a couple of issues,

first the compiler throws up:
DCCPacketScheduler.cpp: In function 'void __vector_17()':
DCCPacketScheduler.cpp:154: error: 'current_packet' cannot be used as a function

Commented out line 154 Serial.print(current_packet(j),HEX); and it compiles ok

Second is there no output on pin9 at all.

Oh, that line should have had square brackets:

Serial.print(current_packet[j],HEX);

That's debugging code from back when I suspected the problem you were experiencing was Mega-specific. Just comment all those Serial.print lines out.

Finally, on the Mega, the DCC signal is output on digital pin 11, not pin 9. :smiley:

I've been watching this thread with interest - nice work on this library :slight_smile:

mowcius:
I've been watching this thread with interest - nice work on this library :slight_smile:

Thank you! I hope to have an OpenLCB library to augment it by the NMRA West convention, to make a complete Arduino-based command station.

That explains alot, with the booster hooked up to pin 11 it's working perfectly!

to make a complete Arduino-based command station.

Pretty neat :slight_smile:

beige:
That explains alot, with the booster hooked up to pin 11 it's working perfectly!

Excellent! Glad to hear it! I'll merge the branches later today.

The Mega has a different pinout for the internal timers, which necessitates using a different pin for the signal output. I clearly need to better document this fact!

Do let me know if any other issues crop up, or if there's a feature you'd like to see added, and keep us abreast of the fun things you do with CmdrArduino!

You asked for more issues, and I think I have one...

CV programming, using the latest version I can't program anything, however if I use the old version from January I can program CV2 and above, programming the short address CV doesn't have any effect..

I've tried this on 2 decoder with the same effect, using the Hornby Select I can program the address, but for some reason it re-programs lots of unrelated CVs, which is annoying...

THat's no good! I'll have a look a bit later to see what's changed.

You can't program an address in ops mode, in general. I don't know if that's in the NMRA specs or not, but my Digitrax Zephyr won't do it either. So that, at least, is not a bug :smiley: But the other things are. Do you think there is a pattern to what's getting programmed?

The only thing I've noticed is while CV programming works fine in the old version of the library, if setSpeed128 etc. are called in the same loop as opsProgramCV it all seems to become very unreliable, only programming 10% of the time.

Need to do some more experiments to narrow it down yet i think.

As to the lack of address change is ops mode, thats not very useful, I guess service mode is needed.