Back in the day, model trains were controlled by varying a DC voltage: low voltage made a train go slowly, higher voltage made a train go faster, and reversing the polarity sent it in the opposite direction. Model trains have since entered the modern era, with digital train control or Direct Cab Control (DCC). DCC works by modulating control information into a steady 12-15V applied to the tracks. Individual trains are addressed by their road numbers (the number on the side of the locomotive), so multiple locomotives can be run on the same track, at different speeds or even in different directions. Trains equipped with DCC decoders can also toggle lights and sounds and other features based on DCC commands. However, modern DCC equipment is proprietary and expensive, in the range of $150+ for the equipment to power and control a few trains.

Thanks to ArTICL, an open-source DCC library for Arduino, and the appropriateness of a graphing calculator as the LCD + keypad for an Arduino, a cheaper alternative is possible. This CalcDCC project is an attempt to build an inexpensive DCC controller that uses a graphing calculator as the throttle, allowing commands to be entered using the calculator's keypad and displaying status information on the calculator's screen. If you already have a graphing calculator with a DBUS (I/O) port, the parts should be relatively inexpensive:
  • LMD18200 motor controller with assorted passive components, ~$10
  • Optional heatsink, <$4
  • Arduino or TI MSP432 Launchpad, $10-$25
  • 5V/12V power supply (often used for external hard drives), or substitute an ATX supply: free-$20

So far, I've been able to control a few features like headlights and set the speed of a locomotive through simple Send(L1) commands on the calculator. I'll add a GitHub link and more information to this topic when I get a chance to work further on this project.

