Base Station project (Arduino DUE support)

Quax Apr 13, 2020

  1. Quax

    Quax TrainBoard Member

    27
    5
    5
    Hello!

    Here’s a little project that I started some time ago…

    After building my first DCC++ base station (Arduino Mega plus motor shield) I felt challenged to make DCC++ run on the Arduino DUE. So I have taken the original DCC++ sketch and modified it to include the DUE as a target platform. This was in 2017, after I have subscribed to this forum :)

    Arduino Due - Motor Shield.jpg

    The DUE board has the same form factor as the MEGA but is based on a completely different CPU hardware architecture (SAM8X3E ARM Cortex) which is more powerful and has more memory than the AVR boards. Unlike the UNO and MEGA boards, the DUE is operated at 3.3 volts. This shouldn’t be a problem as long as your peripherals (motor shield, wifi shield, …) are compatible with this voltage. The motor shield that I use (the DeekRobot clone) seems to work well with the DUE (though I still need to test the current sense pin output voltage under overcurrent conditions).
    No experiences with other motor shields / H-bridge drivers.

    Here’s a comparison of the different Arduino boards regarding the most relevant specs (from arduino.cc):

    Board Specs.png

    There are some points that need to be considered when adding support for the DUE to the original DCC++ code (though most of the code is compatible):

    1) Timer interrupts
    Generating the DCC signal heavily relies on the use of timer interrupts. This part of the original DCC++ code is specific to the AVR hardware platform, so we need a modified interrupt macro function that compiles for the DUE target.

    2) EEPROM
    Unfortunately, the DUE’s processor has no built-in EEPROM. DCC++ makes use of the non-volatile EEPROM to store turnout, sensor and output conditions. So another data storage option is needed.

    3) Data Types
    Another difference is that the „int“ data type is 32 bit whereas the AVR „int“ is 16 bit. If for any target a 16 bit int is needed, this can be forced by using the explicit int16_t data type.

    What I have done so far:

    1) DCC signal generation

    Exploring the timer section in the SAM3X8E processor handbook, I could find the relevant information needed to set up and use the two timers for the main and programming track signals. There are 9 individually usable timers available (3 timer counters, 3 channels each). Having this plenty of timers, we can chose the timer signal lines directly connected to pins 12 and 13 of the DUE board which are linked to the direction inputs of the motor shield so that jumper wires (like in the UNO or MEGA setup) are not needed.

    Hardware specific code to support the Arduino DUE:
    - Timer setup: DUESupport.h.
    - DCC macro function: DCC_SIGNAL(R,N) in DCCpp_Uno.ino
    - Interrupt handler: void TC8_Handler() and void TC0_Handler() in DCCpp_Uno.ino

    2) Substitute for the missing EEPROM

    The missing EEPROM caused me some headache. Searching the web, I found several ideas/options to cope with this problem. These are:

    a) Using the internal flash memory (where the DCC++ program is stored in machine code):​

    No hardware additions (external memory) required, this way in the philosophy of the project. Unfortunately, all stored data will be lost when a new sketch (update) is uploaded to the board. However, implementing a flash storage option is possible.​

    b) External EEPROM via I2C:​

    This was my first approach but I don’t really like it. I have connected a 256 kbit (32KB) EEPROM module via I2C bus (4 wires) to the DUE board, took the EEPROM AVR library and modified it to use the (DUE’s) wire.h library for reading and writing the external EEPROM through the I2C bus. Acceptable in terms of hardware additions but deteriorating the system performance as writing to the external EEPROM through I2C is rather slow-speed and needs some delays between the individual bytes transferred.​

    c) External FRAM:​

    FRAM (Ferroelectric RAM) is another option and it is my favorite. FRAM is faster than EEPROM and Flash and it’s way more durable in terms of write cycles. FRAM modules for Arduino projects are available from Adafruit. These modules are populated with a FRAM chip, one or two resistors and a capacitor and are available in I2C and SPI bus versions. SPI is the best choice as it’s very fast. My Adafruit SPI FRAM board (64 kbit) operates @ 20 MHz max, but you can also find larger capacity FRAM chips with higher bus speed. The connection needs 6 wires: Vcc, GND, MOSI, MISO, CLK and CS (chip or slave select). I have added a wiring diagram to the files @ GitHub.​

    SPI FRAM support: DUESupport.h. ​


    Considerations about SPI for future extensions:

    Once you have brought SPI under your control, this hardware interface could be used to connect other peripherals than FRAM. The DUE board has 3 slave select pins (4, 10 and 52) that can be used for hardware SPI transmission which is supported by the extended SPI library. All three SPI connections can be operated with individual parameters (speed, data mode and bit order), so that you could add additional SPI devices like an OLED display, RTC or the like.​

    On the picture of my base station you can see the rainbow-colored SPI bus coming from the DUE board to connect a RTC module, FRAM module and an OLED display which is mounted in the front plate. For the moment, the source code does only support FRAM storage.​

    3) RailCom/BiDi cutout (experimental)

    I have tried to create a cutout in the DCC signal using the motor shield’s brake feature (to short-circuit the track). This requires intact brake traces on the motor shield. The relevant code can be found inside the DUE-specific ISR macro function.

    In the sketch, the experimental cutout feature is deactivated by default but it can be activated in RCom.h. Be careful when experimenting with this option.

    For the moment, there’s no detector hardware or code to read back loco responses. RailCom specs and a detector design can be found here.

    Arduino sketch:

    You can find the sketch here: http://github.com/Quaxx/BaseStation


    Does it work?

    For the moment, this is experimental stuff. When using the sketch on a DUE board without FRAM then data storage and retrieval operations will have no effect.

    It’s a little difficult for me to do extensive testing without having a real layout on hand. All that I have available is what you can see on the picture: a base station that I have built around the Arduino / Motor Shield combination, a homemade test board (including a decoder tester and Loksound decoder) and a scope.

    Test Board.jpg

    Within the limitations of this setup, I can drive a „loco“ and control decoder functions (lights, sound) from JMRI using the sketch.

    Also, reading and writing CVs on the programming track is possible.


    From my to-do list:

    - adding some yet unsupported functions to the DUE-specific code, like the <D> command (diagnostic mode).
    - general review of the code
    - maybe internal flash storage option
    - RailCom support


    I hope to find some time to proceed with this project.
     
    lnxlnx likes this.
  2. David Cutting

    David Cutting TrainBoard Member

    62
    29
    3
    Excellent work! I'm really interested in this as I'm just starting to work on porting the current DCC++ code to a SAMD21. I will definitely reference your code!
     
  3. Quax

    Quax TrainBoard Member

    27
    5
    5
    Good to hear that this is interesting for you. Maybe there are some similarities between both chips.
    I will take a look at the SAMD21.
     
  4. FlightRisk

    FlightRisk TrainBoard Member

    453
    158
    6
    I have never seen anything neater than that control box! Have you documented this somewhere? Looks like you even have a temperature sensor next to the power brick.

    Due support could easily be added to DCC++ EX with another ifdef as we have for the Uno, Mega and Nano, but as you say, the lack of EEPROM is an issue if people need that feature. Good luck with the project!
     
  5. Atani

    Atani TrainBoard Member

    1,329
    1,010
    27
    For the Due, you might consider using https://github.com/sebnil/DueFlashStorage... It may make sense to move the DCC-EX code to use an abstraction layer of sorts so this can be swapped in easily without needing a ton of ifdef/else/endif blocks around all usages of EEPROM.
     
  6. RCMan

    RCMan TrainBoard Member

    255
    112
    9
    I use my DCC++ using JMRI.
    JMRI stores all my data and I do not use the EEPROM to store my turnout, sensor and output conditions.

    Am I missing something else the EEPROM is needed?
     
  7. FlightRisk

    FlightRisk TrainBoard Member

    453
    158
    6
    @RCMan I suppose the only difference is where the information is stored. If you aren't using a front end that saves all the information, when you unplug the Arduino, it's all gone. JMRI also reads the information at boot from EEPROM if you like and gets anything that was setup not using JMRI.

    If you could help me, since I am still learning JMRI, what are the exact steps you use to set up a sensor? And is it internal or on the DCC++ tab? I was going to try to look at the JMRI code, but I am wondering if you save a sensor in JMRI, does it store it in its table and then every time it boots up, it writes that whole table to DCC++?

    One thing that got me confused was that one way, it asks me for just an ID and a name (which I think is when it thinks you are trying to find a DCC++ sensor to match) but another time I hit the add button, it asks me for the pin. So I think that is where it is bypassing DCC++ and controlling the pin itself? And if that is the case, then maybe it never writes to DCC++ at all when IT is directly monitoring a pin? I'll try to look at the raw monitor because if it saves the sensors to DCC++, I should see <Q..> and <q..> messages when I trip and untrip the sensor.
     
  8. RCMan

    RCMan TrainBoard Member

    255
    112
    9
    I do not use any of the DCC++ Commands except rarely the ON/OFF. JMRI saves everything it the Tables including the Senors, Blocks,Reporters, Signal heads and Masts, etc,. It you add sensors to the Mega that should be accessible from JMRI. I have not tried that. I usually purchase Block occupancy modules and (Current Detection) it gives me everything I need. JMRI handles that well.
    First off I am not an experienced JMRI user, but learning. The documents and videos available I rate between 2.0-3.0, they always think you know it already and omit explanations needed for new users.
    I do not think JMRI writes anything to the DCC++, it just thinks it is a Command Station that all.

    JMRI handles the ID conversions for you.

    Dennis
     
  9. Jimbo20

    Jimbo20 TrainBoard Member

    274
    175
    9
    I don't use JMRI but as regards sensors this is what I guess it does;

    It programs up the BS station pins using the <S..> command. This allows the BS to send <q..> <Q...> when sensor change state.

    However, I presume JMRI does not make the BS save the sensor settings to EEProm by using the <E> command, therefore JMRI will need to set up all the sensors again next power up using <S..> commands.
     

Share This Page