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

Gregg Aug 25, 2015

  1. Gregg

    Gregg TrainBoard Member

    237
    311
    18
    Yes, the output and communication is identical. Same code is used regardless of connectivity. The compiler simply chooses either Serial.print() or eServer.print() during the build process (where eServer is a variable declared as an EthernetServer).
     
    TwinDad and Scott Eric Catalano like this.
  2. Scott Eric Catalano

    Scott Eric Catalano TrainBoard Member

    205
    57
    6
    Now a question comes to mind is this: are the parameters the same no matter which type of ethernet shield is used? Or will we run into the same issue as the motor shield? I have a knock off ethernet shield sitting here....and I do plan on getting the Arduino ethernet shield with logging capabilities etc.
     
  3. Gregg

    Gregg TrainBoard Member

    237
    311
    18
    Most of the parameters are likely the same since most network shields use the SPI bus (which is connected to pins 50-53 on the Mega). However, there may be additional components, such as an SD-Card reader, which might use additional pins. It was the SD-Card on my SEEED Studio shield that was interfering with pin 4 and caused me to switch the Prog Track signal to pin 2. I believe the Arduino Ethernet Shield uses identical pins and also has an SD-Card reader.

    Note that use of the Ethernet Shield is only for the Mega, at least at this time. I think the Uno may max out it's memory if you tried to run DCC++ and an Ethernet Shield at the same time (though I have not yet tried). The main stumbling block to using an Ethernet Shield with an Uno are the pins. On the Uno, the SPI bus uses pins 10, 11, 12, and 13. These interfere with both the Main Track signal generation as well as the Motor Shield direction pins. However, if memory is not an issue and you find you can run both DCC++ and Ethernet code within the Uno (remember, it's not just about sufficient Flash Memory for the code, it's also about dynamic SRAM used to run the code itself), then DJ79's update that allows you to use different pins for signal generation may be the solution.
     
    Scott Eric Catalano likes this.
  4. TwinDad

    TwinDad TrainBoard Member

    1,844
    551
    34
    There is also a Bonjour library that could be used to advertise the Base Station's presence. I haven't been able to get it to work properly yet... but I will need to if I want the WiThrottle interface to work at its best...
     
  5. TwinDad

    TwinDad TrainBoard Member

    1,844
    551
    34
    (duplicate post)
     
  6. Scott Eric Catalano

    Scott Eric Catalano TrainBoard Member

    205
    57
    6
    I haven't had an issue of running out of memory with an Uno yet....I've crammed alot into it....I've got one Uno running the DCC++ interface and with no issues at the mall show....and I have another Uno running my signal system using photo resistors. I would like to try using JMRI however I will just wait until TwinDad is done refining it and when it's released in a stable version of JMRI.
     
    ClassiCut likes this.
  7. Scott Eric Catalano

    Scott Eric Catalano TrainBoard Member

    205
    57
    6
    And by the way....you can connect several Arduinos together to expand your operations in a Master/Slave type configuration by connecting pins A4 and A5 to the same pins on the second arduino and using a jumper wire to connect to both grounds.
     
    ClassiCut likes this.
  8. DJ79

    DJ79 TrainBoard Member

    36
    25
    14
    Hey, Gregg, there are more ways in which DCC signal can be generated. I was looking at how to most easily enable the shield that I got, and before I did it using timer interrupts, I considered using the same compare B interrupt, but slightly differently: set the counting mode to count up to 255 (assuming an 8-bit counter), and load both CompareA and CompareB with the same value. Assuming 1:64 divider at 16MHz as in the current version, load both compare registers with either 255-14 for a short pulse (58us), or 255-24 for a long pulse (100us). Configure both to toggle on compare and on overflow, just as in the current version, but set one of them to invert, and enable the overflow interrupt. Pay attention to double buffering, or lack thereof for this counting mode (I'd need to study the datasheet again to find out). We may need to enable both interrupts if we do have double buffering. In the ISR we update the two compare registers if needed (if changing pulse duration), and we also update the counter value itself. Since the counter is a moving target, we ADD to the counter, instead of just assigning the value. The value we add is 255-28 for a short pulse, or 255-49. Again, check the datasheet; these values might be off by 1 (we may need to account for overhead). What I just described is similar to a standard procedure on the PIC, where the timers are nowhere as feature rich as on the Arduino. This way we can get the DCC signal and its invert at the same time with only two compare registers. The downside is that we still need jumper wires.

    Another technique would be to do the the same basic approach as in the current version: toggle on Compare B, toggle and reset counter on Compare A, but instead of an interrupt on Compare B, setup interrupt on pin change. Then in the pin change ISR write to the output pins. This works even if the Compare B pin is set as an input (which is safer at it prevents accidentally shorting unused pins).

    On a different note, if you're doing many things that require interrupts, here are several techniques that you can use regardless of which method of generating DCC signal you're using:

    - Make the ISRs reentrant, so that other events can interrupt the currently running ISR. You do this by setting the global interrupt enable flag using the SEI instruction, or, in C++ by writing asm volatile ("SEI");, or just sei();, or interrupts();
    - Even better, make the ISRs reentrant and extremely short, e.g. just set a flag, and then take care of it in the main loop. DCC signal generation is timing critical; other stuff is not nearly so.
    - Better yet, don't even use interrupts. In many cases, the hardware itself will set interrupt condition flags. Just check for the condition in the main loop, and then reset it to catch the next event.
     
    Scott Eric Catalano likes this.
  9. TwinDad

    TwinDad TrainBoard Member

    1,844
    551
    34
    Hey... another suggestion...

    We have a protocol for using the Arduino's GPIOs as inputs (sensors)... how about adding the inverse -- control them as outputs?

    I just submitted a pull request that adds a bit of code to Sensor.h/cpp to allow a Sensor to be defined as an Output and driven high or low.

    New commands are:
    <S ID PIN DIR PULLUP> : Define output or input pin. Reply: <O> or <X>
    <S ID PIN PULLUP> : Define input pin (same as before). Reply: <O> or <X>
    <S ID VAL> : Write VAL to pin. No reply (see below)
    <S ID> : Delete definition. Reply: <O> or <X>
    <S> : List Sensor defs. Reply: <Q ID PIN DIR PULLUP> or <X>

    The Write command is ignored for Sensors not defined as OUTPUT. The Write command doesn't generate a direct reply, but the resulting change in pin state will generate a <Q/q ID> message automagically. If you write the same value to a pin twice, there's no state change, and no response.

    I suppose a further tweak would allow a pin to be defined as a bidirectional IO, just allowing a third value for DIR. I may add that in a bit.
     
    Scott Eric Catalano likes this.
  10. w8one

    w8one TrainBoard Member

    89
    109
    5
    Wouldn't a output be a switch (turnout) or a signal (lights)? Maybe Call the pins you want as outputs Accessories or Signals, but not sensors to avoid confusion. Still using the same format you described above just with a different command letter.
     
    Last edited: Dec 2, 2015
  11. RossNZ

    RossNZ TrainBoard Member

    12
    12
    5
    HI,
    Today is a good news and a bad news day....
    Good news..... Arduino motor shield arrived in the letterbox.
    Bad news.... #error CANNOT COMPILE - DCC++ ONLY WORKS WITH AN ARDUINO UNO OR AN ARDUINO MEGA 2560

    oh dear, back to waiting for the Postie to deliver a MEGA2560 to replace my MEGA1280



    Ross
    NZ
     
  12. TwinDad

    TwinDad TrainBoard Member

    1,844
    551
    34
    They should be called something else, probably, but...

    Both Accessories and Turnouts, as presently implemented, have a DCC address and send a DCC message out on the bus to affect the change.

    The change I proposed allows the user to directly control the Arduino's own GPIOs as outputs.

    It was simplest to implement (at least prototype) as an extension of the Sensor (which already deals directly with the Arduino IO), but a different name or different implementation would be fine.

    The idea was prompted by a guy who is looking to use <something> to be the guts of a CTC panel, with switches and lights. It occurred to me that if I could get to the Arduino IO as outputs, the whole thing could be done with a DCC++ Base Station, just ignoring the motor outputs (or using them, too!)
     
  13. w8one

    w8one TrainBoard Member

    89
    109
    5
    I like the idea of using the extra pins on the mega2560 as much as possible. My plan is to use the 30a current sensors ( http://www.ebay.com/itm/181811914122 ) as block detectors on the track but i was not sure what would happen if i set it up wrong and sent +5v to it. I'm thinking about using TLC5940 ic's for leds ( https://www.sparkfun.com/products/10616) they can also be used for servos too.
     
  14. Gregg

    Gregg TrainBoard Member

    237
    311
    18
    Query for the group: unlike turnout status, sensor status is not saved when the power is turned off to the Arduino. This is because as soon as power is restored, sensors will trigger according to the current environment (i.e. a sensor is indeed covered by a train).

    Would it be useful for the state of output pins to be saved in EEPROM in the same way as turnouts. On my own layout I have added an extra <z ID> command that controls miscellaneous functions, including outputs. I could add this into the current buildup in a similar way that sensors are used, but for outputs instead, and where the state is saved in EEPROM.

    Thoughts?
     
  15. TwinDad

    TwinDad TrainBoard Member

    1,844
    551
    34
    Gregg...

    See posts 229 and 232... I have no problem with you adding a <z> command for outputs. Saving the state would be good, though. I would think outputs would need to be restored on POR.

    If you're going to do it, and you can do it (or at least spec out the commands) tonight, that would be good. If I don't get the corresponding JMRI changes in to 4.1.5 this Saturday, it will be January (4.3.1) (or at best Christmas) before JMRI will support it.
     
    w8one likes this.
  16. Gregg

    Gregg TrainBoard Member

    237
    311
    18
    How about:

    <z ID STATE> sets the state of output ID to STATE where STATE is either zero, for low, or one, for high.

    Base Station will return <Z ID STATE> upon completing the operation. The only difference between send and receive is uppercase versus lowercase "z".

    Defining an output will use same protocols as for the sensors except that to create an output there are only two parameters: <Z ID PIN>. There is no pull-up parameter since that's not applicable for an output. The other edit/delete commands and their responses will be the analogue of the sensor procedures.

    State of the output will always be saved in EEPROM. Upon power-up, the state of each output will be set accordingly to the value in the EEPROM. These states will be added to the status <s> command and returned along with state of the turnouts.
     
  17. TwinDad

    TwinDad TrainBoard Member

    1,844
    551
    34
    Sounds good.

    But they closed up 4.1.5 early on me (it's already on lock-down-and-test), so I don't know if I can get this in. I will try to squeeze it in for 4.1.6 as a "minor update".

    Just so I'm clear...
    From JMRI: <z ID STATE> --> change the state of a pin.
    From BS: <Z ID STATE> --> Response confirming new pin state.
    From JMRI: <Z ID PIN> --> Define an output pin. Response <O> or <X>
    From JMRI: <Z ID> --> Delete a pin definitions. Response <O> or <X>
    From JMRI: <Z> --> List defined pins. Response... <Z ID STATE> (x N outputs).


    In other news... it just occurred to me that a JMRI-connected Base Station can use almost any other manufacturer's throttles (Digitrax, NCE, MRC, Lenz, ...). Sweet!

    At the rate this is growing, if I can decide on a big enough motor driver, I may actually make this thing, along with a Raspberry Pi/JMRI setup, my primary DCC command station.
     
  18. Gregg

    Gregg TrainBoard Member

    237
    311
    18
    You are correct on the commands above with one small exception. A <Z> command will return the defined pins in the form <Z ID PIN> since that's the actual output definition. The status <s> command would return <Z ID STATE>, which, now that I write this, won't work because you won't be able to tell the difference between these two returns. Perhaps we should use a different letter for the return of the output STATE, just as we use a different letter for turnouts and sensors. How about <Y ID STATE> ?
     
  19. TwinDad

    TwinDad TrainBoard Member

    1,844
    551
    34
    Why can't the command response use a lower-case z?

    So <z ID STATE> returns <z ID STATE>

    and <Z ID PIN> returns <Z ID PIN>

    ?

    Otherwise, yeah, Y is fine.
     
  20. Gregg

    Gregg TrainBoard Member

    237
    311
    18
    I chose to use different letters for the responses for really old historical reasons (now I'm really dating myself). It was quite common for serial connections to have a default mode that echoed back whatever was sent. This was often used for terminals where if you typed an 'E' it would send that letter to the mainframe but you needed to also turn the echo on to see it print on the paper or screen. Today's serial communication is still based on that protocol. So to make sure the Base Station was really receiving and processing your command, instead of the serial protocol simply echoing back what you sent, I used different letters for the return commands.
     

Share This Page