Hey, that's really cool! Does the train report back any information, like position or anything like that? It'd be cool to draw the track on the calc screen and have to show where the train is, too Razz
merthsoft wrote:
Hey, that's really cool! Does the train report back any information, like position or anything like that?
No, the protocol is largely one-way. There's an exception: you can program the decoder on-board the train, to set things like how fast the train accelerates, how its lights behave, what its number is, and so on, and you can also read the configuration values back. However, you can have non-train DCC accessories, including occupancy sensors that report when there's a train on a particular section of track.
It'd be cool to draw the track on the calc screen and have to show where the train is, too Razz
That would be extremely cool.
I've long wanted to do something similar with an RCX and Lego 9V trains. Very cool.
*bump* I spent some time working on this last night on HCWP, and again this morning. I was having problems with calculator communication interfering with DCC commands; the model train would often switch to what appeared to be DC mode (ie, the 12V wasn't getting modulated, so the DCC decoder was assuming that full-throttle DC power was being applied). I solved this by implemented a quick_fail flag in ArTICL's CBL2 emulation library. This flag makes the CBL2 emulator only wait for 100ms rather than 1s for the calculator to start sending a packet, thus allowing CalcDCC to ask the CmdrArduino library to schedule DCC packets to send to any attached locomotives more frequently. With this fix in place, I was able to control the various features that my Digitrax N scale P42 decoder offers. I also explored programming CVs in order to test ditch lights on the P42, but I don't currently know if the CV programming succeeded. I have committed the current state of my code to GitHub:
What's happening on the calculator side? i.e., what format data is being sent to ArTICL? A quick perusal of the repo didn't turn up anything that looked like Basic.
elfprince13 wrote:
What's happening on the calculator side? i.e., what format data is being sent to ArTICL? A quick perusal of the repo didn't turn up anything that looked like Basic.
There are currently four defined list formats:

{0}: Emergency stop
{1,CV_number,CV_value}: Set CV CV_number to value CV_value
{2,feature,enabled}: Set feature number feature to enabled (0/1)
{3,speed}: Set speed to speed

You set a list (eg, L1) to one of those four, then use Send(L1) to send the command. Currently the code only supports hard-coded locomotive ID 3. That will change in the future.
*bump* I found some more N scale tracks lying around, so I made a quick video of CalcDCC controlling my Kato N scale P42 (minus its shell). I demonstrate setting the speed and direction, sound effects, and the ditch and head/tail lights.

merthsoft wrote:
It'd be cool to draw the track on the calc screen and have to show where the train is, too Razz


Is it possible to have the train report back its current speed, and use that to figure out where it is on the track from a set starting point?
caleb1997 wrote:
merthsoft wrote:
It'd be cool to draw the track on the calc screen and have to show where the train is, too Razz


Is it possible to have the train report back its current speed, and use that to figure out where it is on the track from a set starting point?
Ah, a sort of dead reckoning? You certainly know what speed you set for the train, but each train travels at a different physical speed for each speed setting, and the speed also depends on the slope (grade) of the track and the weight of the train the locomotive is pulling. Dead reckoning would probably yield quite inaccurate results, unfortunately.
Put location checkpoints on very small increments on the track, then you will have the train easily tracked on the calculator screen! Good luck! also, it it possible to port this to a monochrome calc?
*bump* Geekboy1011 and I have been looking at an implementation of this for World Maker Faire 2017. Geekboy wants to directly bitbang DCC from 15MHz calculators, specifically starting with the TI-84 Plus C Silver Edition. I so far convinced him that we should use an interrupt rather than cycle-counting, so we looked at the relevant spec. "1"-bits must be nominally 58μs in each of two periods, and can be between 52 and 64μs (ie, ±6μs). Therefore, if we use the "crystal" timer interrupts with the CPU clock, that's 870 cycles for 58μs. Because we know that the calculator's actual clock speed, based on an RC tank, can vary, I ran the numbers, and anything from 16.73MHz (that's 52μs for 870 cycles) to 13.59MHz (that's 64μs). "0"-bits must be at least 100μs in the first of two periods, and 90-9990μs in the second, so we can just wait two of the 870-count interrupts if we're trying to output a 0 bit. More on this soon!

Edit: We used DrDnar's Clock Speed Test program to test Geekboy's TI-84 Plus C Silver Edition. Its 15MHz clock speed is 14.97-14.98MHz, which yields 58.08μs for 870 cycles. Huzzah!
*bump* We put together a quick z80 ASM program to test out an interrupt that toggles the link port roughly every 58us, and tested that it functioned properly on geekboy1011's oscilloscope. We also started throwing our discussion notes on how we should structure the interrupt into a, and put up a nascent repo for the project:
I got pictures Very Happy

So here we have the calculator running a test program we whipped together to see if we can meet the NMRA DCC signaling for sending a 1 bit.

Top trace is the LMD18200 AC switching on the rails. The bottom trace is the IO lines of at Ti-84+CSE. To read out that data, we clock in at 58μs/60μs for our 2 periods needed to signal a 1 bit. Which is nicely in our required specification of a nominal 58μs +/-3μs between the high and low phase periods.
Do you think we need to support the extended packets described in this pdf They have some nice features, but they are not really necessary at all for this project.
I don't think we need to support them right now, but neither do I think we should do anything that would make it difficult to support them later. Right now we've been talking (for the packet-sending code) about just bit-packing the preamble, the data bytes with the stop bits, and the postamble into a buffer, since the bit-sending/byte-sending code doesn't need to know what those bits actually mean. I'd even go so far as saying that for testing, we can just construct a few such buffers manually, so we can focus on testing the bit-sending code first before we add potential bugs in the packet-to-bit code in. Smile
Time for an update! and a reminder you can follow the project at the repository!

We can now send packets! This is an idle packet with a 15bit preamble! It conforms rather nicely to the specification with ~3μs of leeway!

I needed a break from the code after that. Other then being overwhelmed by some functions. So I put together a DCC++ base station So we can program CVs and addresses if the need arises. Was slightly challenging due to the DCC++ having no clear support for the LMD18200, Which happens to be our current motor driver of choice. Some researching and data sheet reading later we learned that the LMD18200 puts out a variable current on the Current Sense pin. Which means with a resistor to ground we can control the output voltage to be within a safe limit for our micro-controller. In this case we wanted a 2.2kΩ resistor. This gets hooked up to the arduinos ADC. Sadly we have no ADC on our calculators that we can use, So we will not be able to ever read values back from trains with out more external hardware Sad

Broken arduino in hand we wired this up. And it worked on the second try...I really need to remember TX->RX RX->TX on serial connections Razz

What is left to go? We need to finish packet generation on the calculator side. So we can send controls to the model trains. We need to craft a UI for the program that fits the requirements of maker fair! I would also like to make a custom PCB for this for the fair. To ease setup and debugging at the faire, However there was some disagreement(?) about making a custom board instead of something arduino form factor. The arguments being, Community/other people use over a specific module for use with the calculator.
On the arduino module, It grants us a known form factor as well as an easy way to interface it with an atmega for the DCC++ base station. It is not hard to tack a 2.5mm headphone jack on it to let it run "standalone"

Doing it standalone does not give us much benefit other then a smaller form factor. Other then that it lets us configure the LMD18200 specifically for use as DCC driver with out question. Where on the arduino it would be a glorified motor driver shield that already exists.

So circuitry wise its not much benefit to make it a single non arduino sheild form factor board. The real reason for my want to make it custom is more of a set of personal opinions?
I am setting up a board fab/etcher here for small scale boards, Making something in shield form is doable but not worth my effort when I do not use arduinos anyway. I wire in atmegas without the arduino. Less components less cost for me. The second reason is, If people wanted to make this project they could use a normal arduino motor shield wired up just like the DCC++ base station. Jumper the 2.5mm cable to the direction pin and they are done. As well as spend the 22$ on the shield and the cost of the arduino module. It should cost about half to turn and build the smaller form factor board if they decide to follow the project and not use the already commercially viable examples.

Realistically I have no problem with making it in an arduino sheild form factor after Maker Faire but for the show I would love to show off some custom PCB work as well as have something non arduino looking on the table, A large reason for me doing this project was the amount of people that call out our arduino/additional micro-controller use. I really want to tell them to bug off Razz

So to finish this up the other reason this came up, I planned on incorperating the atmega into the form factor of the circuit. I know KermMartian and my self both want to make model train setups at sompoint. And using calculators as controllers is exceptionally fitting. But we would still need a way to program addresses and CV's into our trains, Which like I mentioned earlier the calculator can not support reading of CV's so I would not trust it with writing them due to not being able to confirm them. Which the solution is to have an atmega on board for controlling/programming the trains when the calculator controller is not in use. Or if we wanted to do more fancy layout management with a PC.
Geekboy1011 and I were chatting about our projects and I heard him say that he needed a DCC controller front-end, so I thought it would be nice to help him with it. Shouldn't take too long, right?
Wrong. But let's not say anything about it yet :D

About two days ago, I started sketching on a sheet of notebook paper what I wanted to have the interface look like, then I transferred it to to see how it might look an actual screen-sized area. Some things didn't work so I sized them appropriately, added and changed a few more things. I also kept bugging Geekboy1011 about what the interface needs and made changes to it accordingly.
I also really wanted that 7-segment display.

At the end of that workout we got this mockup.

Once I got that mockup, I tore it apart for graphical assets, mashed together stuff that was previously used to compress assets in ScoggerCSE and wrote the code needed to get the app to compile something. After that, I copied over some of the graphics routines from SCSE and wrote a few more to deal with full screen rendering as opposed to the half-res rendering routines I had. More coffee-fueled work on the interface renderer until half-past midnight produced the following.

The display in a powered-off state. This is an actual screenshot.
The color difference can be attributed to the use of the xLIBc palette.
Or screenshotting from Wabbitemu. Or both. I don't know yet.

Late this morning, Geekboy1011 got me set up with the Github thing and walked me through creating a new branch on the repo without accidentally wrecking everything. I also worked on getting the display lit up based on an internal state and got this.

It's lit up with test data. This is also a screenshot.

The next step is putting together an event based system so Geekboy1011 can write routines that subscribes to these events (such as pushing or releasing a key on the numpad, pushing some other key, when some other operation completes, etc.) Then after that? I haven't thought that far ahead. Whatever is needed, I suppose.

EDIT: I wanted to run a test to see how quickly the 7-segment displays can update. The following is the loop code:
   ld hl,0
-:   ld (ctrl.curaddress),hl
   push hl
      call ctrl.UpdateAddress
   pop hl
   dec hl
   ld a,l
   or h
   jr nz,{-}

Geekboy1011 wanted me to post the result.

Blinking lights
This is looking amazing; keep up the good work! I'm thoroughly impressed with the interface, and from what I've been peering at in the backend code, that's also coming along beautifully.
More work went into the application's front-end and now I believe I am finished with it. All that is left to do is to have Geekboy1011 finish his back-end and link it to the interface.
And fix bugs. And add fun graphical features like 7-segment display color config

Since the last post, the following happened:
* Added event loop and made the controller usable.
* Added graphics and routines to make the config menu possible
* Cleaned up and moved around interface code to get the config and controller screens to init properly
* Cleaned up event loop and added config screen controls
* Optimized graphics build for size

Demonstrated in order: (1) App entry (2) Address input (3) Toggling speed steps and DC mode (4) Entering control mode and messing with throttle (5) A bunch of messing around with function keys and function locking. (6) And bank switching (7) Then back to config for more editing fun and to show a change in speed step (8) And back to control to mess with throttle (9) And finally, I quit.

EDIT: The washed out colors in the prior screenshots, as it turns out, was because I forgot to turn the emulator's contrast all the way up.
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 3
» All times are UTC - 5 Hours
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum