Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 22 of 22

Thread: DCC++ for Model Train Control with Teensy 3.x and Teensy 4.x

  1. #1
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    6,730

    DCC++ for Model Train Control with Teensy 3.x and Teensy 4.x

    Decided to port the CommandStation-EX (https://github.com/mjs513/CommandSta...e/TeensyBranch...) library that currently only supports Arduino Mega and Arduino Uno boards to the Teensy T3.x and Teensy 4.x (https://www.pjrc.com/teensy/) and is used for controlling locomotives that use dcc++.
    What is DCC? DCC stands for Digital Command Control. It is a system where digital commands are sent to the locomotives through the rails. DCC is allows independent control of multiple locomotives without complicated wiring, toggle switches or power packs
    With @luni's help, @KurtE's and @PaulStoffregen final fix to EEPROM lib was able to successfully get it ported over.

    I used a custom breakout board that supports Arduino shields and used a Arduino Motor shield with a Teensy 3.5. Loaded the modified software onto the Teensy and then used exWebThrottle on a laptop to test the conversion. This video is the result.

    Why did I do this, basically wanted to see if it would work with the Teensy. For the test I am using a Walthers EMD-60 modifed for DCC in case you are curious.

    In full disclosure I haven't tested with the Teensy 4 yet - not 100% sure the Arduino Motor shield is compatible?



    UPDATES 2/1/21:
    1. @luni's version of the use of timers has been pushed to the TeensyBranch of the my github repository. Next up issuing a PR back to the authors

    2. Saw on youtube that someone created a wireless throttle using HC-12 433Mhz transceivers. So using a Teensy LC that I had I made my own to interface to the CommandStation-EX basestation:


    Basically what you need is:
    1. Teensy LC
    2. 2 HC-12 Transceivers
    3. KY-040 Rotary Encoders
    4. Nextion 3.2in display

    See https://www.youtube.com/watch?v=neMlNHVZWuY for alot more details. I will post my version of the sketch to Github and update this post.
    Last edited by mjs513; 01-31-2021 at 04:09 PM.

  2. #2
    Junior Member
    Join Date
    May 2020
    Location
    UK
    Posts
    3
    This is awesome, I've followed your and Luni's conversation on the TeensyTimerTool threat (not sure if I can include a URL to it)

    I stumbled on the CommandStation-EX project a few weeks ago and thought that even the Arduino MEGA would be struggling if all the features are enabled (Ethernet, Wireless and Display), the Teensy 4.1 is a massive improvement in memory size, cpu power and has the build in Ethernet port.

    I pulled the GitHup repository today from Luni and got it to compile (only the config.h was missing). I haven't got a Teensy-to-Arduino shield, but working on a DCC controller where I can stick a Teensy 4.1 on with the Ethernet port break out.

    BTW if you want to be precise with the waveform, the specs say that a half period of the "1" bit is 58uS and the half period of the "0" bit is 100uS.

    The original DCC++ software used an ISR triggered every 58uS and waited for 2 timer interrupts before toggling the power pin to sent a "0". I read an article in Practical Electronics October 2019 (UK magazine) where they saying that the 116uS (2x58uS) is still within the limits for a DCC decoder in a loco. The article discusses a low power DCC programmer for a programming track by Tim Blythman. the magazine URL: https://www.electronpublishing.com/1019-2/

  3. #3
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    6,730
    Ok a couple things going to be discussed in this post.

    @luni
    Was working on you changes to the lib but for some reason, either the T4 is hanging or the timers are not starting. I successfully compiled and loaded the sketch but the T4 would not accept commands and did not the initial waveforms I was expecting. As a result I reverted the merge of your changes into into my branch and upload my version. Going to work on it again.

    I did verify that the Arduino Motor shield works with the T4 without a problem so was able to test with the loco with my kludge.

    @henkk
    Thanks for the interest. Wondering if it was only me. As you can see from the above comment to @luni I am having trouble with his version which I would prefer to go to in the long run. As to the config just rename it to config.h from config.example.h and make sure wifi is false if you want to play with it. Also thanks for the added info on the waveform.

    EDIT: Also make sure you pull down the latest changes to the EEPROM library. See discussion on this thread: https://forum.pjrc.com/threads/65950...le+definitions


    Here is the link to what I have verified working on the T3.5 and T4.0: https://github.com/mjs513/CommandSta...e/TeensyBranch

  4. #4
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    6,730
    @luni
    Since it looked like it was hanging I added @Frank B's hardfault mod to core to see what we got and sure enough:
    Code:
    Hardfault.
    Return Address: 0x2A41F0E8
    	(IACCVIOL) Instruction Access Violation
    Not sure where to go from here with this error.

  5. #5
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    8,844
    Quote Originally Posted by mjs513 View Post
    @luni
    Since it looked like it was hanging I added @Frank B's hardfault mod to core to see what we got and sure enough:
    Code:
    Hardfault.
    Return Address: 0x2A41F0E8
    	(IACCVIOL) Instruction Access Violation
    Not sure where to go from here with this error.
    Probably best to avoid it

    For lack of better stuff, I would probably start off with things like adding digitalWriteFast or digitalToggleFast at different places in the code to see if you can get it localized down some.

    Don't have the hardware to try it. But could maybe setup anyway?

  6. #6
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    6,730
    @KurtE
    Thanks ... you know me can’t seem to avoid issues like this

    Actually all you need is T4 and a LA on pins 3 and 12. On start you should see pin 3 low and the waveform on pin 12. That’s it. Think I am done for the night .. maybe.

  7. #7
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    13,704
    That address will resolve into a calling function in a .lst or whatever file created during the link.

    or you could try the GDB setup. If using TSET when assembling the COMPILE.cmd just say yes to debug and this line will be added
    >> start "%tools%\GDB.cmd" "%arduino%\hardware\tools\arm\bin\arm-none-eabi-gdb.exe" "%temp1%\%sketchname%.elf"
    or hand edit versus
    >> REM start "%tools%\GDB.cmd" "%arduino%\hardware\tools\arm\bin\arm-none-eabi-gdb.exe" "%temp1%\%sketchname%.elf"

    Last prompt answer 'd' : D :: yes with DEBUG GDB and save to T:\tCode\TIME\GPS_iValTimer\Compile.cmd

    I haven't tried it lately but it worked when I added it.

    Might have to disable the hardfault catcher code?

    GDB should ideally drop into the faulted code to show a stack trace - and maybe var inspection?

  8. #8
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    13,704
    Was wondering is the trained addressed? Can two such trains sit on the same track and act independently?

  9. #9
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    8,844
    @mjs513 - It did not build at when I just downloaded your branch. I was able to get it to build was to copy the conifig_example.h to config.h

    That does not show up as a updated file in github as config.h is in the .gitignore file.

    But not sure if you are using the default settings or if you modified anything.

    I Tried to copy in Franks hard fault stuff, so far have not seen anything.

    I do have pins 3 and 12 hooked up. So far not seeing anything on 3...

    Click image for larger version. 

Name:	screenshot.jpg 
Views:	20 
Size:	19.3 KB 
ID:	23471

    More tomorrow.

  10. #10
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    13,704
    yes - depending on the implementation - multiple trains ...https://dccwiki.com/DCC_Projects

  11. #11
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,422
    Quote Originally Posted by mjs513 View Post
    Ok a couple things going to be discussed in this post.

    @luni
    Was working on you changes to the lib but for some reason, either the T4 is hanging or the timers are not starting. I successfully compiled and loaded the sketch but the T4 would not accept commands and did not the initial waveforms I was expecting. As a result I reverted the merge of your changes into into my branch and upload my version. Going to work on it again.

    I did verify that the Arduino Motor shield works with the T4 without a problem so was able to test with the loco with my kludge.
    Sorry, I was busy yesterday and didn't find time to answer. The reason why it hang was one change you did in Timer.cpp which I forgot to undo. Specifically, you assigned TeensyTimer Tool timers to TimerA, TimerB.... The library then tried to call the VirtualTimer Methods on them which can't work of course. I fixed that, cleaned up timer.h and added a while(!Serial) to the setup(). Looks like it works now.

    Here the relevant code in timer.cpp:
    Code:
    ....
    #elif defined(TEENSYDUINO)
    
    #include "Teensy4X/Timer.h"   
    Timer TimerA(1);   // use the timer numbers to select which timer you want to create in timer.h
    Timer TimerB(2);
    Timer TimerC(3);
    #endif
    And here a super simple example how to use intervalTimers instead of the AVR timers. I'll prepare an example using the TCK - Software timers. They probably are good enough for the rather long (56Ás) signals.
    Code:
    #pragma once
    
    #include "../VirtualTimer.h"
    #include <Arduino.h>
    
    class Timer : public VirtualTimer
    {
     public:
        Timer(int timer_num) {} 
    
        void initialize()
        {       
            if (timer != nullptr) stop();
            timer = new IntervalTimer();
        }
    
        void setPeriod(unsigned long mu)
        {     
            microseconds = mu;
        }
        void start()
        {     
            timer->begin(isrCallback, microseconds);        
        }
        void stop()
        {     
            if (timer != nullptr)
            {
                timer->end();    //this will release the timer, I assume that the lib doesn't call start after stop without initializing.
                delete timer;
                timer = nullptr; // If so -> start would error. In case the lib wants to stop/start something more elaborate needs to be done here
            }
        }
    
        void attachInterrupt(void (*isr)())
        {        
            isrCallback = isr;
        }
    
        void detachInterrupt()
        {
            stop();
            isrCallback = nullptr;
        }
    
     private:
        uint32_t microseconds;
        IntervalTimer* timer = nullptr;
        void (*isrCallback)();
    };
    
    extern Timer TimerA;
    extern Timer TimerB;
    extern Timer TimerC;
    extern Timer TimerD;

    Here the generated signals on pin 3 and 12

    Click image for larger version. 

Name:	Screenshot 2021-01-27 105752.jpg 
Views:	20 
Size:	47.1 KB 
ID:	23473

    Output on Serial:
    Code:
    DCC++ EX v3.0.3<iDCC-EX V-3.0.3 / TEENSY / STANDARD_MOTOR_SHIELD G-9db6d36>
    
    LCD1:Ready
    I sent you a pull request, but since you changed stuff back, my copy was a bit out of sync and you will have merge conflicts. If you want to try my code, simplest probably is to clone the code from my fork: https://github.com/luni64/CommandStation-EX

    Looks like there is a serial interface to control the trains. Is this "human typable" for tests with SerMon?

  12. #12
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,422
    I did find that WebThrottle application to control it. Sending/receiving of commands is nicely logged so it communicates. If I toggle the power off button pin3 gets high. So, looks like everything works as advertised. I can't however judge if the train is doing what it is supposed to do. So, the fun part is with you :-)

  13. #13
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    6,730
    Quote Originally Posted by KurtE View Post
    @mjs513 - It did not build at when I just downloaded your branch. I was able to get it to build was to copy the conifig_example.h to config.h

    That does not show up as a updated file in github as config.h is in the .gitignore file.

    But not sure if you are using the default settings or if you modified anything.

    I Tried to copy in Franks hard fault stuff, so far have not seen anything.

    I do have pins 3 and 12 hooked up. So far not seeing anything on 3...

    Click image for larger version. 

Name:	screenshot.jpg 
Views:	20 
Size:	19.3 KB 
ID:	23471

    More tomorrow.
    Morning @KurtE - @defragster
    The problem I was having with @luni's modifications prior to his latest changes (see post #11). The version I posted was working for me with The T3.x and T4.x. Thanks for checking - at least I now know it works for others as well.

    Ok I am bad - i got my pin numbers backwards. Pin 3 is the Power Pin - goes high when you send "<1>" and low when you send <0>. Pin 12 is the signal pin. Sorry - was answering on my cell phone last night.

  14. #14
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    6,730
    Quote Originally Posted by luni View Post
    Sorry, I was busy yesterday and didn't find time to answer. The reason why it hang was one change you did in Timer.cpp which I forgot to undo. Specifically, you assigned TeensyTimer Tool timers to TimerA, TimerB.... The library then tried to call the VirtualTimer Methods on them which can't work of course. I fixed that, cleaned up timer.h and added a while(!Serial) to the setup(). Looks like it works now.

    Here the relevant code in timer.cpp:
    Code:
    ....
    #elif defined(TEENSYDUINO)
    
    #include "Teensy4X/Timer.h"   
    Timer TimerA(1);   // use the timer numbers to select which timer you want to create in timer.h
    Timer TimerB(2);
    Timer TimerC(3);
    #endif
    And here a super simple example how to use intervalTimers instead of the AVR timers. I'll prepare an example using the TCK - Software timers. They probably are good enough for the rather long (56Ás) signals.
    Code:
    #pragma once
    
    #include "../VirtualTimer.h"
    #include <Arduino.h>
    
    class Timer : public VirtualTimer
    {
     public:
        Timer(int timer_num) {} 
    
        void initialize()
        {       
            if (timer != nullptr) stop();
            timer = new IntervalTimer();
        }
    
        void setPeriod(unsigned long mu)
        {     
            microseconds = mu;
        }
        void start()
        {     
            timer->begin(isrCallback, microseconds);        
        }
        void stop()
        {     
            if (timer != nullptr)
            {
                timer->end();    //this will release the timer, I assume that the lib doesn't call start after stop without initializing.
                delete timer;
                timer = nullptr; // If so -> start would error. In case the lib wants to stop/start something more elaborate needs to be done here
            }
        }
    
        void attachInterrupt(void (*isr)())
        {        
            isrCallback = isr;
        }
    
        void detachInterrupt()
        {
            stop();
            isrCallback = nullptr;
        }
    
     private:
        uint32_t microseconds;
        IntervalTimer* timer = nullptr;
        void (*isrCallback)();
    };
    
    extern Timer TimerA;
    extern Timer TimerB;
    extern Timer TimerC;
    extern Timer TimerD;

    Here the generated signals on pin 3 and 12

    Click image for larger version. 

Name:	Screenshot 2021-01-27 105752.jpg 
Views:	20 
Size:	47.1 KB 
ID:	23473

    Output on Serial:
    Code:
    DCC++ EX v3.0.3<iDCC-EX V-3.0.3 / TEENSY / STANDARD_MOTOR_SHIELD G-9db6d36>
    
    LCD1:Ready
    I sent you a pull request, but since you changed stuff back, my copy was a bit out of sync and you will have merge conflicts. If you want to try my code, simplest probably is to clone the code from my fork: https://github.com/luni64/CommandStation-EX

    Looks like there is a serial interface to control the trains. Is this "human typable" for tests with SerMon?
    Everyone seems to be a slightly different time zones. Its about 5:30am here in NY so got up when I saw your message. Yes you there are commands you can send via serial monitor but I see you found the exWebThrottlle.

    When I did the initial testing of your version I actually had downloaded it from your repository so that was the version I was referring to that was hanging. Anyway - glad its working now and even compiles for T3.5 Please no need to apologize for being busy yesterday, things still need to get done

    As for whether it works. Based on what I am seeing with the waveform and my previous testing it should work. I ordered some new track and should get next week (i hope) and will give it a proper test.

    EDIT: Forgot the most important part - going to go ahead and just copy your files into my branch then push it back up. Easier than trying to resolve conflicts.

  15. #15
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,422
    He, he, working on model trains at 5:30 reminds me of those mornings after Christmas some 50 years ago :-)

    For completeness I uploaded an example showing how to use the TimerTool TCK (software) timers. You can switch between this and the IntervalTimer example in Timer.cpp

    Code:
    ...
    #elif defined(TEENSYDUINO)
    
    //#include "Teensy4X/Timer.h"     // using IntervalTimer
    #include "TEENSY_TTT/Timer.h"     // using TimerTool TCK timers (software timers)
    
    Timer TimerA(1);   // use the timer numbers to select which timer you want to create in timer.h
    Timer TimerB(2);
    Timer TimerC(3);
    
    #endif
    As expected, the waveforms look quite identical.

    The library is quite well designed -> all in all there was not much to change to switch from the AVRs to Teensy with its completely different architecture.

  16. #16
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    6,730
    Tell me about playing with trains. Used to have (actually still have) a whole lot of Lionel O-gauge trains from the 50's and 60's but takes way too much room to set up. So went to N-gauge for my granddaughter a bunch of years ago. Then I started reading of DCC++ so figured I would try it with a Teensy just because.

    Anyways, back to timers. Really cool how you set up Timer.h to interface with TimerTool. Kind of opens it up for other pursposes. And yes = they really did a nice job on library so you could extend it. From here theres all kinds of things you could do. If you want to disconnect the Teensy from the laptop you could put together a separate throttle that uses Bluetooth or even IR if you don't want to rely on Wifi:
    1. https://www.youtube.com/watch?v=neMlNHVZWuY
    2. https://www.youtube.com/watch?v=4sRVuhFi--I

  17. #17
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    8,844
    Quote Originally Posted by mjs513 View Post
    Tell me about playing with trains. Used to have (actually still have) a whole lot of Lionel O-gauge trains from the 50's and 60's but takes way too much room to set up. So went to N-gauge for my granddaughter a bunch of years ago. Then I started reading of DCC++ so figured I would try it with a Teensy just because.
    Great you are making progress and having some fun! For your granddaughter

    As a kid back in similar time frame had my brother and I had a train set, not sure whatever happened to it. My wife did give me a set 3 or 4 Christmas's ago, which I now often setup during the Holiday season.

    I am guessing that not all train setups use DCC? Did you have to buy special engine or the like, or replace transmitter/receivers?

  18. #18
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    6,730
    Morning @KurtE
    You are right not all trains are DCC capable. Some will say DCC ready so its easy to drop in a decoder ($32), which is what I did for one of loco's, digitrak seems to be pretty good. Then of course you can buy loco's that already have them installed but they can be expensive.

  19. #19
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,422
    If you ever come to Germany you should definitely spend a day in the Minatur Wunderland in Hamburg. Here an official advertisement video



    And here more info about controlling the thing (German, but you can activate englisch subtitles) https://www.youtube.com/watch?v=H47g...ature=youtu.be
    Have fun...

  20. #20
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    6,730
    @luni
    That's impressive! Am actually more impressed with the control room - looks like one of those TV control stations or something from NASA.

  21. #21
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    6,730
    Just updated Post #1 with new video and description of a wireless throttle to interface with the CommandStation-EX.

  22. #22
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    6,730
    Evening all.
    Just by way of an update. With the release of CommandStation-Ex version 3.10, Teensy family (T3.2, T3.5, T3.6, T4.0 and T4.1) are officially CommandStation-Ex: https://github.com/DCC-EX/CommandStation-EX

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •