Introducing DCC++ ---a complete open-source DCC station and interface

Gregg Aug 25, 2015

  1. Michael Zeeb

    Michael Zeeb TrainBoard Member

    11
    9
    2
    Thanks Gregg, Scott, TwinDad for all the ideas......

    I had some time this evening to experiment a little:

    - I'm running older Maerklin loco's with ESU lokPilot decoders. On the main track I run ~18V but the "experimenting" is still happening on the test bench
    - I had been using 12V for fear of overpowering the Arduino Motorshield but the tests below were run with a 15V, 3A power supply I came up with this evening
    - I've put aside JMRI for now to troubleshoot with DCC++ Controller
    - using A output (op's track), I am able to control the locomotive (throttle up, forward/reverse, throttle down, etc.) :)
    (for testing, this locomotive had a known short address of CV1=1)
    - switching back to the B output (programming track), reading any CV returns 255 with the Reading Success message in green
    - reading engine address returns 255(short), 16383(long)
    - all read requests return "Reading Short and Long Addresses Succeeded" in green on the window top bar
    - writing to any CV (for instance CV105) returns "Error - Write failed" in red on the window top bar
    - just for kicks - and because I'm experimenting - I re-connected the A outputs, applied track power, and used the "o" key to write "8" to CV8 on the operating (main track) as suggested by Gregg => effectively resetting the lokPilot decoder to factory defaults
    - changed the cab number to 3 and was able to control the loco => so apparently I can write the CV's from the A outputs on the main track !!
    - changed back to B outputs to read CV1 => Read Succeeded in top bar but value returned is 255!
    - further write attempts on B outputs returns the now familiar "Error - Write failed" in red in the window top bar

    ....just not sure what's going on with the programming track outputs

    Michael
     
    Scott Eric Catalano likes this.
  2. TwinDad

    TwinDad TrainBoard Member

    1,844
    551
    34
    Heads up -- JMRI 4.1.6 is about to be released... DCC++ support is *broken* in this release. If you're working with DCC++ and JMRI, best stick with 4.1.5 until I can get things stable again.

    I broke that age old rule -- "If it ain't broke, don't fix it..."
     
    Scott Eric Catalano likes this.
  3. esfeld

    esfeld TrainBoard Member

    443
    382
    17
    Thank you TD, Important heads up! .... I know you have your hands full ...... hopefully you'll be able to get it worked out for the next release and hopefully, also with the wireless shield code.
    Steve
     
    Scott Eric Catalano likes this.
  4. Gregg

    Gregg TrainBoard Member

    237
    311
    18
    Initial update:

    I swapped out my MEGA for an UNO (with an Arduino Motor Shield) on my layout and tested reading/writing CVs via the programming track with the latest build of the Base Station and it worked as expected (N-Scale / 15-Volt Supply to the Motor Shield). So at least we can rule out problems with the code. I'll do a bit re-wiring and utilize a 12-V supply instead to see the effect.

    For those interested, a few words about reading/writing CVs:

    On the main operations track, writing a CV uses the same style of DCC packets and processing as is used for throttle and decoder function commands. So as long as your decoder allows for "writing to CVs on the main," this should generally work.

    The procedures used on the programming track are very different. For writing, the packet structure does not include a Cab address, but rather the command is expected to be interpreted by whatever loco is on the programing track. Writing by itself does not utilize current-sensing feedback, and will most likely work under most conditions.

    So why does writing not appear to work in DCC++? This will occur if the READING function is not working.

    NMRA DCC standards for reading are very kludgy. You don't actually "read" a bit or byte from the CV. Instead, you send a "verify" command to the decoder asking whether or not a particular CV contains a certain byte, or if a specific bit on a particular CV contains a zero or one. If the CV value matches, than the decoder turns on the engine for an instant to draw some current. If not, it stays silent. This is the only feedback you get - a yes verification, or silence.

    To actually read a byte from a CV, you could loop through every possible byte value (0-255), sending the commands "is this CV a zero?", "is this CV a one?", "is this CV a two?" ... and see which one responds with a current pulse indicating yes. Fortunately, there is a slightly easier, but still kludgy, way to read a byte that requires not up to 256 queries, but only 8. This is because DCC also allows you to query whether a specific bit on a given CV is a one or zero. The way I programmed DCC++ to read a CV byte is to have it send 8 queries: "is bit zero of this CV a one", "is bit one of this CV a one?" ... "is bit 7 of this CV a one?" It then records each of these eight responses from which it can figure out what the byte must be. DCC++ then tries to re-verify the entire byte. If it receives an acknowledgement, it assumes all is well and outputs the value of the byte. If not, it outputs a -1.

    When DCC++ writes a byte to a CV from the programming track, it also tries to verify that the byte was correctly written. Even if the write actually occurred, DCC++ will report that it did not (and return a -1) if the verification did not succeed. Hence, if the "read" functionality is not working because current pulses are not being properly read, then DCC++ will always report an unsuccessful "write" when using the programming track (even if it was successful). This is why Michael is getting an error message saying the write failed when writing from the programming track, but it is successful when writing from the operations track (in which verification is not applicable).

    Michael, you may want to try writing a CV again from the programming track that you know will effect the decoder (such as a reset to CV 8). In spite of the error message, the Base Station may actually be succeeding in the write command. If so, this definitely means the programming track is hooked up correctly, and the problem is either that a current pulse is not being produced by the engine, or the DCC++ logic of reading the current pulse needs to be updated. When you perform a read, does the motor seem to pulse on and off? If so, that means it's definitely the DCC++ logic that is problematic. At present the logic looks for a simple change in the average current over a short period of time. But logic may need to be more robust to work with other voltages and different time delays. I'll begin exploring some alternatives.

    -Gregg
     
    Scott Eric Catalano likes this.
  5. Michael Zeeb

    Michael Zeeb TrainBoard Member

    11
    9
    2
    Thanks Gregg, both for the lesson and for the updates and suggestions. I had no idea that reading the CV values would be such a problematic process. You are absolutely right as it turns out :)oops: not surprisingly!).

    Here are the tests I just completed:
    - with CV1=1, confirmed that I could "run" the train using the A outputs (ie on main track - already established)
    - wrote 8 to CV8 on A output (main track), confirmed loss of control of the loco until writing 1 to CV1 from the main track
    - switched to programming track (B outputs)
    - tried read operation and received 255's on all CV's read as expected (I DID notice a small pulse from the engine - the acknowledgement)
    - wrote 8 to CV8 as a test of ESU decoder reset and received the Error - write failed notification, but.....
    - after checking on the main track, it was apparent that the decoder HAD been reset (CV1=3) => as Gregg postulated, the write's ARE happening on the programming track, they're just not being verified and cannot be read.

    Gregg, does this give you any better clues?

    Michael
     
    Scott Eric Catalano likes this.
  6. Gregg

    Gregg TrainBoard Member

    237
    311
    18
    Thanks Michael -- this is very helpful. These tests verify that the programming track is operating as expected in term of being able to write CVs and that the reads are generating an acknowledgement pulse. The issue must therefore be in the DCC++ logic that reads back the pulse. I'll experiment a bit with the code and see if I can't come up with something more robust for reading the current pulses. Also, I'll add some diagnostics code so that we can monitor the current in real-time to see what the pulse looks like.
     
    Scott Eric Catalano likes this.
  7. TwinDad

    TwinDad TrainBoard Member

    1,844
    551
    34
    ^^^^^
    This is why I'm content to work on the JMRI code and the WiFi interface... while I'm confident that, given some time and study, I would understand the DCC bus interface, I don't really have to, because Gregg has got it. Great explanation, Gregg, and thank you!

    It does occur to me that I maybe should provide an option in the JMRI code that would allow the user to set that their motor shield does not do feedback... this option would disable CV reads and mute the "write fail" response from the Programming Track. No need to have bogus error messages when the user knows the system isn't capable of doing a read...

    I'll put that on the "To Do" list.
     
    Scott Eric Catalano likes this.
  8. Scott Eric Catalano

    Scott Eric Catalano TrainBoard Member

    205
    57
    6
    Also remember this....no matter if it is HO Scale or N scale the new decoders, especially the sound types, require more of a power boost on the programming track to program decoders as I learned on my 5 amp Digitrax system and I had to switch to an 8amp system. The locos equipped with QSI sound decoders were the worst at this....the bachman, atlas, athearns were fine. Non Sound equipped decoders should do just fine. Thats why most programming tracks have an extra booster attached to it.
     
  9. w8one

    w8one TrainBoard Member

    89
    109
    5
    Could it be that the current sense on that output of his shield is not up to the task? Bad solder joint on shield?
     
  10. Gregg

    Gregg TrainBoard Member

    237
    311
    18
    All,

    I've uploaded a new version of DCC++ Base Station containing new and (hopefully!) improved code for reading and writing from the Programming Track. Two changes were made: first, I found a minor bug in the return variable for the <R> command. Upon failure you are supposed to get a negative one, but you would get a 255 (which is a legitimate value). The problem was the declaration of the return variable (was BYTE instead on INT). Now you should get an appropriate error message when a CV Read fails --- which hopefully will no longer happen :)

    The second change is to the logic that tries to determine if the decoder sent back an acknowledgement upon receipt of a CV verify command. This is how reading CVs from the programming track works, and how verification after writing a CV to the programming track works.

    Originally, the logic was based on taking a fixed number of analogRead samples from Arduino Pin A1, which senses current from the Programming Track. If the average value of these samples was above a certain threshold, the code assumed an acknowledgement in the form of a quick current spike was sent by the decoder; if the average was below that threshold it assumed an acknowledge was not sent by the decoder.

    Though this method works for all 7 of my N-scale trains (including one with sound), it is sensitive to:
    1. the size of the sampling window (the larger the window, the lower the average since the current spike would only be a small portion of the window),
    2. the timing of the current spike (it could come too early and be completed before the code begins to take samples, or it can come too late after the code has already taken its samples), and
    3. any baseline current that exists even when the decoder is simply at rest.
    In the new version, the code now:
    1. measures the baseline current before each and every read so it can be subtracted out of subsequent samples,
    2. starts taking samples immediately, in case the decoder responds quickly,
    3. extends the length of the sample period (in case the decoder responds slowly), and
    4. uses an exponential smoothing of the samples to identify a spike that crosses a given threshold level.
    This method is insensitive to the size of the sample window (as long as the spike occurs somewhere in the window).

    I've re-tested on all of my N-Scale trains and it seems to work fine (though so did the original version, so perhaps that's not a sufficient gauge of robustness).

    Michael, please give this a try and let us know how it goes. If it still does not work we can try a few more diagnostics. One test that I found useful is to begin by WRITING (via either the main or programing track) the value 254 to CV #105 (which is reserved for user-definable storage and won't impact the operation of the decoder). Then, try to READ this CV from the programming track. The locomotive should definitely move in short bursts. If not, there may be a connectivity problem. If it does, the new code will hopefully be able to interpret the current feedback correctly. Note that if using DCC++ Controller, it may take 3-4 seconds for a full read of a decoder's long and short address, and there should be a lot of loco movement.

    -Gregg
     
    Scott Eric Catalano likes this.
  11. Michael Zeeb

    Michael Zeeb TrainBoard Member

    11
    9
    2
    Gregg,

    I am in AWE of your skills. Everything now works as expected!

    Michael
     
    Scott Eric Catalano likes this.
  12. Gregg

    Gregg TrainBoard Member

    237
    311
    18
    That is terrific news! Thanks so much for your patience and help in resolving this.
     
    Scott Eric Catalano likes this.
  13. Scott Eric Catalano

    Scott Eric Catalano TrainBoard Member

    205
    57
    6
    Michael,

    How many HO Scale trains are you running at the same time or have tested? Are you programming sound equipped locos?
     
  14. Michael Zeeb

    Michael Zeeb TrainBoard Member

    11
    9
    2
    Scott,
    I'm just beginning the conversion to digital. I'm running original heavy analog Maerklin units purchased by my grandfather in the late 50's and into the 60's; most will likely be left analog and I'll run a separate track for the digital units. To date, I've converted two locos to digital, one old unit that needed major servicing anyway and one eBay find that I couldn't resist. I can't quite bring myself to mess with my grandfather's good locomotives.
    In both conversions I've used lokpilot 4 decoders (without sound). Using Gregg's Controller, the most recently converted unit shows a current draw of about 400 mA when running alone at full (prototypical) speed; I haven't yet run multiple trains simultaneously but I'll likely be limited to two using the motor shield I've got.
     
    Scott Eric Catalano likes this.
  15. Scott Eric Catalano

    Scott Eric Catalano TrainBoard Member

    205
    57
    6
    In the future if you decide to run more I suggest the Pololu motor shield.....it runs very well...I've used 3 locos at the same time and the current draw isn't bad at all.
     
  16. DrGonzo

    DrGonzo TrainBoard Member

    26
    5
    5
    Hi Gregg,
    While I'm waiting for a motorshield to come in, I was thinking that I should be able to use a separate
    Mega 2650 with motorshield to operate accessory decoders, using push buttons for example.
    That would allow me to build a control panel to throw turnouts without the need of doing that
    through software (JMRI etc).
    So, if an input pin on the MEGA changes state, the mega would send out the corresponding DDC
    signal to the accessory decoder to throw the turnout for example.

    Do you see a problem with this setup?

    Thanks,
    Kay
     
  17. Michael Zeeb

    Michael Zeeb TrainBoard Member

    11
    9
    2
    For future reference, which Pololu motor shield are you using?
    Thanks
     
  18. Gregg

    Gregg TrainBoard Member

    237
    311
    18
    This would work quite well, though you may want to check out the DCC++ Controller software since it's quite easy to create a track layout with embedded turnout controls.

    If you want to create a physical panel with push buttons, you could use a simple SPST slide switch that connects any unused pin on the Mega to ground when closed. If this pin is configured as a sensor (using the <S> commands) it will trigger "on" and respond with a <Q ID> when the SPST is closed, and then again with a <q ID> when the SPST is slid to the open position (the pin would be configured to use its internal pull-up resistor).

    You'll then need to modify the sensor code to interpret these sensor triggers to activate the appropriate turnout with a <T> command. I have physical buttons on my layout and do something similar, though I also have the Arduino operate the trains.

    I was planning next weekend on updating the Base Station code to add a generic hook into the sensor logic to call a user-definable function. And as an example, I was going to drop in all of my autopilot routines. These wouldn't be applicable for other layouts, but you can use them as a template for throwing turnouts instead.

    Note that to operate DCC-controlled turnouts you will still need a motor shield. You can use the same Mega for both the Base Station and your panel control - no need for a second Mega. However, if you do want to use a second Mega with a separate motor shield to operate your accessory decoders, then the decoders need to be wired separately from your tracks, which would have a distinct connection to the other Mega. I think using a single Mega would be easiest.
     
  19. Gregg

    Gregg TrainBoard Member

    237
    311
    18
    All,

    One thing that the above question regarding turnout control brings to mind is that using a DCC accessory decoder to control a turnout is not necessarily the only option under DCC++ since we can use free pins for directly controlling turnouts. This may require some additional circuitry, or (even better) the use of a servo to operate a turnout. Arduinos are terrific at controlling servos.

    Has anyone had any experience with using servos to control a turnout?

    -Gregg
     
  20. esfeld

    esfeld TrainBoard Member

    443
    382
    17
    Gregg
    Interesting, so do you think that we could control a Kato TO from vacant Mega pins without the use of a stationary decoder? ....... and, of course, how would one go about this.
    Steve
     

Share This Page