DCC++ EX Software Thread

David Cutting Apr 8, 2020

  1. FlightRisk

    FlightRisk TrainBoard Member

    453
    158
    6
    That circuit is missing a few important components, like the bypass cap you mentioned and a filter cap at the input. The datasheet for the opto specifically says you need a .1uF capacitor across power and ground, so not sure why anyone would omit that. Yet is works for some depending on what it is connected to, the voltage and the length of the wires. Also, that choice of the resistor going into the opto-isolator is important and depends on your track voltage. If it is too low it will burn out the led inside the opto. I tell people the easiest solution is to go here:

    https://model-railroad-hobbyist.com/node/24316

    There is a schematic and a board already made you can get so you don't have to do point to point soldering on a breadboard. This is a good option for people who may be willing to solder, but aren't into electronics design. Then it is paint by numbers; solder only the parts needed for either an optoisolator powered from the tracks by including a voltage regulator, or just an optoisolator powered by something else, or a full decoder and even motor controller ;)

    SignleDecoder-s.jpg

    The bottom is the bare board, the top is populated with a rectifier, regulator, the caps you need and the optoisolator. It also has an Arduino Pro Mini so you can use that to hold a sketch if you want like a 17 function accessory decoder, or a packet sniffer, or whatever else.

    This person sells the boards if you don't want to download a cad file and upload it to a fabricator like Oshpark and get them that way.

    http://www.modelrailroadcontrolsyst...s-low-cost-17-channel-dcc-decoder-bare-board/

    I keep finding uses for them. I am getting ready to order 3 of the high current versions for a project.
     
    Last edited: Aug 21, 2020
  2. FlightRisk

    FlightRisk TrainBoard Member

    453
    158
    6
    @Ash I had a comment and a couple of questions.

    <quote>
    Part of the issue may be due to not understanding how ACK_SAMPLE_THRESHOLD is different with DCCppEX vs. DCCpp. In DCCpp, ACK_SAMPLE_THRESHOLD is used directly to compare with the current sensor, analogRead(A1). DCCppEX uses ackThreshold.
    ackThreshold = ACK_SAMPLE_THRESHOLD/CURRENT_CONVERSION_FACTOR
    DCCpp ACK_SAMPLE_THRESHOLD 30
    DCCppEX ACK_SAMPLE_THRESHOLD 50 but is the numerator for ackThreshold...
    </quote>

    This is just a different methodology. DCCpp is using raw pin reading. We want all the interface between human and machine to be in milliAmps. So the threshold of 30 in DCCpp is a pin reading. Our reading of 50 or 60 is in milliamps. Internally, we then convert the mA value to a pin reading using the CURRENT_CONVERSION_ FACTOR so that all the math is on raw pin readings.

    You upped the smoothing. 9 would just average it out to nothing. I did tests reading out values in real time in the loop and found the delay introduced in the smoothing just obliterated and current pulse. There was a lot of debate about the need for smoothing. I reduced it to .1. Since we added a count (if count==2) to look for more than one ACK, that may be enough to act as a debounce filter. In looking at the current rise and fall, it goes up and down in a curve and is above the ack value for quite a few readings. With the serial monitor running it was about 8-12 readings.

    Given that the timing in this routine is critical, I would want to keep it as simple as possible. Just moving that routine to a function since it is called so many times, broke it. Let me know what your results are.

    You had this routine:
    <code>
    int RegisterList::readBaseCurrent() volatile {
    int base=0;
    for(int j=0;j<ACK_BASE_COUNT/10;j++){
    int base2=0;
    for(int k=0;k<10;k++){
    base2+=analogRead(CURRENT_MONITOR_PIN_PROG);
    }
    base+=base2*10/ACK_BASE_COUNT;
    }
    base/=10;
    return base;
    } // RegisterList::readBaseCurrent()
    </code>

    I must be having a bad day, but is this allowing the same code to handle current sense from 0-1023 and the ones that have negative current from 0-511 and positive from 512-1023? Can you explain your math so I can make notes? Thanks!
     
  3. Ash

    Ash TrainBoard Member

    46
    8
    2
    Code:
    // updated to retain int data type with zero base 512 current sensor
    int RegisterList::readBaseCurrent() volatile {
      int base=0;
      for(int j=0;j<ACK_BASE_COUNT/10;j++){          
        int base2=0;
        for(int k=0;k<10;k++){
          base2+=analogRead(CURRENT_MONITOR_PIN_PROG);
        }
        base+=base2*10/ACK_BASE_COUNT;
      }
      base/=10;
    
      return base;
    } // RegisterList::readBaseCurrent()
    With ACK_BASE_COUNT=100: Instead of a loop of 100, there is a loop of 10, within a loop of 10. It avoids an overrun of the int data type. It adds the first 10, computes an average, stores the average. Repeats. Final step divides by 10. It should work regardless of sensor that starts at zero or one that is zero mA at 512.

    Since you are comparing pin counts, it does not matter if the pin count is 60-0 or 572-512. The difference is 60.

    I was trying to keep the efficiency of using int data type, without losing precision. The unsigned int might have worked, but it resulted in some math anomolies when used in later formulas, and could cause overruns if number of counts were increased.

    Perhaps the simpler solution is to avoid the extra 'for loop' and use long, but return int.
     
  4. Ash

    Ash TrainBoard Member

    46
    8
    2
    @FlightRisk
    -- perhaps like this ...
    Code:
    int RegisterList::readBaseCurrent() volatile {
      int base=0;
      long baseL=0;
      for(int j=0;j<ACK_BASE_COUNT;j++){
          baseL+=analogRead(CURRENT_MONITOR_PIN_PROG);
      }
      baseL/=ACK_BASE_COUNT;
      base = (int) baseL;                        // convert LONG to INT
      return base;
    } // RegisterList::readBaseCurrent()
     
  5. huub

    huub New Member

    6
    2
    1
    Hi FlightRisk and Ronb

    Ronb thanks for your post, it got me thinking, and the comment of FlightRisk made me try something else
    For testing I used the dcc signal coming out of the motorshield and it didn't work with the mardec decoder
    the schematic used is below.
    I feed the mega with 12V DC and my 8 amps booster with 15.5V DC
    hooking up my test-rig after the booster solved the problem!!!!!,
    As you stated FlighRisk, the 1.5K resistor has to be adapted to the current you are using, or as in my case, i have enough current after the booster.

    I am running now 10 mardecs driving 40 electrofrog points using 2 relais per point for frog-polarisation, and 14 engines on DCC++ , and that under the control of the best software available, ROCRAIL
    thanks to you for thinking with me, and I will post this message in a few boards over here to help a lot of other people

    A very happy guy from Belgium :)

    [​IMG]
     
    FlightRisk likes this.
  6. haba

    haba TrainBoard Member

    76
    32
    7
    That 1.5K at the input is designed so that you never exceed 20mA to the 6N137, even if you feed it with 25V. But if you have a lower voltage DCC signal you can calculate backwards from what voltage the 6N137 will not be reliable any more. Per spec it needs 5mA and if you calculate the voltage drops if the 6N137 and the motor shield together 12V motor shield input voltage will get you quite near that limit. This input is not accoring to DCC spec which should tolerate at least 8V to 24V DCC input signal (8V-1.2V=6.8V, 6.8V/1500Ohm=4.5mA). If one lowers the resistot to 1.25kOhm it might be just in range for both low and high DCC voltages. Otherwise a better Optocoupler with a wider current range or additional components are needed.

    Regards,
    Harald.
     
  7. rkmAT

    rkmAT New Member

    8
    3
    1
    Hi all!
    I am new here in the forum and also new to model railroad. So I decided to start digital. I use microcontroller (mostly AVR) since years to develop small projects. So I found your DCC++ EX project which is very intresting and I did my first steps with it. So much to my background.
    For my DCC++ project I use an arduino mega2560 board with wifi and an Arduino motor shield. Contolling the trains works fine but reading CVs was not possible. Ok, I found that my old motor shield I used before the Arduino motor shield did not have an sense output. So I exchanged the motor shield. But reading CVs was not possible. After I sended a read request from the mobile phon or the JMRI software the controler hangs. No answer, no reconnect. Only reset worked. After I putted some debug outputs into the code I located the controler hanged in an endless loop in DCC.cpp in line 642.
    There is a while loop

    while(ackState==2) ackState=DCCWaveform: progTrack.getAck();

    After inserting a simple change to

    while(ackState==2)
    {
    if (Diag::ACK) DIAG(F("\nDEBUG: WACK_LOOP"));
    ackState=DCCWaveform: progTrack.getAck();
    }
    it worked!

    Next step I inserted an delay instead if the Diag and it worked too. But an delay makes no sense here, so I taked a look at the ackPending variable inside the DCCWaveform an I saw the ackPending is not volatile. So I changed this and now it is working.

    I think this is a problem of compiler optimizing. I use VisualStudio Code and PlatformIO with framework-arduino-avr 5.0.0 and toolchain-atmelavr 1.50400.190710 (5.4.0). Is there someone else who had this problem or had heared from it? Maybe ackPending (and some other variables which can change the value witin an interrupt routine) should be set to volatile to prevent compiler optimizings.

    I hope my post here was right. I don't wanted to open a new thread because this thread is named "software thread"

    And please excuse my bad English, hope you can understand what I mean.


    Regards,
    Maik
     
    FlightRisk likes this.
  8. S t e f a n

    S t e f a n TrainBoard Member

    168
    87
    4
    Hi Maik, welcome to Trainboard!
    Usually the authors/maintainers of DCC++EX are pretty quick to reply. I'm guessing they might ask you to also create a new issue (i.e. file a bug report) on github (https://github.com/DCC-EX/CommandStation-EX ).
     
  9. rkmAT

    rkmAT New Member

    8
    3
    1
    Hi Stefan!

    You are right. Maybe I should make a bug report. If it isn't a bug or if only I have this problem then they can close it. But I was wondering that I couldn't find any other in the www with the same problem. Maybe it is only a problem with VSC and PlatformIO. Most people uses Arduino IDE to compile and upload the code. Maybe I will find time to install the Arduino IDE and try it out the next days.

    Regards,
    Maik
     
  10. S t e f a n

    S t e f a n TrainBoard Member

    168
    87
    4
    That's probably true (problem depends on development environment), but if there is an easy way to prevent wrong decisions by the compiler, then that would probably be a good thing.

    Also, I don't know whether you are aware, but besides the 'production' branch there is also a development version 'CommandStation-EX', which looks quite different from the Basestation-EX version. It might be worth having a look at that, if you are thinking of doing some modifications of the software yourself, since, if I understand it correctly, this is where DCC++EX is going.
     
  11. rkmAT

    rkmAT New Member

    8
    3
    1
    Oh I forgot to tell that I cloned and worked with the "CommandStation-EX" from GitHub because in the readme of the Basestation-EX there is a hint "All future development is on the CommandStation-EX repository".
     
  12. haba

    haba TrainBoard Member

    76
    32
    7
    The volatile has been put in. Thanks for finding and the excellent report. I am not that good in analyzing compiler optimizations to decide if the compiler was in error to make this optimization when it was not declared volatile.

    Regards,
    Harald.
     
  13. haba

    haba TrainBoard Member

    76
    32
    7
    There will be a relase "soonish" of Commandstation-EX and the Basestation(s) are history.
    Regards,
    Harald.
     
  14. rkmAT

    rkmAT New Member

    8
    3
    1
    Thank you Harald, also for the communication with you today. I'm looking forward to watch this great project grow.

    Regards,
    Maik
     
  15. pepeONrails

    pepeONrails TrainBoard Member

    14
    2
    3
    I hope this is the right place to ask, as there are some other DCC-EX threads:
    I would like to know where in DCC-EX the pins are declared. In Greggs original this was done in "DCCpp_Uno.h" but there is no such file
    in EX (or I did not find it...).
    The thing is, that I use a Seeduino Motorshield ( see here: https://wiki.seeedstudio.com/Motor_Shield_V2.0)
    which is not pin compatible out of the box and also missing two ICs (CD4077, LM358) which I have separatley wired!
    This looks a bit like a disadvantage, but using variable resistors make it possible to adjust the short circuit threshold or
    to adjust the point when the current should switched off.
    I comes with a big heatsink already mounted. I only use it for driving the main not for programming.
    I have a 2nd assembly for programming which is now running DCC-EX and there are no problems in reading and writing CVs
    which is great, as the original did not read every decoder (for example Piko-Sound-Decoders or miniTrix mtc14)
    So I would like to try it with the Seeduino as well, but therefore I need the pin which are used on the Uno and/or Mega.

    kind regards

    Peter
     
  16. Atani

    Atani TrainBoard Member

    1,331
    1,022
    27
    Unfortunately that motor shield is going to be a problem even with those extra pieces added. There is no current sense by default so you will need to wire that in yourself.
     
  17. haba

    haba TrainBoard Member

    76
    32
    7
    To define an own motorshield do like this:

    1. Copy the standard motorshield definition from MotorDrivers.h to config.h (in front of the motorshield row)
    2. Change STANDARD_MOTOR_SHIELD to MY_MOTOR_SHIELD at all places in config.h
    3. Change the pin values
    4. Change the define of MOTOR_SHIELD_TYPE
    In the end you will have something like this in config,h but with your values:
    Code:
    #define MY_MOTOR_SHIELD F("MY_MOTOR_SHIELD"),  \
        new MotorDriver(3, 12, UNUSED_PIN, UNUSED_PIN, A0, 2.99, 2000, UNUSED_PIN), \
        new MotorDriver(11, 13, UNUSED_PIN, UNUSED_PIN, A1, 2.99, 2000, UNUSED_PIN)
    #define MOTOR_SHIELD_TYPE MY_MOTOR_SHIELD
    
    For more explanation and examples see MotorDrivers.h You can define as many motorshields you want, MOTOR_SHIELD_TYPE chooses the active one. The first MotorDriver is MAIN and the second is PROG track. Currently you can only have one main and one prog but that might change at a later release. Tip: Save a copy of you customized config.h.

    Harald.
     
    pepeONrails likes this.
  18. pepeONrails

    pepeONrails TrainBoard Member

    14
    2
    3
    many thanks for the quick response, but may be I was misunderstood!

    In the original version is a file "DCCpp_Uno.h" and in here are the following lines of code:

    .....
    #define ARDUINO_TYPE "UNO"

    #define DCC_SIGNAL_PIN_MAIN 10 // Ardunio Uno - uses OC1B
    #define DCC_SIGNAL_PIN_PROG 5 // Arduino Uno - uses OC0B
    .......

    #elif defined ARDUINO_AVR_MEGA2560

    #define ARDUINO_TYPE "MEGA"

    #define DCC_SIGNAL_PIN_MAIN 12 // Arduino Mega - uses OC1B
    #define DCC_SIGNAL_PIN_PROG 2 // Arduino Mega - uses OC3B

    ........
    these are the lines I am searching for in DCC-EX
    The Declaration of the pins of the board (Uno or Mega) I want to know,
    because the seeduino-shield can not be attached directly to the board because the pinout is

    D8 OUT1
    D9 Enable of Channel0
    D10 Enable of Channel1
    D11 OUT2
    D12 OUT3
    D13 OUT4

    and the connection "shield to board" is made completely with wires plus external parts (CD4077, LM358)
    to make it work. As an example: pin8 of the motorshield connects to pin10 on the Uno or pin12 on the Mega
    and so on, its all "cross over".... and also needs to be connected to the two ICs for "current sense"
    It works nice witch dcc++(original) but now I would like to "translate" it to DCC-EX
    I thougt a had a foto of my first prototype, but cant find it...

    kind regards
    Peter
     
  19. Ash

    Ash TrainBoard Member

    46
    8
    2
    @pepeONrails I had similar difficulty in updating from DCC++ for another motorboard (not a shield). Perhaps this will help:

    1. Harald explained steps on how to define customized motorboard definitions. It is now done in config.h
    Keeping other files intact and unedited will facilitate updates.​

    2. One of the changes was to eliminate the need for the jumper wires, such as between pin 2 and 13 for the Mega.

    -- for reference, the old method:
    An Arduino Motor Shield (or similar), powered by a standard 15V DC power supply and attached on top of the Arduino Uno or Mega, is used to transform the 0-5V DCC logic signals produced by the Uno's Timer interrupts into proper 0-15V bi-polar DCC signals.

    This is accomplished on the Uno by using one small jumper wire to connect the Uno's OC1B output (pin 10) to the Motor Shield's DIRECTION A input (pin 12), and another small jumper wire to connect the Uno's OC0B output (pin 5) to the Motor Shield's DIRECTION B input (pin 13).

    For the Mega, the OC1B output is produced directly on pin 12, so no jumper is needed to connect to the Motor Shield's DIRECTION A input. However, one small jumper wire is needed to connect the Mega's OC3B output (pin 2) to the Motor Shield's DIRECTION B input (pin 13).
    3. -- from a version of DCCpp.h
    #define ARDUINO_TYPE "MEGA"
    #define DCC_SIGNAL_PIN_MAIN 12 // Arduino Mega - uses OC1B
    #define DCC_SIGNAL_PIN_PROG 2 // Arduino Mega - uses OC3B

    #if MOTOR_SHIELD_TYPE == 0
    #define MOTOR_SHIELD_NAME "ARDUINO MOTOR SHIELD"

    #define SIGNAL_ENABLE_PIN_MAIN 3
    #define SIGNAL_ENABLE_PIN_PROG 11

    #define CURRENT_MONITOR_PIN_MAIN A0
    #define CURRENT_MONITOR_PIN_PROG A1

    #define DIRECTION_MOTOR_CHANNEL_PIN_A 12
    #define DIRECTION_MOTOR_CHANNEL_PIN_B 13

    // ((5/1024)/1.65) * 1000
    #define CURRENT_CONVERSION_FACTOR 2.96 // 2.96 * 100 so we can do integer math later​

    4. -- from CommandStation-EX

    // Arduino standard Motor Shield
    #define STANDARD_MOTOR_SHIELD F("STANDARD_MOTOR_SHIELD"), \
    new MotorDriver(3, 12, UNUSED_PIN, UNUSED_PIN, A0, 2.99, 2000, UNUSED_PIN), \
    new MotorDriver(11, 13, UNUSED_PIN, UNUSED_PIN, A1, 2.99, 2000, UNUSED_PIN)​

    5. I previously used pin 2 (and pin 11) for the program track. Now I use pin 13 (and pin 11).

    @haba Thanks for the instructions on how to update config.h
     
    pepeONrails likes this.
  20. pepeONrails

    pepeONrails TrainBoard Member

    14
    2
    3
    @Ash big thanks for that, it helped to open the knot in my brain... (y)
    @haba thanks for the hint to "MotorDrivers.h"

    so let me resume, and please correct me if I am still wrong:

    There is no such declaration "DCC_SIGNAL_PIN" anymore,
    its all done now in the array in "MotorDriver.cpp"

    MotorDriver::MotorDriver(byte power_pin, byte signal_pin, byte signal_pin2, int8_t brake_pin,
    byte current_pin, float sense_factor, unsigned int trip_milliamps, byte fault_pin)

    which is configured by default in "MotorDrivers.h"
    by
    #define STANDARD_MOTOR_SHIELD F("STANDARD_MOTOR_SHIELD"), \
    new MotorDriver(3, 12, UNUSED_PIN, UNUSED_PIN, A0, 2.99, 2000, UNUSED_PIN), \
    new MotorDriver(11, 13, UNUSED_PIN, UNUSED_PIN, A1, 2.99, 2000, UNUSED_PIN)

    where 3 is the power_pin, 12 the signal_pin, and A0 the current_pin for the main track, next line is for prog track

    And, that was not really clear to me (but now is ...) there is no difference in pins between Uno and Mega.

    And the answer to my "wired" question is somewhat of so easy, I only had to reconnect two wires
    from pin 5 to 13, and from 10 to 12
    I've just tried it, it works nice, and to my big surprise, now it also seems to work on the prog-track
    (just readed a Zimo MX617N succesfully) which did not work before with that Seeduino-shield.
    I also found the foto - looks horrible - works nice !!! seed-shield.jpeg

    So, thanks again and GREAT STUFF that is DCC-EX !!!

    kind regards

    Peter
     

Share This Page