DCC++Arduino: Bare-bones DCC++ generator

Travis Farmer Mar 8, 2018

  1. WillemT

    WillemT TrainBoard Member

    55
    40
    7
    I must admit I did not look at the rest of the ATtiny range. There are quite a few. The processors seem to be the same over the range - maybe I am wrong on that one. There seems, however, a large difference in the peripherals. It is good to know about the UARTS in the 841. I notice my Arduino IDE ATtiny extension even allows the use of an Opti bootstrap loader for it.

    My problem is that when I looked at the possibility to stay with a serial string, I found it impossible to use any of the sprintf or sscanf instructions - the memory footprint is in excess of 2.2k, ie about 27% of available memory. So, if you can write a more economical unpack routine for string to integers - great. Otherwise, I do not think you are going to get DCC++ to fit into 8K. Also strings tend to be larger than what I use at present. Memory is a problem if you are trying to pack in features and strings are memory hogs.

    The 841 does have two 16 bit timers though. You can keep the original code using those. The "High Speed" 8 bit timer in the 85 is great - you can set the exact usec timings. Another difference I picked up is that you will need to add an external crystal or resonator to get 16MHz with the 841 while the 85 can get that with the internal 8MHz oscillator.

    In the end I assume it is what you are aiming for. Price-wise they are practically the same (from my source in any case). I am quite enjoying the challenge of getting a usable system set-up with just these small 8-pin processors and one or two logic chips. Looking forward to see what you manage.

    Willem.
     
    Scott Eric Catalano likes this.
  2. patrick_martin

    patrick_martin TrainBoard Member

    23
    27
    7
    The 841 can also get away with the 8MHz internal (I have a couple 1614 and 1634's here just in case it can not fit)

    I also prefer to find an integer based solution over sending text. Text can be sent out to the Serial Debug when dealing with the throttle or debugging, but I don't think there should be a need for the throttle to send "encrypted" to the Base Station. I mean, why not send from the throttle exactly what the Base Station is going to put onto the lines - freeing space and cycles from the Base Station.
     
    Scott Eric Catalano and WillemT like this.
  3. WillemT

    WillemT TrainBoard Member

    55
    40
    7
    That is what I do by sending a struct (only I send using I2C). For example throttle is send as:
    Code:
      I2Cdata.Code = 't';
      I2Cdata.byteData = currentLoco + 1;                 // DCC++ register
      I2Cdata.intData1 = Locos[currentLoco].LocoSpeed;    // Throttle setting
      I2Cdata.intData2 = Locos[currentLoco].LocoAddress;  // Cab address
    
    Speed is send as -ve for reverse and +ve for forward. Saves a variable, only two bytes and two ints, a total of 6 bytes.

    Willem.
     
    Scott Eric Catalano likes this.
  4. WillemT

    WillemT TrainBoard Member

    55
    40
    7
    I just had a look at those 1614 and 1634 processors. I like the 1614 - up to 20MHz, 16Kb flash and just over halve the price of the 841 or 85 (in packs of 10). Only problem is I do not have the 1614 available as a board in the IDE.

    Willem.
     
    Last edited: May 7, 2018
    Scott Eric Catalano likes this.
  5. patrick_martin

    patrick_martin TrainBoard Member

    23
    27
    7
    ... and t would be an integer ... 116 or 0x74, so strings maybe can be eliminated
    in a text throttle
    < 60 starts,
    t 116 type,
    'space' 32 commit byte, inc paramcount, zero value=0
    >62 ends
    for numbers as params -
    value = value * 10 + (byte-48)

    But your structure still isn't down to bare native values for hitting the wire
    I am digging in to the code ...
     
    Scott Eric Catalano likes this.
  6. patrick_martin

    patrick_martin TrainBoard Member

    23
    27
    7
    start.atmel.com looks like it can handle the 1614, personally hoping Arduino has an updated core ... somewhere
     
    Scott Eric Catalano likes this.
  7. WillemT

    WillemT TrainBoard Member

    55
    40
    7
    Maybe. "char" - "byte", sizewise the same. The struct:
    I like to keep the char. It makes it easy to read and reference back to the original.

    Willem
     
    Scott Eric Catalano likes this.
  8. WillemT

    WillemT TrainBoard Member

    55
    40
    7
    Just a quick progress update.

    After sorting two problems on the software side, entirely of my own design, everything now seems to work as intended.

    I am using both sides of the Dual Motor Bridge, L298N, as per the original. However, due to various limitations of the Tiny85, there is only one available timer for the DCC signal. This is therefore fed to both sides of the bridge. Side A is used for Main and side B for Program. Only one can operate at a time. This is handled as follows.

    A slide switch is used to select between Main and Programming (less likely to be switched by accident). The switch enables either side A or side B when track power is turned on. When in "Main mode" only Throttle, Loco Function and Writing CVs on the Main instructions can be sent to Side A. When switching to "Program mode", only Reading and Writing CVs to the Programming track can be issued to Side B. Also, when changing "Mode", the controller sends a "mode change" instruction to the Base Station. This works as follows.

    On receiving a change to Programming mode, the Base stations does the following:
    1. If enabled, turn track power off.
    2. Turn off Timer Match interrupts, effectively stopping the DCC signal.
    3. Clear and initialize all registers. This prevents any possible Throttle packets to be sent to the Programming track.
    4. Load an Idle Packet into register 1.
    5. Re-enable the Timer Match interrupts. This now sends idle packets to the Programming track providing a DCC signal to it.

    The Controller also enables side B of the Motor Bridge. So, when track power is turned back on, DCC signals are sent to the programming side.

    It is assumed we have allocated an isolated piece of track for Programming on the layout. A DPDT switch connects Main (Side A) or Programming (Side B) to this Programming track. This prevents any Programming signals from being accidently sent to the Main, programming all locos parked there. A Loco can be driven onto the Programming track in Main mode and then switched to programming, isolating the Main.

    Switching back to Main does not require any change on the Base Station side. We just send the currently selected Loco's throttle setting to it.

    All currently operates as designed, which not necessarily implies as it should.

    Willem.
     
    Last edited: May 25, 2018
    Scott Eric Catalano likes this.
  9. WillemT

    WillemT TrainBoard Member

    55
    40
    7
    A small update.

    With everything seemingly working, I laid out a PC Board and finally have version 4 working. The first was marred by some dirt in the resist (I am using pre-sensitised boards), the second I have left the unused half of the dual op-amp floating which is, after checking the web since it did bother me, not a good idea. I ended up using it to buffer the on-board DCC led. The third, after soldering the entire thing, had a problem on the board layout. Since these are homemade boards, I do not have plated through holes. I solder wires to join the sides for vias. I can solder both sides of header pins but not screw connectors. Those need to be soldered on the bottom and I did not allow for that on one of them (the one for the 5V power). I finally gave up trying to save the board and made a new one. (With all the soldering and drilling I am getting quite good at it).

    Everything works as planned. I do however have one problem which I have not been able to solve. Maybe someone here, knowing more about op-amps, can give some advice.

    With no current flowing, track power off, I get a sense current reading of 8. That translates to about 25mA. With track power on, and a load, it does read and display a sensible reading and trips as expected with a short. I can also read CVs when using the programming side.

    Here is what I have done to try and get to the bottom of this.

    After checking everything physically and program wise, I removed the op-amp (I am using a dual LMV358 - all SMD). I soldered a wire to the pin 1 pad (feeding through to the ATtiny pin 3 - ADC 2) and connected it to ground and various voltages using a resistor divider. Grounding gave the expected zero reading and all other voltages gave the correct readings. The ATtiny seems to be OK.

    I soldered in a new op-amp and am back to 25mA.

    The op-amp is wired with 10k from output, Pin1 , to inverting input, pin2. Pin 2 is also connected to ground with a 1K resistor. Sense voltage is connected to the non-inverting input, pin 3. This gives a non-inverting amplification of 11. Chip ground and power is correct.

    Pin 3, the non-inverting input, reads practically 0V as it should with no current flowing through the sense resistor. Pin 1, the output, reads about 45mV. If I measure between pins 2 and 3, the inputs, I get a reading of about 4.5mV difference - my understanding of a non-inverting amp is that these pins should be at the same potential (or very close). Any ideas?

    Willem.
     
    Scott Eric Catalano likes this.
  10. SP_fan_1951

    SP_fan_1951 TrainBoard Member

    93
    86
    6
    You are seeing the minimum output voltage for the op-amp. To truly get to 0V out, you would need the negative supply to be -.25 or lower. If you are using a 3 terminal regulator for your 5V supply, you can put a forward biased diode in the ground leg of your regulator, draw your 0V voltage from above the diode, and your -V supply for the op-amp from below the diode, giving you a little bit lower output voltage. Another option is to sum a fixed 1V offset into the input of the op-amp, and calibrate your circuit for 1V = 0mA.
     
    Scott Eric Catalano and WillemT like this.
  11. WillemT

    WillemT TrainBoard Member

    55
    40
    7
    Thanks for the input. I am currently reading all I can find about op-amps.

    I like the idea of the diode to ground for the voltage regulator, I am sure I will use it at some stage. For this application I do not think the effort to fix this is worth it. I might just live with some sort of zero base reading, it does not seem to effect the general operation. The DCC++ code does cater for an offset on the sense voltage.

    Willem.
     
    Scott Eric Catalano likes this.
  12. WillemT

    WillemT TrainBoard Member

    55
    40
    7
    A small update.

    Reading a lot about op-amps on the net I think I now have a reasonable understanding of how they work and their limitations. My observations and measurements for the LMV358 fall in line with the specs for the device.

    I measured about 4.3mV across the inputs at different input levels, which leads me to believe I am seeing pretty much the input offset. I know this is not the way it is measured but the difference is constant. Specs says up to 7mV. This gives around 48mV output after 11x amplification, this then being the lowest level I see with zero input. This translates to a minimum reading of 26mA with track power off.

    To check my conclusions I ordered a better amp - the NCS2333. They are not the best available but already expensive enough. The specs say max 30uV offset for the dual and much closer to the rails output swing. The LMV358 sells for around 30 US cents and the NCS2333 about US $2 in lots of 5 - a big price difference. The next level up is way out of price range for me.

    I swopped the chips and am getting 0mA with track power off - a lot more acceptable. I connected my vintage (1981 Fluke 8021B) DMM in-line with the 12V input and checked readings. They matched pretty well up to about 600mA where the DCC reading started showing progressively higher than the DMM. I do not know why, or which is wrong, but it does not really matter at that point.

    Is it worth the price difference? I suppose it depends on where and what you expect from it. As a follower/buffer to switch LEDs the 358 is fine. I would also use it as comparator to switch a MOSFET like in power supplies - see UNO usb control. As an amp for small voltages, like with the L298 Dual Bridge current sense, I think I prefer a more accurate amp. I like to see more correct small currents for the following reason.

    I re-connected my flex track to the decoder's motor outputs - I am on N-Scale. Running my mid 1970 Minitrix loco, it starts moving at about 75mA (quite slow but not exactly a crawl) and reads 235mA at max speed (step 244). This seems to be in line with what I have seen on forums. This loco is probably not even run in yet and also needs cleaning and lubrication after more than 40 years (it has never been opened). Next I tried my new Gaham Farish Princess Coronation Class "City of Bradford" (what a beautiful loco - it is still DC). It starts at about 8mA and draws 43 at max speed. Both were run on level track pulling two small coaches. The low current for the Coronation is one of the reasons a 26mA base current is not quite acceptable.

    Willem.
     
    Last edited: Jun 14, 2018
    Scott Eric Catalano likes this.
  13. WillemT

    WillemT TrainBoard Member

    55
    40
    7
    A follow up.

    I finished the CPU board, cleaned and painted it. I then found a white speck of something between and behind pins 9 & 10 of the 74HCT02 Quad NOR gate chip. I cleaned it out, using a pin, and repainted the spot. Testing to check everything, I found two problems - the Main/Programming LEDs did not operate correctly and one LED of the main DCC output did not light (also the L298 got hot pretty fast suggesting a short somewhere). Checking I found I managed to cut the trace connecting pins 9 and 12. Yes, you guessed it - it runs under the chip. Had to remove the chip, fix the trace then replace the chip. Also found a miniscule flake of solder which embedded itself across a via along the DCC output trace and the surrounding ground plane. Removing that as well and all worked again. Also discovered that Flux-Off dissolves Plastik spray - so, check and clean all before spraying it. See attached picture of CPU board sans heat sink which is definitely required

    I next made a base board to hold it all together. See the attached picture. Also had to make a faceplate, a bit larger than required at this stage, to set the height and position of the LEDs before I could solder them to the base board. The slide and bush button switches require 8mm between the top of the base board and back of the face plate. The LCD display, when positioned to just protrude from the top of the face plate requires 5mm between it's PC board and the top plate. So I had to make 8mm, 5mm and 1.4mm (the LCD display's PC board is 1.6mm thick) spacers. All worked OK and I soldered in the LEDs

    The CPU board plugs onto the back of the base board to form a neat package. See the attached picture.

    I now only need to decide on a keypad. The membrane ones are quite large compared to the rest of the system. Also they always look a bit stuck on. So I am going to get a smaller button pad that mounts into the face plate and see how that looks. Need to wait for next month since I spent my current budget on some more components for other experiments - will discuss that in a new thread.

    Willem.
    CPU Board.jpg On The Bench.jpg Base Board.jpg Piggy Backed.jpg
     
    Last edited: Jul 15, 2018
  14. WillemT

    WillemT TrainBoard Member

    55
    40
    7
    It has been a while since I reported any progress on my ATtiny 85 project. The simple reason is that it was on hold mostly due to me not knowing how to finalise some outstanding programming issues, mostly to do with the display. The reason is simple, I ran out of memory and could not do any further additions or changes.

    I next started playing around with the ATTiny 84, for a different project. The device options list for the 84 had an additional entry - "Pin Mapping". While reading up on what that exactly does, I also checked the "LTO" option, which I left at it's default setting - "Disabled". I should really have caught on to this one, I think age is catching up on me. For anyone else not knowing, it stands for "Link Time Optimisation". It can be enabled for IDE version 1.6.11 onwards (current version is 1.8.6). I enabled "LTO" and re-compiling my controller code. WOW. Code went from 8186Kb (yes I was really at the end) down to 6322Kb. Suddenly I had bags of memory to do all the required updates and then some.

    Made a front panel graphic an attached it (See pictures). It is not perfect - I made some mistakes - but I can live with it. Once set, it is nearly impossible to get off. All seems to work as planned and I can now proceed with my next project, for which I actually need this one.

    The LEDs turned out to be a bit bright (5V with a 1K resistor - I thought that would be enough). I suppose I can add an additional resistor to dim them down a bit but will probably just leave them as is. Next time I will power them via a PWM pin making the brightness adjustable - live and learn they say.

    I think I will eventually have to get a crimping tool so I can make my own jumper wires of suitable lengths to connect the modules. In the meantime I just used standard length ones.

    There is a button function I think I need to change. Currently one button is used to select the Loco (white one) and the other controls the DCC signal (red button) - it toggles between the <0> and <1> track power instructions (as used by the DCC++ Base Station). My current feeling is that turning DCC On/Off will not normally be that common. A better use for that button would probably be to just issue a "Stop" (throttle = 0) to the currently selected Loco, maybe even an "Emergency Stop". I could use the same button to enable/disable DCC power by adding a long hold mode for it. Any advice from more experienced users would be appreciated.

    I now just need to decide how and where I am going to mount the unit.

    Front.jpg Back.jpg
     
    Last edited: Sep 2, 2018
    NScaleKen likes this.
  15. WillemT

    WillemT TrainBoard Member

    55
    40
    7
    Thought I would report back after using the controller a bit.

    I experimented with cheaper motor driver chip "Boosters" (money is always a problems so I try to save where ever I can) and stationary decoder circuits - feeding off the DCC rails. Turning off the DCC signal, using the power button (to emergency stop trains) turned out to be a problem. Circuits downstream do not like having their power removed.

    Since I do not have any extra buttons, I changed the existing one to turn DCC on or off by holding it down for a second. Clicking the same button stops the current loco. I may add a double click to emergency stop all trains. That solves the power problem and all now works great.

    So, in conclusion. Knowing what I know now, would I do the same?

    Using the ATtiny85 or 84, for DCC signal generation is great. The AVR MCU timers are practically custom made for this. Instead of messaging other, sometimes dual, timers to do this I will probably continue using these little chips (84 or 85) for generating the DCC signal. 8Kb flask RAM is ample for this purpose. Driving them with I2C from a controller MCU allows separate MCUs to be used for Main, Program and accessories etc. if required.

    As a controller the ATtiny85/84 is just not enough. The biggest problem is that it basically isolates the system. There is just not enough memory or any facility to connect to either serial or Wi-Fi allowing additional controllers or JMRI. This needs to be replaced by a more powerful unit. Lots of options available. 328P, 32U4, ESP8266 or more likely an ESP32 (some needing a USB to Serial bridge - I currently use the CP2104). The ESP options allow Wi-Fi natively so are probably the preferred units.

    Using a potentiometer for speed control is also not ideal - it works but is a bit of a pain to always first lock onto the new speed when switching Locos. A rotary controller will definitely be a better option. It does however require a bit more than an ATtiny85.

    Was it all worth it? Certainly, It got me to explore and experiment with different chips, aside from 328P and 32U4. The ATtiny range is large and very flexible. Apart from the 328P and 32U4, I currently have ATtiny 84, 85, 841 and 1634 chips. These are the most cost effective (selecting the cheaper packages) and useful for my purposes - they are also all supported by my ATtiny IDE core. Also made me look at other, cheaper, single H-Bridge motor drivers. The ones I tried works great with between 1.5 to 3.5 amp capability.

    So a big thanks to Travis, for starting the idea (and tread), as well as others participating and getting me looking at all the alternatives.

    Willem.
     
    Last edited: Oct 13, 2018
  16. Travis Farmer

    Travis Farmer TrainBoard Member

    352
    320
    14
    Your welcome. :)

    I have been way out of the loop for quite some time, mostly due to other projects, and personal issues. i was woken back up when i got a email notification of this reply. i still don't have much time to fully dive back into DCC++, but i will make a point to review this thread, and see what was spawned by my idea.

    ~Travis
     
  17. Antonio Fiol

    Antonio Fiol New Member

    9
    1
    1
    Hi,
    I am trying to get started with tinyDCCpp, and found I was not able even to compile the example sketch.
    My IDE is version 1.8.7, with ATTinyCore version 1.2.1.
    When trying to compile, the first thing I noticed is you're including "arduino.h" from Config.h and ATTinyCore provides "Arduino.h" with a capital A. I guess I'm using the wrong core, but not sure which one I should use.
    I quickly changed Config.h to use Arduino.h and see if I got lucky, and the second error was about "TinyWireS.h", which I don't have in my system. I googled for it, and found some I2C libraries for ATTiny, but then saw that ATTinyCore already has some Wire.h in it, so maybe I shouldn't need it.
    Could anyone please give me quick "getting started" guidance for tinyDCCpp? Meaning, what should I install before trying to use it?
    Thanks in advance!
     
  18. WillemT

    WillemT TrainBoard Member

    55
    40
    7
    I presume you are talking about Travis' "tinyDCCpp". Yes, he does not use the same core.

    I do use the same ATtinyCore as to you. It does not use the TinyWireS library but, as you stated, has its own built in wire functions for the ATtiny range. I actually stripped the original down to only include the mobile instructions for DCC for my own version of DCC++ and it works great.

    I use two ATtiny85s for my system, one for the DCC generation and one as a controller. A major problem with my version is that I have no external connection for driving the DCC++ from a PC or JMRI. It is a closed self contained controller.

    If you want to look at what I did on my system, let me know and I can let you have the sketches.

    Willem
     
  19. Antonio Fiol

    Antonio Fiol New Member

    9
    1
    1
    I did not realize that there were two versions around. Could you please point me to your code?


    I only need to be able to send signals from I2C to locos. No accessories or anything else.

    Even better. I will only use one of those: I don't need a hardware controller.

    I see. Well, I may have an idea for you. A raspberry pi, which is what I'm using as a "controller", can talk I2C without any problems. I'm using it all over my project.

    Absolutely! That would be great.

    My project currently works for DC locos, and allows controlling a large number of track segments, allowing the trains to move along and always knowing where they are.

    My "analog" boards are mainly like arduino motor shields "times N".
    Generating speed signals for the lot of motor drivers is done via either a bunch of 16-channel PWM drivers or, in the new design, one PWM driver and a bunch of interconnecting matrix ICs.
    Direction is generated using the same PWM drivers in the first version, and using a bunch of cheaper shift registers in the second version, but I've included logic to allow the direction to be controlled by a DCC signal... or so I hope.

    So, essentially, I'm planning to add DCC support to my analog circuits so that I can mix analog and digital trains in different sections of the layout, and control all of them from the same PC-based automation system.

    I do not own any decoders or digital locos yet, but I'm planning to buy a cheap one to start testing next month. For now, I need to be able to generate the signals on a prototype board.
     
  20. WillemT

    WillemT TrainBoard Member

    55
    40
    7
    Attached the promised files. First is the ATtiny 85 DCC++.

    A few pointers.
    1. All code not related to the mobile side has been stripped.
    2. Only one timer is implemented so the controller needs to switch between Main/Operations and Program/Maintenance. I use a "M" to switch mode and the function is "setSystem". You can see the commands I implemented in the "I2Ccommand.cpp" tab. The function is in the "PacketRegister.cpp" tab. There is a "writeCVBit" function in the "PacketRegister.cpp" tab, but since I never access it the linker will not include it in the upload. (I did not need that one yet).
    3. Switching to programming I clear all registers, stopping throttle instructions, and load an idle packet into register 1. All instruction on the programming track goes via register 0.
    4. Since there is only one DCC pulse output it needs to be routed externally to the correct input for the Mains or Programming motor drive. It is the controllers responsibility to make the switch and ensure programming instructions are only sent to the programming track. I am attaching my schematic to show I did it.
    5. The ATtiny85 DCC++ runs as an I2C slave.
    I use two structs to communicate via I2C. One to send instructions and one to receive return status.

    I included the controller sketch so you can see how I implemented the I2C side. I used a MCP23017 bus expander to provide the required I/O pins for the controller (the keypad alone requires 7).

    Compile the DCC code using the following board options:
    • Board: "ATtiny 25/84/85"
    • Chip: "ATtiny 85"
    • Clock: "16MHz (PLL)"
    • Timer 1 Clock: "CPU"
    • LTO: "Enabled"
    • The rest as you please.
    When I talked about my unit being a closed system, it only applies to the controller side. The ATtiny85 just does not have the additional memory or connectivity to talk to the outside world as well. I will use a different processor for my next controller. I need to see what I can do with the ESP8266 with its built in Wi-Fi.

    I am currently using the ATtiny84 for the DCC generator. Much cheaper in the VQFN package. Only change is it needs an external crystal/resonator (I use a resonator) to run at 16MHz. Also a few more available pins. The timer is a 16bit one like in the UNO or Mega - so the code goes back to the original there. I have a version adapted for Accessories only, talking to a six servo Decoder based on a 328P (will eventually be the 328PB) running great on the breadboard.

    If you have any questions, just ask.

    Willem.
     

    Attached Files:

    Last edited: Mar 17, 2019

Share This Page