wavedcc - DCC Command Station running on a Raspberry Pi...

Glenn Butcher Jun 29, 2021

  1. BigJake

    BigJake TrainBoard Member

    3,259
    6,173
    70
    To be fair, "Bit Manipulation" is not the best name for that command. I almost overlooked it's query option myself.

    Speed-up factors of 32X are really sweet when found!

    Glad I could help this time.
     
    Glenn Butcher likes this.
  2. Glenn Butcher

    Glenn Butcher TrainBoard Member

    167
    306
    9
    Just merged a work branch to main with an initial implementation of improved CV reading. Good news was that bit operations worked pretty much the same as byte operations, so the timing and sequencing I'd worked out previously applied to using bit ops. However, the logic to actually get a value is quite different than, "is 0 it? No? okay is 1 it? No? okay......"

    What I implemented is a simple walk of the bits, adding bits found to be '1' to their proper place in a 0-initialized variable. However, I leveraged checking the first bit (0) with a test for both '1' and '0'; if neither gave an ack, then I assume there's no locomotive or there's a contact problem and report the error. Also, I use the bit 0 results to initialize the value variable with either 1 or 0, respectively. Then, I loop through 1..7 verifying for a '1' bit; if acked, I add the 1-bit to the value, otherwise I assume a '0' verify would return an ack, and leave the existing '0' value in that position undisturbed.

    Now, there's always a chance that the locomotive connection could be compromised after the first bit is evaluated. If there's a remote possibility of that, I'' want to change the logic to check for both '1' and '0' for every bit. As I write that, I envision a nefarious user rocking the loco off the tracks while the verify chain is going on, just to see what happens. So, I'll probably change my logic to do that, at the expense of a couple of seconds of time, because I don't like nefarious users... :D
     
    BigJake likes this.
  3. CSX Robert

    CSX Robert TrainBoard Member

    1,502
    638
    41
    It wouldn't even take that. Since it's common for decoders to pulse the motor to generate the acknowledgment the engine could move onto a dirty section in the track, or if there is a bad connection in the loco the movement could cause it lose contact.
     
    Glenn Butcher likes this.
  4. BigJake

    BigJake TrainBoard Member

    3,259
    6,173
    70
    While verifying each bit both ways protects against unknowingly incorrectly reading the decoder, it doesn't obviate the need for a clean programming track. Ensuring a clean programming track is still required.

    And this method still provides a 16x speed-up from before...

    This is probably the clearest advantage of having a separate programming track from the layout. Some users mount their programming track on a pull-out tray/drawer under the layout or workbench, which protects it better from accumulating dust, dirt and debris.

    From watching/listening to my locomotives when being read into DP with my SPROG system, I believe it does this double-read verification as well (there always seem to be 8 flashes/bumps per register). I was always curious about that...

    Does anybody know if DCC++EX does this too? Or other DCC systems?
     
    Glenn Butcher likes this.
  5. Glenn Butcher

    Glenn Butcher TrainBoard Member

    167
    306
    9
    I spent a good bit of time playing with various strategies on the three locomotives in my DCC stable, and came to the following:

    1. Verify 1 and 0 of bit 0; this is where an absent/errant loco is caught
    2. loop through bits 1-7, verifying 1.
    3. Byte-verify the byte collected in steps #1 and #2. If not equal, go back to #1 and try again.
    4. Do #1-#3 until a good verify is obtained in #3, or 4 tries have been attempted.

    I implemented two configurable parameters with essentially the same names and meanings as their DCC++ counterparts: acklimit and ackmin (my logic doesn't need ackmax, I don't think...). They default to DCC spec-compliant values; interesting is that I had to up acklimit for my Soundtraxx-equipped loco to 200ma. There was just too much variation in the quiescent current to use 60ma as the ack test.

    With the above logic and parameter tweaking, I've got most reads to succeed in one attempt. Some still take two, and I had one on the Soundtraxx loco take three attempts. I'm liking the retry scheme.

    I got a lot of good insight from the DCC++ documentation on diagnostics, and a TrainBoard thread from a couple of months back:

    https://dcc-ex.com/reference/software/diagnostic-d-ack-command.html

    https://www.trainboard.com/highball/index.php?threads/dcc-ex-programming-track.136531/
     
  6. Glenn Butcher

    Glenn Butcher TrainBoard Member

    167
    306
    9
    I had changed out how I evaluated the collection of currents for an ack to go through the entire list, previously I used the last 10 measurements. I'd forgotten why I did it the first way, and that was to avoid tail-off currents from the previous ack. That still seems to exist for my Soundtraxx locomotive, so I just reverted the logic to the original "last 10".

    DCC++ evaluates the current draws after each verify packet, in order to abort the pulse train when a proper ack is received. I put together and send the entire pulse train, so I don't have such insight. I'm thinking about how I'd reorganize my logic to support such; indeed, libpibpio would support it easily. However, my next step is to test what I have against DecoderPro; it may be good enough for gov't work, as it is... I'm itching to start layout construction; I already have the capability I'll use most of the time, ops mode; all this work on programming mode doesn't actually run trains... :D
     
    BigJake likes this.
  7. BigJake

    BigJake TrainBoard Member

    3,259
    6,173
    70
    Glenn,

    I think the way you are sensing motor current may be causing some of your current measurement issues. Your current sensor is reading the filtered (via capacitor) supply current for your motor driver IC.

    The Arduino L298 motor driver shield uses the current sense output from the L298 IC to get an indication of instantaneous drive current (not driver supply current). If the current measurement (A/D conversion) is timed relative to the DCC pulse you control (to stay away from the transitions in the DCC waveform), it can result in a more consistently accurate measurement.

    Since DCC allows stretching the '1' (or is it the '0'?) pulse width duration on the waveform (for running DC locomotives), it should be possible to stretch the pulse long enough to get an A/D conversion smack in the middle of a track pulse, and thereby get an accurate current measurement.

    For that matter, I don't know how fast your current monitor is responding either...

    The ADC on the Pi Arduino Shield Adapter is capable of 5 uS conversions, but I don't know how fast the R-Pi IO can reliably drive the clock.

    Looks like it would be quite involved to get the Arduino Motor shield, with current monitoring, running on an Arduino shield adapter on the R-Pi...
     
  8. BigJake

    BigJake TrainBoard Member

    3,259
    6,173
    70
    On the contrary, programming mode is required to run trains, unless you want them all to act like one (albeit disconnected) consist!

    Or you could cheat and use your pre-existing programming solution. Where's the fun in that?!
     
  9. Glenn Butcher

    Glenn Butcher TrainBoard Member

    167
    306
    9
    Oh, without a doubt. The INA219 is sitting on the input side of the L298n, so I have to measure and account for the draw of the motor driver logic, in addition to the locomotive's quiescent draw. I'm also pulling samples over a I2C bus on a 1ms period; I may cut that in half and see if the increased resolution helps work past the packet sequencing epochs.

    But I really think I can get the resolution I need if I come up with a packet-at-a-time driver for service mode, similar to the continuous driver I wrote for ops mode. That way, I can look for the ack between single packets, rather than trying to line it up against the full packet chain. Right now, I'm adjusting current and timing away from the DCC spec to mitigate overlaps of the ack period with the next verify, and that's just not elegant...
     
  10. BigJake

    BigJake TrainBoard Member

    3,259
    6,173
    70
    Well, it may be that the capacitor on the motor driver board is doing you a favor, by smoothing out the current load during level transitions on the bus, thus reducing/eliminating the need to critically time the sampling of the current, especially since it would be difficult/impossible to restrict the current sample to be wholly contained within a DCC pulse.

    If you take many current samples throughout the response window, do you see variation across samples (other than at the edges of the response pulse) for the same decoder?

    But then again, the fact that the motor is used to generate the current load is fraught with consistency problems itself...
     
  11. Glenn Butcher

    Glenn Butcher TrainBoard Member

    167
    306
    9
    Oh, I see significant variation in current, ack-to-ack. The Soundtraxx loco will vary from 1A to 3.2A. The worst is the DN140 in the Kato SD9, sometimes it's ack is below the 60ma spec. With wavedcc's new data logging capability, I'll capture and post a few.
     
  12. Glenn Butcher

    Glenn Butcher TrainBoard Member

    167
    306
    9
    So, I set out to do some data capture. Attached you'll find two text files, 464.txt is the capture from the Soundtraxx K-27 #464 with a Tsunami decoder, 5417.txt is an Atlas SD-9 with a Digitrax DN140 decoder. In each file you'll find current and event logging for three CV reads, CV1, CV17, and CV18. Each file starts with a string of baseline readings take at a .5sec period, this period is decreased to about 4ms (the minimum I can do with my current monitoring thread right now) for the start of a CV read operation.

    The timestamp of each log event is in sec_usec, courtesy gettimeofday().

    Let's look at 464 first. Before the CV read starts, note the variance of the current, from about 140ma to 192ma. The CV read starts with the log event

    read CV: start 20 power up resets

    and ends with

    read CV: 20 power up resets complete
    read CV1: quiescent=681.40ma, acklimit=200.0000ma, ackmin=4


    The second line reports the assessed quiescent current of the combined L298n and the decoder, and reports the configured acklimit and ackmin, as the config file can change that. Quiescent is determined from the last ten current reads, to avoid the inrush measured when the reset packet chain starts. Right after that, the CV bit-collection-verification sequence starts; the current scheme is to verify "1" in each bit position, collecting them as the sequence progresses, then verifying the byte collected with the CV contents. If that last verify does not ack, then try again, up to 4 times. Here, we're reading CV1, and here's the verify results:

    CV1 found 1 in bit position 0 (max=1726.90, pc=8)
    CV1 found 1 in bit position 1 (max=1410.30, pc=13)
    CV1 did not find 1 in bit position 2 (max=1410.30, pc=3)
    CV1 did not find 1 in bit position 3 (max=0.00, pc=0)
    CV1 did not find 1 in bit position 4 (max=0.00, pc=0)
    CV1 did not find 1 in bit position 5 (max=0.00, pc=0)
    CV1 did not find 1 in bit position 6 (max=0.00, pc=0)
    CV1 did not find 1 in bit position 7 (max=0.00, pc=0)
    Verify CV1 value 3
    CV1 = 3 (max=1623.50, pc=14)


    So, this one worked with one attempt. Note the differences in the max currents measured during the ack periods. "pc" is the count of measurements > the quiescent current + the ack limit; note that bit position 2 "succeeded" because the number of ack current measurements didn't meet the criterion, 4, but the truth is that there's a 0 in that position so there should not be any ack-quality current. Ah, just reviewed the git log for each Pi, and I haven't pulled the last change over to this computer, which would have averted that situation.

    CV17 succeeded with one attempt, but CV18 took 2 attempts.

    Now that you know the pattern, I'll leave 5417.txt to individual initiative. Of note, the first CV took 2 attempts. Also note the variation in the ack currents, from about 480ma to 3200ma.

    Anyway, food for thought, if you can decipher my madness...
     

    Attached Files:

  13. BigJake

    BigJake TrainBoard Member

    3,259
    6,173
    70
    Strange...

    For 5714, you found a 1 in CV17 bit 2, on only a couple hundred mA delta, when most other 1 bits are >1A delta... And the small delta did not end (it did not see the end of the pulse before it moved on to the next bit. Was CV17 bit 2 actually set to 1?
     
  14. Glenn Butcher

    Glenn Butcher TrainBoard Member

    167
    306
    9
    The loco address 5714, is stored as CV17=214=11010110, CV18=82=01010010. wavedcc read CV17=213=11010101, so there were three bad assertions made, bit 0, bit 1, and the verify of 213. Bit 2 had a current pulse > 60ma, but you see the large variation verify-to-verify, makes me want to abrogate 60ma

    My logic needs work (I think I'm going to go back to bit-verifying both 1 and 0), but it's going to be tough when some locomotive/decoders exhibit such variation in an ack pulse. The DCC++ folk intimate such in their diagnostic page, but what I'm seeing with this loco is even worse...
     
  15. Glenn Butcher

    Glenn Butcher TrainBoard Member

    167
    306
    9
    Dang, stop looking at it, I've got bigger problems than feeble acks. I'm not verifying where the ack is solid, and the "feeble" acks mask the problem. I need to walk through the bit-verify code from the ground up...
     
  16. BigJake

    BigJake TrainBoard Member

    3,259
    6,173
    70
    Given that even the pulses that show both ends, end rather close to the end of samples. You might look at extending (or delaying) your current sampling.

    It also seems weird that the two errant bits in CV17 are opposite direction errors... which indicates that current sensing is not accurate. Or that the timing or logic is wonked. Well, that narrows it down (not)!

    Verifying 1s and 0s may provide more data to figure out what's going on...
     
  17. BigJake

    BigJake TrainBoard Member

    3,259
    6,173
    70
    oops, missed your last post...
     
  18. Glenn Butcher

    Glenn Butcher TrainBoard Member

    167
    306
    9
    Bugged me all night, came to the basement first thing to figure it out. In my overnight musings, I really couldn't find fault with the "build-value-from-1s-then-verify-value" approach...

    First thing was to inspect the config file for the acklimit setting. Really, I had that information in the log file, but hey, there it was, 20.0ma, set during a play at comprehending the low ack pulses. So, I set it to 60ma, and reran the CV1/CV17/CV18 collection. Ta-da, got correct values for each query, although the first, CV1, took three attempts.

    There's still a bit of ambiguity in the low-current acks, but that might be due to the H-bridge current variation. But the 60ma setting looks to drive that occurrence to <2 in a read op, so the chances of a bad verify in both the 1-bit collection and the value verify is small. Attached you'll find the log file for the new collection.

    I did a bunch of CV reads with both N scale locomotives, all came out correct. Had a few that required multiple attempts, but that's how I'm going to handle decoder shenanigans for the time being. I also did a JMRI test, found out I was encoding the <r...> response incorrectly. Fixed that, and I was able to successfully do single CV reads from JMRI. The failures I encountered were properly reported, and due to a dirty track segment. Next challenge is figuring out DecoderPro's sheet-reads; for some reason, I can't get JMRI to enable the programming track from there. I haven't dug into their docs yet, however, man that I am... :D

    I'm probably going to push the programming to the back-burner for a bit. Getting the itch to start building the shelf layout, so I sketched a compression of the Chama, NM north yard where the locos are serviced. Now, need to decide how heavily I want to get into hand-laying track, to get a couple of HOn3 #4 turnouts...
     

    Attached Files:

  19. BigJake

    BigJake TrainBoard Member

    3,259
    6,173
    70
    If it were HOn30, I know what I'd do... but I'm not one to even consider hand-laying track (unless that includes laying Unitrack pieces by hand!)

    SW is fun, but like my son said after his first day of (5-day/week) kindergarten: "That was fun, but I wouldn't want to do it every day."

    I'm a retired Electrical Engineer, and he is now a Software Engineer.
     
    Glenn Butcher likes this.
  20. Glenn Butcher

    Glenn Butcher TrainBoard Member

    167
    306
    9
    I'm looking at FastTracks, but geesh, that's an expensive investment. However, I intend to eventually build some modules, and my kid is interested, so the outlay for tools and templates may make it cost-effective over the long run.

    Where I've had the opportunity to run on well-laid handlay I've noticed the difference in smoothness and reliability, especially where turnout rail was extended well into the adjacent trackage. Never could bring myself to building a turnout in-place, spiking down the components; the templates and PC board ties to which the rail is soldered in the new methods looks more do-able and reliable for less fastidious folk like me.

    Regarding software, I like the mental challenge, keeps me thinking logically. Like last night, bothers me when I don't have it under control, but it feels good to get that control back. I've worked in and around software engineering for most of my career, but most of my actual coding has been for fun, like wavedcc...
     

Share This Page