As an electrical engineer, I'd like to congratulate you on your courage and open-mindedness. An excellent start. I have just one suggestion to make, if I may. Try replacing your voltage regulator with a simple voltage divider. This is just a pair of resistors of fairly liberal values, say 2.7k and 8.2k. You'll get a cleaner signal and, ultimately, fewer headaches.
Thank you for your kind words and this useful information 🙂 A few others have also suggested I should use voltage dividers, or other things besides a voltage regulator, so that message is coming through loud and clear, and I'll be doing some component shopping before the next iteration 🙂
@@endoorrailway A voltage regulator is designed to provide a _stable_ supply voltage, so it's not surprising that it doesn't work that well for an intentionally changing signal.
@mrab4222 - thanks, yes I guess that does make sense because it's going to be trying to counteract fluctuations, so that's likely to add some delay even though the voltage is totally dropping off below what the regulator works with. So far my main limiting factor is that it can take a long time for the MicroPython to take a reading of the input, compare it to one that's in memory, and record the time if there's a flip; none of how long that takes is affected by the voltage regulator. The regulator may well affect what happens in the scenarios where I used interrupts though, since they directly hinge off changes in the signal. I'll be moving to C and, for now at least, some resistors for voltage dividing - it looks like I've already got some at resistances that should work 🙂
@@endoorrailway If you already have a bunch of random resistors laying around, you can connect them in parallels or in series to get the required equivalent resistance. This will be sufficient for a quick prototype.
@barmalini Good point, thanks - putting smaller ones in series could be useful if power through them is too high too, though it looks like that's not going to be an issue in this case.
@@endoorrailway @endoorrailway Vrms = 13V * 0.707 = ~9V, but that would be for a AC sinusoidal wave, not a bipolar square wave .. The cheap DMM can't make sense of it since it also lacks a true zero crossing. The bipolar square wave isn't referenced to a fixed ground, it's floating. So it's not a true AC signal, where the reference (N) is at a fixed potential. Your measurement in DC mode is just the average it sees over some time, it's simply too slow to measure the signal.
As someone who as ample of experience with the Raspberry Pi Pico and using it to decode binary protocols. I highly recommend you to took into using the PIO System-Machines. While it is assembly language, which in another comment you stated you don't want to deal with. PIO-Assembly is exclusively I/O Assembly with a total of only 9 instructions. PIO can only do I/O nothing more. The IO is then put into a buffer to be read by CPU or if you want to extra fancy it can be written into memory directly using DMA. The Stat-Machine then can trigger an interrupt for CPU do do its things. So you can stick with MicroPython and the inherent inefficiencies you get from running an interpreted language or go to C it doesn't matter.
Thanks for letting me know about this - I'm not all that experienced with microcontrollers - I've just dabbled with the Pico for a few bits on the railway in the last couple of years, so hadn't come across the PIO stuff. It does look ideally suited to this, from what you say and from a brief overview I just read. I didn't mention it in this video (I've been doing the visuals for ages - I recorded the audio several weeks ago), but to get something physically small enough to go into N gauge locos I'm expecting to need to use something physically smaller than the RP2040 - possibly an ATTiny of some sort - so I don't want to do things that are super-specific to the Pico. At this stage I'm building an understanding of what I need to do both from the perspective of electrical components and interpreting the signal, so Python was an easy way to do that... except it's just far more inefficient than I'd expected!
@@endoorrailway I worked with the Pico in an employment setting so I have good experience with it. I never had N Model Railroad only H0 and G. But a RP2040 just as a package without the the Pico board around, I think is only 7x7mm bit you would need some PCB design knowledge if you want to use it as a package. Heads up if you want to use Python, you will restrict your choice if microcontroller significantly. Chips like the SAMD21 are already a pain on python as the whole Python runtime uses almost all 256k of Flash. For C++ you can use Arduino which supports a variety of Controllers but the independent of the controller also means more overhead although less than python for sure. If you go with C, you can be rather certain, that the code you now write for the pico in C can not be ported to an ATTiny as the SDKs are very very different. For an ATTiny I would suggest reading a lot about hardware timers.
@IamTheHolypumpkin - that's all really useful detail, thanks! I think with the number of pins on the RP2040 I would struggle to solder that to a board, though I wouldn't need to connect all of its pins I suppose, so wouldn't necessarily need to have it in a diamond orientation. I'm not set on using Python really - it's definitely my preferred for getting started, but if it's too slow then I'm happy to move to C or C++. It sounds like I'll need to have a read of the ATTiny SDK sooner rather than later then - I might be able to write the code in a way where I can isolate the specific differences, if I'm aware of what they are. So far I've never programmed anything besides a Pico, so I've definitely got learning to do one way or another!
Great video. Two suggestions to vastly improve reliability for you: 1. Opto-couplers (I don't suggest resistor dividers; see below) 2. Interrupt driven GPIO Bonus tip: Oscilloscope 1. Opto-couplers As others have said, a voltage regulator is a terrible solution for this. The regulator will take time to, well, regulate the voltage. This regulation can take time, and, is not really deterministic. So your response time may vary. Also, with the regulator you are coupling the (virtual) ground (the zero volts) on the rails to the ground on the Pi, and by extension your PC. That's not an ideal solution. Others have suggested resistor dividers. That works on a single rail, but can still cause the ground coupling issue, which isn't ideal. Opto couplers are ideal here, because they have diodes built-in, you can use one in one orientation and the other opposite that. Then you can use two GPIO pins to monitor either direction if you want. You'll get ground de-coupling, voltage isolation and a deterministic response time all in one. Opto couplers are perfect for this application. 2. Interrupt driven GPIO Others have mused that a 16MHz Arduino has no trouble decoding DCC, but you're struggling with a 133MHz Pi. The reasons are Micro Python and probably the voltage regulator. To make that more deterministic again and make sure you're not missing pulses, you should switch from polling to interrupt driven GPIO handling. An interrupt allows code to be processed immediately, regardless of what the rest of the processor is up to. You can simply timestamp the pulse then or count it and then resume "normal operations" A quick Google found an article titled "Raspberry Pi Pico Interrupts Tutorial- Examples in MicroPython" that might explain it for you. This will make a big impact on reliable pulse counting. Bonus tip: An oscilloscope would be super handy here. These days, a super basic one can be had for DIRT CHEAP. They won't be great, but absolutely perfect for testing and debugging this kind of issue. The "FNIRSI DSO-152" (no affiliation; just and example) is one example. You can get something like this for well under $30.... Hope this helps.
Thanks for the encouragement and for taking the time to write up that information for me! I've been a bit baffled by ground coupling for a while - often things I buy seem to require it, and the common ground on the electrics of this layout seem to link lots of things. I would much prefer things to have more isolation, so if optocouplers are small enough then I'm in favour of trying them 🙂 I did actually start off with interrupt-driven code, but I couldn't get good results and switched to the polling, which worked better. However, the interrupts will be directly linked to what the voltage regulator is doing, so that could well be a source of issues from what you and others have explained to me. I did actually read through a detailed interrupts tutorial from the MicroPython documentation before writing any code - it gives lots of useful information. I don't think there are other projects I'm going to want an oscilloscope for, so I'll see how far I can get without one - I'm pretty sure the signal at the tracks is going to be good because I've got plenty of trains receiving instructions correctly, but I admit it would help with diagnosing the issues I've had! Based on all the helpful comments like this one, I think a combination of switching to C and for now using a voltage divider (both things I should be able to do soon without doing shopping), are likely to bring much better results 🙂
@@endoorrailway optocouplers can be extremely small. Definitely give it a go. One side behaves exactly like an LED, though you never see the light; the other side is often a PNP or NPN transistor with exposed collector & emitter. There are many, many example circuits on the net.
I played around with all this a couple of years ago (for Scalextric Digital, which also uses DCC)... I can wholeheartedly recommend all these suggestions. I know a scope is an investment, but you're doing everything blind without one. I went for a Hantek standalone unit for under £200, but USB ones which use your PC to do a lot of the work are £50 or less.
I had a bit of a look at oscilloscopes today - it looks like they'd need to have megahertz bandwidth, and then it was unclear to me if ones that said they're 1 or 10 MHz can handle square waves at that speed. I'll see how far I can get without one - I can be confident that the signal at the track is OK because 30+ locomotives all respond to commands just fine, and I know from the NMRA specs what the signal for the commands should be, so I'll only need to get an oscilloscope if I get stuck. Thanks for the comment 🙂
As others have said, I'm VERY impressed with your work. To get where you have without an oscilloscope is mind boggling ! I am an electronics engineer and have used the the Pico and I agree with other comments. If I was you I would go for a PIC micro. Microchip provide a free compiler MPLAB X which with your attitude you will easily master. As you say 'C' is by far the best language for real time stuff like this. High-level languages like Python are not good at uS levels. I also would say you should use interrupts, there are loads of timers in the PIC processors like the PIC18F27Q43 that can take most of the timing work away from the CPU. In fact the PIC18F27Q43 has a ZCD (Zero Crossing Detector) feature that I have used to detect the rev signal from an alternator. All you would have to do is put a resistor (50k) in series with the signal line. You can then use a timer to measure the pulse length. I wish you the best of luck. If you need any help with the circuitry let us know! Best of luck, Simon
Hi Simon, thank you for your kind words and for taking the time to write-up those suggestions, and for offering future help - I may well need it! I've made a note of the PIC18F27Q43 as a potential thing to look into, thanks 🙂
Hello there Nice work you managed to explain what you were doing very well and for someone with no prior experience in coding I understood what you were saying. Keep up the good work and good luck with your decoders Nat🚂👍
Hi Nat, thanks! 🙂 I'm particularly pleased you were able to follow along without prior experience - it took me a little while to decide how to explain it all, but the visuals in this one took me absolutely ages to make!
This is one of those videos where the comments below it are just as educational as the video itself. Very cool project, I may give it a try as well some day. But I would definately do it in a faster language, probably in Go (because I'm most familiar with that...)
I've been surprised both at the level of interest in this video and the amount of helpful advice - it's going to be a challenge for me to take on board as much of the advice as possible! I'm vaguely considering learning Rust or Go, as memory-safe but fast programming options, but for now I've got too much to learn on the electronics side of things. Thanks for the comment 🙂
My few cents: Stick with a regulator for supplying power to the pico. Use a voltage divider using two resistors for the signal. Have a look at interrups and write the recieved bits into a circular buffer (ring buffer)
Thanks for your thoughts 🙂 I think a regulator from rectified power for the microcontroller would be sensible, and actually the DCC specifications say decoders should be able to work with up to 20V from the track, so I imagine it would help with that. I actually started out using interrupts but got worse results that the polling; however, from what others have said it seems that could be at least partly to do with using the voltage regulator for the signal.
this is fascinating, best bit with going from the ground up is you actually know what its doing and why, helps with debugging. I did similar, scalextric digital slot car stuff, way to go is to use interrupts (or the PIO on the RP2040, interrupts are easier). simple IRQ stores a flag. not too hard to get the timing between them in a loop, store it somewhere and use a state machine to process it home made decoders are not generally small, they are however perfect for static decoders
Thanks 🙂 I found writing the code to use interrupts pretty easy to do, though the polling code is also easy. I think I'll start with an interrupt-driven approach when I move to C. I have no idea what I'll actually be able to achieve with the circuit, but I'll have the freedom to make it a non-standard shape to fit the spaces in my locos, so that might help. I feel a long way off that yet though!
I'm seeing lots of good suggestions in the comments - one thing I will offer is this: As microcontrollers are designed to interface with the physical world much more than general purpose computers, there are often pieces of built in hardware to do tasks like asynchronous timing. For the 2040, the simplest way of accessing the hardware timers is by reading global system timer, which counts in microseconds. See section 4.6 of the datasheet for more info. A pin change interrupt to read this timer should be tight enough to get your the precision you need. The "more correct" way of doing it is in section 4.5 PWM of the datasheet. In 4.5.2.5. Level-sensitive and Edge-sensitive Triggering it describes how to tell the PWM counter to count while there is a high level on its input pin. In this way you could measure the exact time of the high periods irrespective of what the core is doing at any given time. A pin change interrupt could then tell you when to read the value and allow you to clear it for the next count. I don't generally program in high level languages, so I don't know what the overhead of these schemes would be in micropython, but as it is hardware based it should be agnostic to programming language.
Thanks for the extra information - I don't remember the PWM one being mentioned yet, though I'm finding it hard to keep track of all the suggestions! I'm quite happy to leave Python behind - I prefer it to write in, but not if it's going to cause extra headaches. The full details of the RP2040 datasheet are too much for me to digest at the moment - I'm pretty inexperienced with working with microcontrollers - what I've done with the Picos up to now has been relatively limited, so I'll take things slowly and see what I can get working in simple ways first. Thanks for taking the time to read the other comments and to write up those suggestions 🙂
@@endoorrailway for the vast majority of your programming, micropython is probably fine. For your timing critical tasks, tight routines written in C and triggered by interrupts may be necessary. After a nice nap and some thinking, if you use an interrupt to put your high/low times into a circular buffer, the main program can read the buffer at its leisure and work out where the packets are and how to read them, completely asynchronous from the receipt of the 1s and 0s. The 2040 has loads of RAM, so you can make the buffer quite large too. Look for the preamble, count from there, and check for validity. Fortunately, us humans won't notice tens or even a few hundreds of milliseconds of delay between command and response. Also, I suggest you throttle your main program loop to something in the 50-200Hz range if you are not already. Once again, you can use the system timer to decide when it is time to run a new execution of the main loop. The simple way to do this is to set a last-run time in the main loop, and then check the current system time against that time plus your timestep. No delay() commands (or whatever it is in micropython), as this will lock the uC's execution until the delay finishes. Running your main decision making code at a higher rate than this is likely unnecessary and can make it easier to decide how to split your CPU time.
Thanks for the follow-on advice 🙂 Good idea about deliberately throttling the main code - I haven't thought about power efficiency yet, but I've been surprised at how quickly the Pico is able to drain my _laptop's_ battery if powered from USB. The efficiency of modern hardware and software is very impressive.
Fascinating video. The digital trains to demonstate the packet contents was genius. I thought using a voltage regulator to level change was a bit odd, and i am surprised you get as good results as you do. As advised elsewhere there are probably better alernatives with voltage dividers or opto isolators or even capacitive isolator connections, although the latter will introduce other issues. There may even be specialist level changing chips available given that it must be a fairly common requirement for 3v systems. I know there was for 5v systems, but am not familiar with 3v interface chips. I shall be following your journey with interest
Thanks 🙂 Yes I'm very new to all this sort of electronics, so I may yet unwittingly do other things that are strange! I did searches for how to change the voltage level and there were various results, the regulator looked like a simple way, but it's abundantly clear now that other ways are better. The amount of advice I've been given from this video is great 🙂 Glad to have you along, thanks!
I'm glad youtube recommends me this! I've been thinking on doing the same but I'd need to learn quite a lot of stuff and its quite a daunting task. I like the way you explained the dcc protocols and maybe I can replicate your work someday! (I know there are libraries for arduinos, but just like you, I want to know the inner workings of the dcc system as well)
Thanks - it took me a lot more effort to make this video than my usual ones because of the diagrams for the explanations, so I'm glad it's making a difference 🙂 I may make my eventual "production" code public on GitHub, but in a way it's a bit pointless because people like you and I want to do it ourselves from scratch anyway 🤣 I too find this daunting though - I'm comfortable with programming, but there's loads that I don't know about the electronics side. But it looks like there's plenty of community help available - I've been given good advice in comments already 🙂
Same here. I'd LOVE to convert all my locos ( 00 not N , thank goodness! ) to DCC, but the cost of loco modules is SOOO expensive, and then of course, the main controller as well.... I'm definitely looking forward to your solution. One question, is it possible to do it this with Arduino, as I have a spare Nano I can use for test purposes? Cheers.
There are other people who've done it on Arduino - the search phrase "DIY DCC decoder" on Google brings back useful results. I read about some of the things linked from dccwiki.com/Do_It_Yourself#Decoders, but not in depth. I'm a long way off anything that can go into locomotive yet, but it looks like other people have done it already 🙂
Thanks for saying so! There was a point when I was folding all the bits of paper where I was doubting the sanity of putting the time into it, so it's good to know when people enjoy it 🙂
@@endoorrailway It was 100% worth it. I'd love to see you do it again if its needed in a future video. As well as being fun to watch, it did genuinely help me understand better
@@MTMByt Awesome, I'm glad it worked for both purposes 🙂 I'll see how things pan out - at the moment, nearly a month from when I filmed that part, those wagons all still have their binary covers on, so it would be easy to re-use them.
This looks like a cool and fun project. A couple of suggestions: For input use a comparator rather than the voltage regulator. It will give a digital output depending on where input A is higher than input B, or B is higher than A. Get one suitable input voltage range and 3.3V output and it can safely connect to the Pico. For timings remember the phrase “be strict with what you produce and generous with what you consume”. If your outputting signal make them accurate. If your reading them accept input which is outside spec but which makes sense. For the timings here you basically need to set a cut off time between a short signal and a long one. That will make your code resistant to issues. As for the code itself the PIOs on a Pico are specifically designed for processing serial data like this and they’re way, way faster than Python. Use them if you can. I’m not sure what that would look like here, people on the Raspberry Pi forums can probably give the best advice.
Thanks for your suggestions - they're helpful 🙂 A comparator or voltage divider sounds good - I'll be having a go with some resistors soon for the divider, and comparators look low-cost so might be worth trying too. Eventually I'll need to fit everything onto a circuit board that fits into a locomotive, so if I can get away with a couple of resistors that seems like it might take up less space than an integrated circuit package. Yes a simple cut-off sounds good - I think the signal is likely to be good most of the time, and since commands are repeated it shouldn't matter if the odd one gets mangled somehow. A couple of other people have mentioned PIO on the Pico - I hadn't come across that before. It does sound good, but ultimately I'm expecting to move to something physically smaller than the RP2040, so I don't want to develop things with things that are too Pico-specific.
@@endoorrailway Regarding resistor dividers, I’d be wary of voltage spikes causing damage to the Pico. To avoid that look for something called a protection diode and put in across the bottom resistor of the pair (assuming you’re powering the Pico from the rails. Between GND and the Gipson pin if not). This will prevent the voltage going higher than the diodes rating (which should the 3.3v here).
Thanks - that's worth knowing about - the DCC specifications for decoders state they should be able to work up to something quite high - I think it's 20 Volts - so I should consider it possible the controller could output that. Spikes could also happen for various reasons, so they're worth defending against if possible.
Great information here (both in the video and in the comments). All we need is for someone to make a RP2040 board small enough to fit in a N-gauge loco.
Thanks 🙂 That would certainly make things easier, though I think it would be hard to make a development board that small, given the large terminals around the edges. The RP2040 has lots more pins than should be needed for decoder purposes, so not connecting most of them to any terminals would help. Ultimately I'm not expecting to use the RP2040 for a final solution, but the Pico is what I've got available already and am (relatively) familiar with using in a basic way.
@@endoorrailway As a development board, the Pico is fine. It would be amazing to develop a board with a RP2040 (though another microcontroller would also be fine), the voltage handling circuitry and a speaker, in a form factor that fits most N-guage locos,
Don't know if this is mentioned already, but you might want use the DMA (direct memorry access) peripheral to read out the input automatically and write it to a buffer. A bit of a hassle to setup, but worth the performance as you are looking for microsecond measurements. Probably also possible to setup in python. (Not sure on this, but i think DMA is capable of transferring gpio inputs at, or near, cpu clock speeds, so might also come in handy troubleshooting as a substitute for an oscilloscope/logic analyzer) The PIO (programmable I/O) peripheral might also be a good option, as it is made with the intent of letting the user program a custom communication peripheral, with precise timing. Even more of a hassle than DMA, though😅
Thanks for the suggestion - yes a couple other have mentioned DMA and quite a few PIO - this week I'll write up a summary of suggestions and make it a pinned post. Nobody has mentioned using DMA to turn a Pico into an oscilliscope though - that could come in handy if I'm having trouble later on having got past this accurate signal measuring step, especially as I'm trying to avoid buying an oscilliscope 🙂
Not a simple undertaking especially without an oscilloscope but you have the right attitude, read the spec, start simple and work up to something more feature rich. Monitoring both rails is really only done to improve reliability as it can be quite electrically noisy monitoring rail voltages. The PI pico has some clever state engine functionality on its GPIO pins that should allow you to measure the intervals without using the processor at all. This can then just DMA the results to a memory buffer for your code to look at. Using that your measured timings will be super accurate. This will however require you learning the machine code to program the state machines but I don't think it's very complicated as it only has a few instructions.
@@endoorrailway After thinking about this for a while I think it would be very easy to get this working using PIO programming, it would be able to capture predefined number of bits into a register then interrupt the processor to read the register. PIO clock speeds can be set accurately so you are always sure when signals change state.
One of the things I find weird is how the pico running at 48Mhz has throuble reliable decoding the DCC packets, while and Arduino running at 16MHz is reliable for decoding the packets. Also, use a voltage devider, not a voltage regulator. a voltage regulator mangles signals like crazy. Even better would be an opto coupler Consider buying an cheap osiloscope to view what you are actually working with
From what I read the Pico is 133 Mhz, so to take 30 microseconds to get a reading of the input means it's executed nearly 4,000 instructions! The fact the Arduinos can do all this reliably makes me think that MicroPython is the issue - before long I'll have a go at this with C, just to see the difference. Several other people have also advised that the voltage regulator isn't the way to go, so I'll also see what resistors I've already got and make a voltage divider instead. It would then be interesting to see how the MicroPython does too after that. I'm not expecting to need an oscilloscope for many things, so I'll see how far I can get along without one, but am open to the possibility I'll need to get one. Thanks for the suggestions 🙂
Python is usually interpreted, whereas C++ (as it roughly is) on the Arduino is compiled. So every Python statement has to be read (often copied to an instruction buffer), taken apart, tokenised, parsed and then starts the execution of a fragment of machine code, and then the next part of the statement has to be... yes, you guessed it. I would normally reckon on interpreted code being 20 times slower than compiled code. Compiled programs tell the processor exactly what to do, at full speed. They are, however, tricky to debug, the Arduino IDE and others have a good go at spotting errors at compile time, but after that, the processor will be on its own. There will be some error trapping, for out of memory access, numbers out of range, trying to put values into an input port and so on, but... A good example, I wrote a fractal program in BASIC (interpreted) in 1988 that took 55 minutes to create the Mandelbrot set on screen. I then found a fractal program that did it using compiled machine code in about a minute. The BASIC was, however, good enough for a printer exerciser that wasn't time-crucial.
@@neilbarnett3046 Yeah, I remember thinking when he said it the budget was 100 instructions per microsecond that it would be fine in C or assembler where I'd expect 10 instructions per bit. But if Python is 10x worse that's 100 instructions and very close to being too slow. Python definitely has its uses in data science type applications but running it in a real time embedded system is not one of them. C is great for that sort of thing and if the C compiler does a bad job on the time critical parts you can just write them in a assembler.
@neilbarnett3046, @user-qf6yt3id3w There's some degree of compiling in Python, but I suppose it's more like caching because it's first done at runtime. But that's normal Python - I've not got any idea how MicroPython is implemented. I fully expect interpreted languages to be slower - really I was just having a go with MicroPython to see how it would turn out, and underestimated just how much work it's needing to do to be like standard Python. Eventually I'll get to trying some C on the Pico. Thanks for your comments 🙂
This is a great project. I think you need to be able to measure and see what you are measuring. Please borrow or buy an OSCILLOSCOPE. I have one on my desk at work and without it, you would be guessing. The idea of just using a voltage divider is a great idea. Yes a comparator may work, but you now have to worry about speed and false triggering. There are fast opto couplers available. I use one made by Sharp and has 5 pins, two for the LED inside and three for a 5V, Ground and signal. If memory serves it's called a PC400. Best of luck with this. What I have seen is that when you can reliably trigger on your signal, then the decoding starts to make more sense as you are getting good data,
Thanks 🙂 With the various different suggestions I've been given I may well have to give in and buy an oscilloscope, just to see how the different approaches compare. Thanks for the component code - when I get a chance I'll need to go back through these comments and make a list of the things people have suggested and do some online shopping!
Great video, really interesting. I would recommend taking a look at the PIO feature of the RP2040, I think you should be able to implement all of the timing critical low-level stuff with PIO, and just deal with protocol level stuff in micro-python.
Absolutely LOVED this video... completely Nerdy and pushed so many of my buttons with reverse engineering, electronic, programming and Picos. I think microPython and Pico PIOs is a good solution. I have a project 'picotimcode' which de/encodes a similarly structured protocol. Use separate PIO blocks running small state-machines to break the capture/decode into several parts. Collate the bits and pass to microPython code via FIFO and interrupts. I use one core to controll PIOs to do decode/encode, and the other core to do UI for controlling the whole lot. Good luck, and thank you for bringing me smiles/entertainment.
Also when thinking about capturing bits, think in terms of time rather than voltage. Quick toggles vs slow toggles.... this should be easy for a PIO block.
Thank you very much 🙂 It's getting a lot more views and comments than is typical for my channel, so I think it's ended up appealing more to the general electronics hobby or pros than to just model train-loving folk! Thanks for mentioning PIO - I haven't spent much time to date working with microcontrollers and hadn't come across it before making this video, but others have since mentioned it too. I'm glad you like Picos too, but ultimately for this project I'm aiming to use something physically smaller than the RP2040 (some kind of ATTiny is what I have in mind), so I don't intend to go down the PIO route because it looks like it's specific to the Picos, but if I were sticking with a Pico then it does look like a good way to go. I'm glad you enjoyed it, thanks for letting me know 🙂
A stamp is too big for a lot of N gauge locomotives. For what they have crammed inside these systems on a chip are a real marvel of engineering, and so cheap for all the wonders they perform, but at 6.5-7mm square the RP2040 takes up a decent amount of space that I'll need for other bits and pieces like optocouplers, resistors, some kind of non-volatile storage, motor driver, amplifier etc. - I know there are less capable but much smaller chips around. I really don't know what will work, ultimately - I may well end up with an RP2040.
Rather than a regulator to reduce the track voltage, try using an opto coupler, that is what I use. You are going to struggle with the PI as there are other processes running in the background and these will be using some of the processor cycles and may delay events being detected giving eratic timings. The PI has a lot of things going behind the scenes. This is why an arduino at 16MHz can quite happily decode DCC as it only runs the code you place in it and there are no background processes.
He's using a PI Pico, which is just running his code in the same way as the AVR in an Arduino. The Pico is a microcontroller like the AVR, it's *NOT* a board running an OS like the PI4/PI5 etc.
@@RamothElectronics But if you want Linux running and Arduino at the same time try using the MilkV, can do both at the same time. SBC is not bigger than the rpi PICO.
Thanks for the info. Even though this is indeed a microcontroller, I was surprised at just how inefficient MicroPython seems to be - taking 30 microseconds to do something means nearly 4,000 clock ticks! Good point about the optocoupler - I imagine it's possible to get very small ones too, which will be useful when trying to fit everything into an N gauge loco. Are they able to withstand 13-ish Volts coming in?
@@endoorrailway yes optos will work at that voltage, I work it out that you need 10mA to driver the opto, therefore if you have say 13V then you need probably a 1.5K Ohms resistor in series with the diode. The output needs to be pulled high with respect to zero volts by something like a 47K Ohms resistor. Chip resistors can be soldered directly onto the pins of the opto. When current flows in the diode side of the opto then the output will be pulled low. And yes micro python is not efficient. C will probably get you a shorter code path, but i have never run it on a PI pico. Watch for useful efficiencies.
I had a little look on the weekend, but it turns out there's a lot of variation on what they can do - the ones I found for less than £50 were mostly 200KHz, which would be too slow, and ones that were 1MHz for normal AC weren't clear what their ability was for measuring square wave signals. I really don't have much of a clue how to read their specs! Quite a few people think having one is a must, but I dislike shopping around for them, and I'll see how far I can get without one and consider it a last resort. Thanks 🙂
Enjoyed your video! What about using two diodes instead of the voltage divider or regulator for the input? Connect the catodes to each rail and the anodes to two different inputs of the Pico and perhaps separate pullup resistors between 3.3V and the anode of each diode.
Thanks 🙂 And thanks for the suggestion. The various helpful comments on this video have served to remind me just how little I know about electronics! Diodes just control which direction current can flow in, if my understanding of them is correct, and so I used them to split the signal - but the signal is at 13V, which is far too high for the Pico's (or other microcontrollers') inputs. Is your suggestion that, essentially, only a large enough resistor is needed in order to reliably reduce the voltage from 13V to 3.3V after the diodes? The Pico has internal pull-up and pull-down resistors, which one to use is configured in code, so at this stage I don't need to add any for that purpose as far as I'm aware.
@@endoorrailway With a diodes mounted the way I suggested, the current should only flow to through the diode and pull the input down to 0V when there's 0V on the rail (suggest using similar diodes as the rectifier to have the same voltage drop). When the rail is at 13V the diode blocks and pin is pulled up to 3.3V either internally or with a resistor. Probably not necessary to monitor both rails, then you can use only one diode and input. But I think a setup with an optocoupler as some already suggested is the most optimal way of harversting the signal.
I don't know the PI2040 as well as AVR microcontrollers but if that MCU has timers and at least one of them has a capture pin¹, then you can let that timer time every transition instead of doing it in code. Then all you have to do is subtract the previously captured value from the current one to get the length, in clock pulses of the bit you're measuring. I've also seen suggestions about optocouplers. They're not fit for the job, they're too slow. Instead you may need signal shaping/debouncing done in hardware - unless the Pico has hardware mechanisms to filter spurious pulses away, of course. Micropython may be too slow even with this approach though. You'll have to assess that as well. ¹ A capture pin is used to copy the current counter value of a timer into specific registers, named capture registers, when a transition occurs on that pin. These transitions may also trigger an interrupt, which is useful to signal the application firmware an event occured.
Thanks for taking the time to write up that extra information, and for reading through the other comments to see what people have said. Interesting about the optocouplers - quite a few people are keen on those. I'll give a few things a go and see what kind of results I get - if the code is successfully getting the instructions I think the controller should be sending, and with enough time to do something with it, then it'll achieve what I'm after 🙂
Good evening Jonathan! I thoroughly enjoyed your journey exploring the DCC signal! Your visualisations were really compelling, especially the locos pulling wagons of bits around the track! Very clever! Your end goal of creating a sound decoder is fantastic, as I'm hoping you'll eventually confirm that we are currently paying well over the odds for what's involved! In terms of speed, I think C / C++ is the only way to go for this type of task, unless you can find a compiler for Python! Another route would be to find something that converts Python to C, if you're not familiar with programming in C! Give me a shout if you need a hand with the programming! I'm a bit rusty with C, but programming is like riding a bike isn't it? :) All the best, Ian.
Morning Ian, thank you very much! I don't find it too hard to come up with ideas for visualisations most of the time, but it takes me an absolute age to actually make them, so I'm glad you liked them! I was particularly pleased with the bit wagons, and those were comparatively quick to do too 🙂 As an aside while mentioning wagons - when I pre-ordered some with The Model Centre the other day I noticed that adding to Trunk was a delivery option - turns out they've implemented a Hattons-style trunk service! There are many unknowns for me with what I'm trying to do - I'm expecting I'll need to use some kind of circuit printing service - I know they exist and that it's possible to get custom circuits for a few dollars, and that common components can be included... but what it will all come to in the end is a mystery to me right now. We'll see! Thanks for your offer, but I'll be OK - I prefer Python these days but I've done C and C++ before, so am familiar with pointers etc. Plus like you say, once you've done enough programming new languages aren't usually much of a hurdle 🙂 The main thing I need to research is just what to do specifically for the Pico, but I'm expecting to be able to find guides for that very easily.
@@endoorrailway - Ooh! A new trunk service? That's great! Hopefully they'll also adopt Hattons pricing too, as I always think TMC is a little expensive compared to other retailers! I follow a few people who've used custom PCB making services, and they work great apparently! The more PCB's you order, the cheaper they are! No problem with the programming help offer, and good luck! :) Ian
According to Digitrax each rail is measured separately. Rail A and ground on your command station gives one number for voltage and Rail B and ground should give the same number no matter what system you are using. Try this to see what it is reading. Then adding both readings gives you the voltage output for both rails.
I hadn't heard of it before making this video, but someone else mentioned Nyquist too. The highest frequency would be the shortest DCC "one", which is 52μs - that would make the Nyquist frequency 26μs. With 26μs samples a DCC "one" of 64 could potentially be measured as lasting 78μs, but the shortest a DCC "zero" could be measured at is 104μs. But with a 29μs sampling frequency a similar thing comes out - max One is 87μs, minimum Zero is 116μs. I think if the interrupts run quickly enough when programmed using C (which I fully expect they will, based on what quite a few people have said), then that's probably the most elegant way to program things. Thanks for the comment 🙂
I would look into using the PIO on the Pico. You should be able to read data using zero clock cycles on either core. This mean MicroPython is completely viable
I'm glad you're interested in how this is going - so far I haven't done enough more for a second video. I managed to get some C running on the Pi Pico and ran some basic timing code on it reading the state of an input, and as expected it was a lot, lot faster to execute that than the Python had been. I also found resistors that I can use as a voltage divider and bought various capacitors and Zener diodes, to try implementing things people have suggested. It's going to be a long and slow project I'm afraid, just like everything else I do with the model railway 😆
The HW is "right". Meaning, the rectifier bridge with the voltage regulator. Don't forget some decoupling capacitors. DCC is in kilohertz square wave. The code must be much more robust. Ideally, in C or assembly, using interrupts and HW timers, not relying on execution speed at all. Good luck :)
Thank you for your thoughts. I'll definitely be moving away from the voltage regulator between the signal and microcontroller inputs! Execution time will always be relevant - even in an efficient language and triggered by interrupts, instructions must still be executed for anything useful to be done. But knowing that C is a lot more efficient, and from what others have commented, I'm expecting switching to that make a big difference. Thanks 🙂
I guess zero stretching is for determining witch rail is witch... try listening for stretched zeros first on both flanks to choose witch flank to listen to later. Using PIO may be worth looking in to - You should be able to programing PIO from python.
I don't think so - the stretched zeros could be on either rail, and actually both could be stretched equally so long as their sum doesn't exceed 12,000 microseconds. I'm fairly certain it gets used for controlling DC locomotives, by making the current flow mostly in one direction, though I didn't see that purpose mentioned in the specifications. Thanks, others have mentioned PIO too 🙂
@@endoorrailway Controlling DC locomotives... make sens. A bit harder then. Listening on both flanks and summing up the absolute difference of periods before and after each flank while trying to ignore stretched zeros. Then, if the difference is bigger for raising flank use that, if the difference is bigger for falling flank us that. But PIO is probably the best bet... Should give sub ms precision if wanted without loading the CPU at all.
Your multimeter likely doesnt measure peak voltage in ac mode, since if it did it would divide it by the square root of 2 before displaying it (since this resulting voltage value is the equivalent of the dc voltage that would dissipate the same power in the circuit, but only if the ac waveform is a sine wave). More likely you have a good multimeter that actually performs integration on ac waveforms
You know, I never even considered that I might have a good one! I _think_ proper signal integration in AC mode is the first explanation I've heard that seems to explain why it gets both the sine and square waves correct. Thanks 🙂
i wonder what the proper commercial approach to signal conditioning is? is there anything in the spec that describes appropriate circuits for picking up the signal from the rails? in my opinion voltage regulators and voltage dividers are not going to be enough, and will be noisy. i think you might have better luck with optocouplers. these use a light (or infrared) emitting diode across the input signal to turn on a phototransistor on the output side, and will automatically produce a 3v3 signal that is completely isolated from the rail power. if you install two, and connect one in reverse, across the rails, you can select the polarity you are detecting. because optocouplers more dependant on current than voltage, it should give a much more reliable pickup, i think, and i strongly suggest you look into this. however i really would like to know what the specification expects. as for interrupt driven decoding, you may want to consider that there are different priorities of interrupts and, unless you use the highest priority, your interrupts will be postponed by anything else the system thinks is more important, and this will skew your timing. thank you for introducing me to this topic, it is fascinating.
In what I was reading I didn't come across anything that suggested implementation solutions, it was just specifying what needs to be achieved, but I haven't read through most of the documents - I was just trying to get started somewhere. The various specifications are at www.nmra.org/index-nmra-standards-and-recommended-practices A few other people have suggested optocouplers too - I'll have to take a look at what's available - ultimately I'd like to make something that fits into an N gauge locomotive, so small surface-mount components will be needed. I'm sure there's be optocouplers that fit that constraint though 🙂 There was a nice guide about interrupt programming I read that's part of the MicroPython documentation; I'm not sure what other interrupts would be going on, but it seemed to be saying that all of the same priority would queue up if they overlapped, so I just left them at default. Maybe there are others happening that I don't know about, but I think they'll also be affected by the voltage regulator potentially distorting the timing, so there seem to be a few ways in which I could improve things. Thank you for taking the time to share that useful information 🙂
@@endoorrailway i tried reading the spec, thanks for the link, but it seems they do not concern themselves with the actual interface, and these are proprietary. must first admit my electronics technical degree was a very long time ago, and i am very out of practise, but i think you could use a PC817, with an appropriate current limiting resistor, directly across the track signal, and you could then connect the ouput directly (and safely) to your GPIO pin. if the track voltage changes, though, you would need a different resistor.
It didn't take you long to scan a lot of information there! With a degree like that you'll have forgotten a lot more than I'm likely to learn in this field. Thanks for the suggested component - I'll have to start making a list of the various things that have been suggested.
Any cheap Arduino-based board + interrupts should make light work of this. I am currently trying to do something similar to emulate the tape interface of an old Casio 80s handheld computer. But that is painful for many reasons.
You're undoubtedly correct, but I think only if a fast programming language is used too - the Pico is a lot faster than the Arduino-based boards. Tape-based, eh? Personally as an end-user I'm very pleased to leave tapes in the past, and CDs for that matter 🤣 Thanks for the comment 🙂
Maybe consider using Rust, rather than C or C++, and gives comparable performance, and pushes most errors and bugs from run time to compile time. Sadly though Rust programs are likely to us more RAM than C code.
I am indeed considering it - besides a quick search a month ago I don't know anything about it, but if it's going to be a major language that is fast but removes lots of memory management errors then it would be useful for me to learn. It caught my attention when the Pi Pico 2 launched and advertised support for it. From what I found there's support for Rust with ATTiny microcontrollers too, though I don't know how good it is. Thanks for the suggestion 🙂
Nyquist's sampling theorem applies to your track signals: you must sample at least twice as fast as the shortest pulse, so given shortest = 52us, you have to [be able to] sample at 26us intervals. I would suggest you sample at a faster rate than this though: it's common with UARTs to sample at 16x the baud rate, and while that might not be needed, 4x is probably a good thing to aim for. I would strongly suggest looking at the "PIO" units of the Pico. They are kind-of a dedicated I/O processor, and will be able to sample the input very effectively. You can program them from a high level language and then get the benefit of full speed processing. There are a number of example configurations available in the pico SDK - look for example at the I2C and UART setups for inspiration, as they are doing similar things (sampling a pin and decoding signals on it).
I knew there must be a formula, thanks! With 26μs samples a DCC "one" of 64 could potentially be measured as lasting 78μs, but the shortest a DCC "zero" could be measured at is 104μs. But with a 29μs sampling frequency a similar thing comes out - max One is 87μs, minimum Zero is 116μs. I must admit I keep having thoughts like this, but eventually find a scenario that proves me wrong. So far 29 is the largest I've come up with where (I think) there can't be an overlap in interpreting the longest One and shortest Zero. Thanks for mentioning PIO - it's not something I'd come across before making this video (I've not got a lot of experience with microntrollers), but a few other people have mentioned it since. I think it's specific to the Pico, so I'm not intending to go down that route to start with because there are physically smaller microcontrollers around, so I'm expecting to translate what I learn to another architecture. Thank you for taking the time to explain those things 🙂
Regulator is awful solution to match signals voltage levels. Resistor divider will be enough, eventualy optocopuller or specialised level shifting ic (old ones from RS232)or just transistor.
Thanks for the info 🙂 Ah OK - out of curiosity, what makes the regulator so bad for this? I'll definitely need to scale this down though, and I know it's possible to get small surface-mount resistors, presumably also transistors and optocouplers. But wouldn't the resistor approach rely on the track voltage staying the same? In practice it does, but according to the DCC specifications a base station would be allowed to produce a lower voltage, and decoders should be able to cope with it. Plus locos might get poor pickup on occasions even if the track voltage is consistent.
I came here to say the same 🙂 : Nobody uses voltage regs as level shifters. I have not looked at the signal on a scope, but I don't think their startup time/speed will be reliable enough for proper timing. The pico should be plenty fast (I think) for what you are doing. You can try with a resistor divider if you do not want to isolate the track and pico with an optocoupler.
The voltage regulator is not ideal - a step change on the input will result in a slope change on the output. I recommend you use a high speed optocoupler (6N137 is commonly used). This will also protect your PC from any damage. In your final decoder, you can just use a series resistor to limit the current into your microcontroller and rely on its input protection diodes to clip the signal to 3V3 or 5V.
@@endoorrailway I only add some to what colegues wrote. Those regulators work stable when some substantial current is drawn from output and today's microcontroller inputs are not taking current at all almost. Also they have some kind of regulation loop and may became oscilatiors without decopuling and they are not suited for high freqency signals as one write it may generate substantial slopes, especially when load is almost not existent. It may be mitigated partially by pulldown resistor on 3.3v side and some capacitors but sincerely I'm shocked that it works at all 😉
@@CarstenBe about lower voltage - if you do divider 1:4 for example then if input drops 1v then output drops 0.25v also voltage value accepted as logical 1 is quite wide starting from 2V also most microcontrollers will accept more than 3.3v some even 5v without harm, eventually you can add zener diode to for safety. But optocupuler maybe most safe and small solution.
It’s likely your meter isn’t a true RMS meter, so instead of taking a proper average it just takes the peak and multiplies with 2/3 which would be correct for a sign wave, but is wrong for any other wave like the square wave.
Thanks for the theory; in AC mode it does measure the DCC track voltage (without any of my diodes in place) as the expected 13V, so it must be taking a proper average to get that. The readings where it was 2/3 of full voltage were when it was in DC mode - I don't think it should be doing any kind of RMS (or an approximation) for DC, if nothing else because it would never produce a negative value. In DC mode it does correctly measure normal DC signals, like the supply for my LEDs, or the terminals of a 9V battery, as being at the expected voltages. Maybe I need to put it into AC mode and see what it makes of a single track's signal through the diodes - I didn't do that because the current isn't alternating. This multimeter was about £7, so it's not going to be a fancy one.
@@endoorrailway If you were to give your multimeter on AC a 13V sine wave, the peak voltage is going to be 1.4 times the RMS value, and the meter is calibrated to tell you that the RMS is 13V. This is the cause of your 2/3 and 3/2 values, though they sound like the average, rather than the RMS. Try that AC read on a 9V battery and see what you get, compare the DC and AC readings, that should calibrate the reading in your mind. Most multimeters measure AC by rectifying the AC to DC and then dividing by 1.414, the square root of 2 (or multiply by 0.707, the inverse, it's the same result). This matches the definition for measuring an AC value, that it should come out the same as the DC voltage that would deliver the same POWER. (if you have root 2 times the voltage, you get root 2 times the current, and volts x amps = power.) For most multimeters, your AC range will read 13V RMS AC as being 13V and it will usually do the same for 13V DC, though it may say 18.3V... A smart multimeter will recognise DC and scale itself accordingly, though most simple multimeters are not that smart. You could try this and it will be informative. It would seem that when no instructions are being delivered to the track, it rests at 13V DC. You could tell by putting a DC-only engine on, it should go like Mallard... Multimeters are a black art that I mastered in 1973, but now can't explain very competently. It's been a while...
@neilbarnett3046 thanks for the information. The 9V battery test is odd - in DC it measures 8.5 or -8.5 swapping the leads, so that seems about right. In AC it measures 18.8V with the leads one way, and 0V the other way. I expected about 12V or 13V regardless of which way around the cables were, if it were applying the scaling to get equivalent DC power. I think I'll need to do some proper reading up on multimeters, or maybe buy one that comes with detailed documentation - I'm going around in circles with what I'm understanding of what people are telling me vs what I measured, but thank you for taking the time to try and help me with it!
This is the first time I've tried to work with a digital signal at this level, so it's all "DCC stuff" to me, but it seems likely the engineers who designed it were familiar with other similar things like canbus and took inspiration. That would also help other engineers understand it and work with it easily as there'd be familiarity.
@@endoorrailway yes true, in fact just about all signalling systems have evolved from another before, no matter how complex they make it once it passes through circuitry it all boils down to just 1's and 0's. this one is fairly basic in that theres no error correction just bad packet skipping, you want an headache, look into a cd players data stream thats designed to cope with random flipped bits from noise/dirt of the disc, its amazing how they even came up with it and I'm glad i'll never have to try to code for it....
At this stage I'm pleased that the error detection is just skipping and not correction! Yes I've been impressed with how well CDs can play even with a decent amount of scratching on them. I think that's going to be at a complexity beyond what I dabble in during my hobby time 😉
I assume that micropython is doing some garbage collection, so you might try force a gc.collect() at a time that makes it suitable for you. Python is not going to be a real time os. You might be better trying to run DMA transfers and processing that instead of trying to poll it.
Thanks. The polling wasn't my first approach, but it was the one that worked best in MicroPython. I'll be moving away from MicroPython for this - I was hoping it would do the job, but it doesn't seem to.
There's a wide range of Open Source DCC decoders so unless your doing it for the thrills I don't really see the point in re-inviting the wheel. Had you picked Arduino/Teensy as a platform there's even a library for DCC decoding.
Yes - I did a bit of searching and found a few, including one that's specifically for the RP2040 - they gave me the confidence that it's feasible. I'm doing it from scratch for the fun of it, but if I get stuck or lose interest then I can move over to one of the existing solutions 🙂
No - whilst I enjoy programming, C is about as low-level as I like, so if that's not fast enough I think I'll be giving up on writing the code myself 🤣
@@endoorrailway with those kinds of timings I'd expect you'll be fine in C on a pico or any modern microcontroller tbh. I'd certainly be doing it in C.
I didn't mention it in this video, partly because I did the audio recording several weeks ago and them spent the rest of my time since then making the visuals, but the RP2040 isn't my end goal for this - I think physically it's too big to go on a board with other bits and fit into N gauge locos. That's not to say it couldn't be used in accessories, but they aren't my aim, so I'm using the Pico to get an understanding and prove some concepts but will probably end up trying an ATTiny eventually. I hadn't come across the PIO stuff before - from what I just read it does look like this is exactly the sort of thing it's for.
your multimeter is averaging not true rms therefore the real voltage reading should be multiplied by 1,4 to get an actual voltage, if you pass it trough fill bridge rectifier you should get that minus 0,7v i still need to build my n decoder because everything off the shelve is just a bit too big also your instructions don't have to be mesured with any high accuracy, since bit 1 and bit 0 are different length you just need to check every 0,7 of the length of the shorter bit and if value fliped read 0 and if it didn't set 1 and set interupt for another rising edge , then reset timer and do read again
To follow up, averaging RMS meters assume a sine wave amd multiply their measured value by 1.11 to approximate RMS. ( (sqrt(2)/2) / (2/pi) ) So divide by 1.11 to get the average value of your measured signal. Since average and RMS for square are the same, you're done. Should be measuring less than two thirds though, I cant explain that @ 3:55.
Thanks @kokodin5895 and @electrowizard2000 for the information - this afternoon I looked up what RMS is and came to the same conclusion about the square wave, explaining the track output in AC mode. I don't think the multimeter would need to do RMS to measure DC, though - in fact it can't be, else it would never produce a negative reading, so for now I think the two-thirds thing remains a mystery.
@@electrowizard2000 this is not sine though, it is square wave alternating via h bridge from single positive voltage if a meter has small bandwidth even if it is averaging it would measure much less than normal ac, most cheap meters is bandwidth limited to less than 1khz because ac they are ment to measure usually is 50-60 hz, the best way to measure this kind of voltahe is to put full bridge on it and measure dc and better yet use something like texas instruments active bridge rectifier and it would spit out 1/10 of rms voltage as a dc, i made meter like that to measue 14khz pulse voltage used in crt tv's as a heater voltage for the crt
I love the "binary train". Great visualization.
Thanks! Once I'd had the idea, I just had to do it 🙂
As an electrical engineer, I'd like to congratulate you on your courage and open-mindedness. An excellent start.
I have just one suggestion to make, if I may. Try replacing your voltage regulator with a simple voltage divider. This is just a pair of resistors of fairly liberal values, say 2.7k and 8.2k. You'll get a cleaner signal and, ultimately, fewer headaches.
Thank you for your kind words and this useful information 🙂 A few others have also suggested I should use voltage dividers, or other things besides a voltage regulator, so that message is coming through loud and clear, and I'll be doing some component shopping before the next iteration 🙂
@@endoorrailway A voltage regulator is designed to provide a _stable_ supply voltage, so it's not surprising that it doesn't work that well for an intentionally changing signal.
@mrab4222 - thanks, yes I guess that does make sense because it's going to be trying to counteract fluctuations, so that's likely to add some delay even though the voltage is totally dropping off below what the regulator works with. So far my main limiting factor is that it can take a long time for the MicroPython to take a reading of the input, compare it to one that's in memory, and record the time if there's a flip; none of how long that takes is affected by the voltage regulator. The regulator may well affect what happens in the scenarios where I used interrupts though, since they directly hinge off changes in the signal. I'll be moving to C and, for now at least, some resistors for voltage dividing - it looks like I've already got some at resistances that should work 🙂
@@endoorrailway If you already have a bunch of random resistors laying around, you can connect them in parallels or in series to get the required equivalent resistance. This will be sufficient for a quick prototype.
@barmalini Good point, thanks - putting smaller ones in series could be useful if power through them is too high too, though it looks like that's not going to be an issue in this case.
The multimeter in AC mode will show Vrms, it measures the peak voltage and divides it by the sqrt(2), assuming a sinusodial wave.
Thanks for the info. If it did that wouldn't it end up reading the 13V square wave as being around 9V? 13 / (2^0.5)
@@endoorrailway @endoorrailway Vrms = 13V * 0.707 = ~9V, but that would be for a AC sinusoidal wave, not a bipolar square wave .. The cheap DMM can't make sense of it since it also lacks a true zero crossing. The bipolar square wave isn't referenced to a fixed ground, it's floating. So it's not a true AC signal, where the reference (N) is at a fixed potential.
Your measurement in DC mode is just the average it sees over some time, it's simply too slow to measure the signal.
OK thanks .
As someone who as ample of experience with the Raspberry Pi Pico and using it to decode binary protocols. I highly recommend you to took into using the PIO System-Machines.
While it is assembly language, which in another comment you stated you don't want to deal with.
PIO-Assembly is exclusively I/O Assembly with a total of only 9 instructions.
PIO can only do I/O nothing more. The IO is then put into a buffer to be read by CPU or if you want to extra fancy it can be written into memory directly using DMA. The Stat-Machine then can trigger an interrupt for CPU do do its things.
So you can stick with MicroPython and the inherent inefficiencies you get from running an interpreted language or go to C it doesn't matter.
Thanks for letting me know about this - I'm not all that experienced with microcontrollers - I've just dabbled with the Pico for a few bits on the railway in the last couple of years, so hadn't come across the PIO stuff.
It does look ideally suited to this, from what you say and from a brief overview I just read.
I didn't mention it in this video (I've been doing the visuals for ages - I recorded the audio several weeks ago), but to get something physically small enough to go into N gauge locos I'm expecting to need to use something physically smaller than the RP2040 - possibly an ATTiny of some sort - so I don't want to do things that are super-specific to the Pico. At this stage I'm building an understanding of what I need to do both from the perspective of electrical components and interpreting the signal, so Python was an easy way to do that... except it's just far more inefficient than I'd expected!
I came here to say using the PIO would be the best option. The other option is using a capture timer module and interrupts.
@@endoorrailway
I worked with the Pico in an employment setting so I have good experience with it.
I never had N Model Railroad only H0 and G. But a RP2040 just as a package without the the Pico board around, I think is only 7x7mm bit you would need some PCB design knowledge if you want to use it as a package.
Heads up if you want to use Python, you will restrict your choice if microcontroller significantly. Chips like the SAMD21 are already a pain on python as the whole Python runtime uses almost all 256k of Flash.
For C++ you can use Arduino which supports a variety of Controllers but the independent of the controller also means more overhead although less than python for sure.
If you go with C, you can be rather certain, that the code you now write for the pico in C can not be ported to an ATTiny as the SDKs are very very different.
For an ATTiny I would suggest reading a lot about hardware timers.
@SimonEllwood thanks for the info - I hadn't heard of a capture timer module before, so that'll be something for me to look up 🙂
@IamTheHolypumpkin - that's all really useful detail, thanks! I think with the number of pins on the RP2040 I would struggle to solder that to a board, though I wouldn't need to connect all of its pins I suppose, so wouldn't necessarily need to have it in a diamond orientation.
I'm not set on using Python really - it's definitely my preferred for getting started, but if it's too slow then I'm happy to move to C or C++.
It sounds like I'll need to have a read of the ATTiny SDK sooner rather than later then - I might be able to write the code in a way where I can isolate the specific differences, if I'm aware of what they are. So far I've never programmed anything besides a Pico, so I've definitely got learning to do one way or another!
Great video. Two suggestions to vastly improve reliability for you:
1. Opto-couplers (I don't suggest resistor dividers; see below)
2. Interrupt driven GPIO
Bonus tip: Oscilloscope
1. Opto-couplers
As others have said, a voltage regulator is a terrible solution for this. The regulator will take time to, well, regulate the voltage. This regulation can take time, and, is not really deterministic. So your response time may vary. Also, with the regulator you are coupling the (virtual) ground (the zero volts) on the rails to the ground on the Pi, and by extension your PC. That's not an ideal solution.
Others have suggested resistor dividers. That works on a single rail, but can still cause the ground coupling issue, which isn't ideal.
Opto couplers are ideal here, because they have diodes built-in, you can use one in one orientation and the other opposite that. Then you can use two GPIO pins to monitor either direction if you want. You'll get ground de-coupling, voltage isolation and a deterministic response time all in one. Opto couplers are perfect for this application.
2. Interrupt driven GPIO
Others have mused that a 16MHz Arduino has no trouble decoding DCC, but you're struggling with a 133MHz Pi. The reasons are Micro Python and probably the voltage regulator. To make that more deterministic again and make sure you're not missing pulses, you should switch from polling to interrupt driven GPIO handling.
An interrupt allows code to be processed immediately, regardless of what the rest of the processor is up to. You can simply timestamp the pulse then or count it and then resume "normal operations"
A quick Google found an article titled "Raspberry Pi Pico Interrupts Tutorial- Examples in MicroPython" that might explain it for you. This will make a big impact on reliable pulse counting.
Bonus tip:
An oscilloscope would be super handy here.
These days, a super basic one can be had for DIRT CHEAP. They won't be great, but absolutely perfect for testing and debugging this kind of issue. The "FNIRSI DSO-152" (no affiliation; just and example) is one example. You can get something like this for well under $30....
Hope this helps.
Thanks for the encouragement and for taking the time to write up that information for me!
I've been a bit baffled by ground coupling for a while - often things I buy seem to require it, and the common ground on the electrics of this layout seem to link lots of things. I would much prefer things to have more isolation, so if optocouplers are small enough then I'm in favour of trying them 🙂
I did actually start off with interrupt-driven code, but I couldn't get good results and switched to the polling, which worked better. However, the interrupts will be directly linked to what the voltage regulator is doing, so that could well be a source of issues from what you and others have explained to me. I did actually read through a detailed interrupts tutorial from the MicroPython documentation before writing any code - it gives lots of useful information.
I don't think there are other projects I'm going to want an oscilloscope for, so I'll see how far I can get without one - I'm pretty sure the signal at the tracks is going to be good because I've got plenty of trains receiving instructions correctly, but I admit it would help with diagnosing the issues I've had!
Based on all the helpful comments like this one, I think a combination of switching to C and for now using a voltage divider (both things I should be able to do soon without doing shopping), are likely to bring much better results 🙂
@@endoorrailway optocouplers can be extremely small. Definitely give it a go. One side behaves exactly like an LED, though you never see the light; the other side is often a PNP or NPN transistor with exposed collector & emitter. There are many, many example circuits on the net.
Great, thanks 🙂
I played around with all this a couple of years ago (for Scalextric Digital, which also uses DCC)... I can wholeheartedly recommend all these suggestions. I know a scope is an investment, but you're doing everything blind without one. I went for a Hantek standalone unit for under £200, but USB ones which use your PC to do a lot of the work are £50 or less.
I had a bit of a look at oscilloscopes today - it looks like they'd need to have megahertz bandwidth, and then it was unclear to me if ones that said they're 1 or 10 MHz can handle square waves at that speed. I'll see how far I can get without one - I can be confident that the signal at the track is OK because 30+ locomotives all respond to commands just fine, and I know from the NMRA specs what the signal for the commands should be, so I'll only need to get an oscilloscope if I get stuck. Thanks for the comment 🙂
As others have said, I'm VERY impressed with your work.
To get where you have without an oscilloscope is mind boggling !
I am an electronics engineer and have used the the Pico and I agree with other comments. If I was you I would go for a PIC micro.
Microchip provide a free compiler MPLAB X which with your attitude you will easily master.
As you say 'C' is by far the best language for real time stuff like this. High-level languages like Python are not good at uS levels.
I also would say you should use interrupts, there are loads of timers in the PIC processors like the PIC18F27Q43 that can take most of the timing work away from the CPU.
In fact the PIC18F27Q43 has a ZCD (Zero Crossing Detector) feature that I have used to detect the rev signal from an alternator.
All you would have to do is put a resistor (50k) in series with the signal line.
You can then use a timer to measure the pulse length.
I wish you the best of luck.
If you need any help with the circuitry let us know!
Best of luck, Simon
Hi Simon, thank you for your kind words and for taking the time to write-up those suggestions, and for offering future help - I may well need it! I've made a note of the PIC18F27Q43 as a potential thing to look into, thanks 🙂
Hello there
Nice work you managed to explain what you were doing very well and for someone with no prior experience in coding I understood what you were saying.
Keep up the good work and good luck with your decoders
Nat🚂👍
Hi Nat, thanks! 🙂
I'm particularly pleased you were able to follow along without prior experience - it took me a little while to decide how to explain it all, but the visuals in this one took me absolutely ages to make!
This is one of those videos where the comments below it are just as educational as the video itself. Very cool project, I may give it a try as well some day. But I would definately do it in a faster language, probably in Go (because I'm most familiar with that...)
I've been surprised both at the level of interest in this video and the amount of helpful advice - it's going to be a challenge for me to take on board as much of the advice as possible! I'm vaguely considering learning Rust or Go, as memory-safe but fast programming options, but for now I've got too much to learn on the electronics side of things. Thanks for the comment 🙂
My few cents: Stick with a regulator for supplying power to the pico. Use a voltage divider using two resistors for the signal. Have a look at interrups and write the recieved bits into a circular buffer (ring buffer)
Thanks for your thoughts 🙂 I think a regulator from rectified power for the microcontroller would be sensible, and actually the DCC specifications say decoders should be able to work with up to 20V from the track, so I imagine it would help with that.
I actually started out using interrupts but got worse results that the polling; however, from what others have said it seems that could be at least partly to do with using the voltage regulator for the signal.
this is fascinating, best bit with going from the ground up is you actually know what its doing and why, helps with debugging.
I did similar, scalextric digital slot car stuff, way to go is to use interrupts (or the PIO on the RP2040, interrupts are easier). simple IRQ stores a flag. not too hard to get the timing between them in a loop, store it somewhere and use a state machine to process it
home made decoders are not generally small, they are however perfect for static decoders
Thanks 🙂
I found writing the code to use interrupts pretty easy to do, though the polling code is also easy. I think I'll start with an interrupt-driven approach when I move to C.
I have no idea what I'll actually be able to achieve with the circuit, but I'll have the freedom to make it a non-standard shape to fit the spaces in my locos, so that might help. I feel a long way off that yet though!
I'm seeing lots of good suggestions in the comments - one thing I will offer is this: As microcontrollers are designed to interface with the physical world much more than general purpose computers, there are often pieces of built in hardware to do tasks like asynchronous timing. For the 2040, the simplest way of accessing the hardware timers is by reading global system timer, which counts in microseconds. See section 4.6 of the datasheet for more info. A pin change interrupt to read this timer should be tight enough to get your the precision you need.
The "more correct" way of doing it is in section 4.5 PWM of the datasheet. In 4.5.2.5. Level-sensitive and Edge-sensitive Triggering it describes how to tell the PWM counter to count while there is a high level on its input pin. In this way you could measure the exact time of the high periods irrespective of what the core is doing at any given time. A pin change interrupt could then tell you when to read the value and allow you to clear it for the next count.
I don't generally program in high level languages, so I don't know what the overhead of these schemes would be in micropython, but as it is hardware based it should be agnostic to programming language.
Thanks for the extra information - I don't remember the PWM one being mentioned yet, though I'm finding it hard to keep track of all the suggestions! I'm quite happy to leave Python behind - I prefer it to write in, but not if it's going to cause extra headaches. The full details of the RP2040 datasheet are too much for me to digest at the moment - I'm pretty inexperienced with working with microcontrollers - what I've done with the Picos up to now has been relatively limited, so I'll take things slowly and see what I can get working in simple ways first. Thanks for taking the time to read the other comments and to write up those suggestions 🙂
@@endoorrailway for the vast majority of your programming, micropython is probably fine. For your timing critical tasks, tight routines written in C and triggered by interrupts may be necessary.
After a nice nap and some thinking, if you use an interrupt to put your high/low times into a circular buffer, the main program can read the buffer at its leisure and work out where the packets are and how to read them, completely asynchronous from the receipt of the 1s and 0s. The 2040 has loads of RAM, so you can make the buffer quite large too. Look for the preamble, count from there, and check for validity. Fortunately, us humans won't notice tens or even a few hundreds of milliseconds of delay between command and response.
Also, I suggest you throttle your main program loop to something in the 50-200Hz range if you are not already. Once again, you can use the system timer to decide when it is time to run a new execution of the main loop. The simple way to do this is to set a last-run time in the main loop, and then check the current system time against that time plus your timestep. No delay() commands (or whatever it is in micropython), as this will lock the uC's execution until the delay finishes. Running your main decision making code at a higher rate than this is likely unnecessary and can make it easier to decide how to split your CPU time.
Thanks for the follow-on advice 🙂 Good idea about deliberately throttling the main code - I haven't thought about power efficiency yet, but I've been surprised at how quickly the Pico is able to drain my _laptop's_ battery if powered from USB. The efficiency of modern hardware and software is very impressive.
Fascinating video. The digital trains to demonstate the packet contents was genius.
I thought using a voltage regulator to level change was a bit odd, and i am surprised you get as good results as you do.
As advised elsewhere there are probably better alernatives with voltage dividers or opto isolators or even capacitive isolator connections, although the latter will introduce other issues.
There may even be specialist level changing chips available given that it must be a fairly common requirement for 3v systems. I know there was for 5v systems, but am not familiar with 3v interface chips.
I shall be following your journey with interest
Thanks 🙂 Yes I'm very new to all this sort of electronics, so I may yet unwittingly do other things that are strange! I did searches for how to change the voltage level and there were various results, the regulator looked like a simple way, but it's abundantly clear now that other ways are better. The amount of advice I've been given from this video is great 🙂 Glad to have you along, thanks!
@endoorrailway the regulator will be fine for powering the pi. You just need to keep the signal inputs separate from the power inputs
I'm glad youtube recommends me this! I've been thinking on doing the same but I'd need to learn quite a lot of stuff and its quite a daunting task. I like the way you explained the dcc protocols and maybe I can replicate your work someday! (I know there are libraries for arduinos, but just like you, I want to know the inner workings of the dcc system as well)
Thanks - it took me a lot more effort to make this video than my usual ones because of the diagrams for the explanations, so I'm glad it's making a difference 🙂 I may make my eventual "production" code public on GitHub, but in a way it's a bit pointless because people like you and I want to do it ourselves from scratch anyway 🤣
I too find this daunting though - I'm comfortable with programming, but there's loads that I don't know about the electronics side. But it looks like there's plenty of community help available - I've been given good advice in comments already 🙂
Same here. I'd LOVE to convert all my locos ( 00 not N , thank goodness! ) to DCC, but the cost of loco modules is SOOO expensive, and then of course, the main controller as well....
I'm definitely looking forward to your solution. One question, is it possible to do it this with Arduino, as I have a spare Nano I can use for test purposes?
Cheers.
There are other people who've done it on Arduino - the search phrase "DIY DCC decoder" on Google brings back useful results. I read about some of the things linked from dccwiki.com/Do_It_Yourself#Decoders, but not in depth. I'm a long way off anything that can go into locomotive yet, but it looks like other people have done it already 🙂
@@alanclarke4646 IIRC, for the main controller you can use arduino with "DCC++" Although I've never used it myself
I to would be interested if you could share the code you have so far
The byte train was so cool
Thanks for saying so! There was a point when I was folding all the bits of paper where I was doubting the sanity of putting the time into it, so it's good to know when people enjoy it 🙂
@@endoorrailway It was 100% worth it. I'd love to see you do it again if its needed in a future video. As well as being fun to watch, it did genuinely help me understand better
@@MTMByt Awesome, I'm glad it worked for both purposes 🙂 I'll see how things pan out - at the moment, nearly a month from when I filmed that part, those wagons all still have their binary covers on, so it would be easy to re-use them.
This looks like a cool and fun project. A couple of suggestions:
For input use a comparator rather than the voltage regulator. It will give a digital output depending on where input A is higher than input B, or B is higher than A. Get one suitable input voltage range and 3.3V output and it can safely connect to the Pico.
For timings remember the phrase “be strict with what you produce and generous with what you consume”. If your outputting signal make them accurate. If your reading them accept input which is outside spec but which makes sense. For the timings here you basically need to set a cut off time between a short signal and a long one. That will make your code resistant to issues.
As for the code itself the PIOs on a Pico are specifically designed for processing serial data like this and they’re way, way faster than Python. Use them if you can. I’m not sure what that would look like here, people on the Raspberry Pi forums can probably give the best advice.
Thanks for your suggestions - they're helpful 🙂
A comparator or voltage divider sounds good - I'll be having a go with some resistors soon for the divider, and comparators look low-cost so might be worth trying too. Eventually I'll need to fit everything onto a circuit board that fits into a locomotive, so if I can get away with a couple of resistors that seems like it might take up less space than an integrated circuit package.
Yes a simple cut-off sounds good - I think the signal is likely to be good most of the time, and since commands are repeated it shouldn't matter if the odd one gets mangled somehow.
A couple of other people have mentioned PIO on the Pico - I hadn't come across that before. It does sound good, but ultimately I'm expecting to move to something physically smaller than the RP2040, so I don't want to develop things with things that are too Pico-specific.
@@endoorrailway Regarding resistor dividers, I’d be wary of voltage spikes causing damage to the Pico. To avoid that look for something called a protection diode and put in across the bottom resistor of the pair (assuming you’re powering the Pico from the rails. Between GND and the Gipson pin if not). This will prevent the voltage going higher than the diodes rating (which should the 3.3v here).
Thanks - that's worth knowing about - the DCC specifications for decoders state they should be able to work up to something quite high - I think it's 20 Volts - so I should consider it possible the controller could output that. Spikes could also happen for various reasons, so they're worth defending against if possible.
Great information here (both in the video and in the comments). All we need is for someone to make a RP2040 board small enough to fit in a N-gauge loco.
Thanks 🙂 That would certainly make things easier, though I think it would be hard to make a development board that small, given the large terminals around the edges. The RP2040 has lots more pins than should be needed for decoder purposes, so not connecting most of them to any terminals would help. Ultimately I'm not expecting to use the RP2040 for a final solution, but the Pico is what I've got available already and am (relatively) familiar with using in a basic way.
@@endoorrailway As a development board, the Pico is fine. It would be amazing to develop a board with a RP2040 (though another microcontroller would also be fine), the voltage handling circuitry and a speaker, in a form factor that fits most N-guage locos,
Don't know if this is mentioned already, but you might want use the DMA (direct memorry access) peripheral to read out the input automatically and write it to a buffer. A bit of a hassle to setup, but worth the performance as you are looking for microsecond measurements. Probably also possible to setup in python.
(Not sure on this, but i think DMA is capable of transferring gpio inputs at, or near, cpu clock speeds, so might also come in handy troubleshooting as a substitute for an oscilloscope/logic analyzer)
The PIO (programmable I/O) peripheral might also be a good option, as it is made with the intent of letting the user program a custom communication peripheral, with precise timing. Even more of a hassle than DMA, though😅
Thanks for the suggestion - yes a couple other have mentioned DMA and quite a few PIO - this week I'll write up a summary of suggestions and make it a pinned post.
Nobody has mentioned using DMA to turn a Pico into an oscilliscope though - that could come in handy if I'm having trouble later on having got past this accurate signal measuring step, especially as I'm trying to avoid buying an oscilliscope 🙂
Not a simple undertaking especially without an oscilloscope but you have the right attitude, read the spec, start simple and work up to something more feature rich. Monitoring both rails is really only done to improve reliability as it can be quite electrically noisy monitoring rail voltages. The PI pico has some clever state engine functionality on its GPIO pins that should allow you to measure the intervals without using the processor at all. This can then just DMA the results to a memory buffer for your code to look at. Using that your measured timings will be super accurate. This will however require you learning the machine code to program the state machines but I don't think it's very complicated as it only has a few instructions.
Thanks 🙂
Yes, a few other people have mentioned the state machine on the Pico - it's not something I knew about before - thanks 🙂
@@endoorrailway After thinking about this for a while I think it would be very easy to get this working using PIO programming, it would be able to capture predefined number of bits into a register then interrupt the processor to read the register. PIO clock speeds can be set accurately so you are always sure when signals change state.
One of the things I find weird is how the pico running at 48Mhz has throuble reliable decoding the DCC packets, while and Arduino running at 16MHz is reliable for decoding the packets.
Also, use a voltage devider, not a voltage regulator. a voltage regulator mangles signals like crazy. Even better would be an opto coupler
Consider buying an cheap osiloscope to view what you are actually working with
From what I read the Pico is 133 Mhz, so to take 30 microseconds to get a reading of the input means it's executed nearly 4,000 instructions! The fact the Arduinos can do all this reliably makes me think that MicroPython is the issue - before long I'll have a go at this with C, just to see the difference.
Several other people have also advised that the voltage regulator isn't the way to go, so I'll also see what resistors I've already got and make a voltage divider instead. It would then be interesting to see how the MicroPython does too after that.
I'm not expecting to need an oscilloscope for many things, so I'll see how far I can get along without one, but am open to the possibility I'll need to get one.
Thanks for the suggestions 🙂
Python is usually interpreted, whereas C++ (as it roughly is) on the Arduino is compiled. So every Python statement has to be read (often copied to an instruction buffer), taken apart, tokenised, parsed and then starts the execution of a fragment of machine code, and then the next part of the statement has to be... yes, you guessed it. I would normally reckon on interpreted code being 20 times slower than compiled code.
Compiled programs tell the processor exactly what to do, at full speed. They are, however, tricky to debug, the Arduino IDE and others have a good go at spotting errors at compile time, but after that, the processor will be on its own. There will be some error trapping, for out of memory access, numbers out of range, trying to put values into an input port and so on, but...
A good example, I wrote a fractal program in BASIC (interpreted) in 1988 that took 55 minutes to create the Mandelbrot set on screen. I then found a fractal program that did it using compiled machine code in about a minute. The BASIC was, however, good enough for a printer exerciser that wasn't time-crucial.
@@neilbarnett3046 Yeah, I remember thinking when he said it the budget was 100 instructions per microsecond that it would be fine in C or assembler where I'd expect 10 instructions per bit. But if Python is 10x worse that's 100 instructions and very close to being too slow. Python definitely has its uses in data science type applications but running it in a real time embedded system is not one of them. C is great for that sort of thing and if the C compiler does a bad job on the time critical parts you can just write them in a assembler.
@neilbarnett3046, @user-qf6yt3id3w There's some degree of compiling in Python, but I suppose it's more like caching because it's first done at runtime. But that's normal Python - I've not got any idea how MicroPython is implemented. I fully expect interpreted languages to be slower - really I was just having a go with MicroPython to see how it would turn out, and underestimated just how much work it's needing to do to be like standard Python. Eventually I'll get to trying some C on the Pico. Thanks for your comments 🙂
This is a great project. I think you need to be able to measure and see what you are measuring. Please borrow or buy an OSCILLOSCOPE. I have one on my desk at work and without it, you would be guessing. The idea of just using a voltage divider is a great idea. Yes a comparator may work, but you now have to worry about speed and false triggering. There are fast opto couplers available. I use one made by Sharp and has 5 pins, two for the LED inside and three for a 5V, Ground and signal. If memory serves it's called a PC400.
Best of luck with this. What I have seen is that when you can reliably trigger on your signal, then the decoding starts to make more sense as you are getting good data,
Thanks 🙂
With the various different suggestions I've been given I may well have to give in and buy an oscilloscope, just to see how the different approaches compare. Thanks for the component code - when I get a chance I'll need to go back through these comments and make a list of the things people have suggested and do some online shopping!
Great video, really interesting.
I would recommend taking a look at the PIO feature of the RP2040, I think you should be able to implement all of the timing critical low-level stuff with PIO, and just deal with protocol level stuff in micro-python.
Thanks!
I didn't know about PIO before making this video, but quite a few people have said likewise. Thanks for the suggestion 🙂
Absolutely LOVED this video... completely Nerdy and pushed so many of my buttons with reverse engineering, electronic, programming and Picos.
I think microPython and Pico PIOs is a good solution. I have a project 'picotimcode' which de/encodes a similarly structured protocol.
Use separate PIO blocks running small state-machines to break the capture/decode into several parts. Collate the bits and pass to microPython code via FIFO and interrupts.
I use one core to controll PIOs to do decode/encode, and the other core to do UI for controlling the whole lot.
Good luck, and thank you for bringing me smiles/entertainment.
Also when thinking about capturing bits, think in terms of time rather than voltage. Quick toggles vs slow toggles.... this should be easy for a PIO block.
Thank you very much 🙂 It's getting a lot more views and comments than is typical for my channel, so I think it's ended up appealing more to the general electronics hobby or pros than to just model train-loving folk!
Thanks for mentioning PIO - I haven't spent much time to date working with microcontrollers and hadn't come across it before making this video, but others have since mentioned it too.
I'm glad you like Picos too, but ultimately for this project I'm aiming to use something physically smaller than the RP2040 (some kind of ATTiny is what I have in mind), so I don't intend to go down the PIO route because it looks like it's specific to the Picos, but if I were sticking with a Pico then it does look like a good way to go.
I'm glad you enjoyed it, thanks for letting me know 🙂
@@endoorrailway there are quite a few _really_ small RP2040 and RP2350 boards, magic word is 'stamp'....
A stamp is too big for a lot of N gauge locomotives. For what they have crammed inside these systems on a chip are a real marvel of engineering, and so cheap for all the wonders they perform, but at 6.5-7mm square the RP2040 takes up a decent amount of space that I'll need for other bits and pieces like optocouplers, resistors, some kind of non-volatile storage, motor driver, amplifier etc. - I know there are less capable but much smaller chips around. I really don't know what will work, ultimately - I may well end up with an RP2040.
Rather than a regulator to reduce the track voltage, try using an opto coupler, that is what I use. You are going to struggle with the PI as there are other processes running in the background and these will be using some of the processor cycles and may delay events being detected giving eratic timings. The PI has a lot of things going behind the scenes. This is why an arduino at 16MHz can quite happily decode DCC as it only runs the code you place in it and there are no background processes.
He's using a PI Pico, which is just running his code in the same way as the AVR in an Arduino. The Pico is a microcontroller like the AVR, it's *NOT* a board running an OS like the PI4/PI5 etc.
@@RamothElectronics Sorry missed that, thought is was a standard PI.
@@RamothElectronics But if you want Linux running and Arduino at the same time try using the MilkV, can do both at the same time. SBC is not bigger than the rpi PICO.
Thanks for the info. Even though this is indeed a microcontroller, I was surprised at just how inefficient MicroPython seems to be - taking 30 microseconds to do something means nearly 4,000 clock ticks!
Good point about the optocoupler - I imagine it's possible to get very small ones too, which will be useful when trying to fit everything into an N gauge loco. Are they able to withstand 13-ish Volts coming in?
@@endoorrailway yes optos will work at that voltage, I work it out that you need 10mA to driver the opto, therefore if you have say 13V then you need probably a 1.5K Ohms resistor in series with the diode. The output needs to be pulled high with respect to zero volts by something like a 47K Ohms resistor. Chip resistors can be soldered directly onto the pins of the opto. When current flows in the diode side of the opto then the output will be pulled low.
And yes micro python is not efficient. C will probably get you a shorter code path, but i have never run it on a PI pico. Watch for useful efficiencies.
you can get small handheld scopes for about £50 nowadays - seems a must for this
I had a little look on the weekend, but it turns out there's a lot of variation on what they can do - the ones I found for less than £50 were mostly 200KHz, which would be too slow, and ones that were 1MHz for normal AC weren't clear what their ability was for measuring square wave signals. I really don't have much of a clue how to read their specs! Quite a few people think having one is a must, but I dislike shopping around for them, and I'll see how far I can get without one and consider it a last resort. Thanks 🙂
Enjoyed your video! What about using two diodes instead of the voltage divider or regulator for the input? Connect the catodes to each rail and the anodes to two different inputs of the Pico and perhaps separate pullup resistors between 3.3V and the anode of each diode.
Thanks 🙂 And thanks for the suggestion. The various helpful comments on this video have served to remind me just how little I know about electronics! Diodes just control which direction current can flow in, if my understanding of them is correct, and so I used them to split the signal - but the signal is at 13V, which is far too high for the Pico's (or other microcontrollers') inputs. Is your suggestion that, essentially, only a large enough resistor is needed in order to reliably reduce the voltage from 13V to 3.3V after the diodes? The Pico has internal pull-up and pull-down resistors, which one to use is configured in code, so at this stage I don't need to add any for that purpose as far as I'm aware.
@@endoorrailway With a diodes mounted the way I suggested, the current should only flow to through the diode and pull the input down to 0V when there's 0V on the rail (suggest using similar diodes as the rectifier to have the same voltage drop). When the rail is at 13V the diode blocks and pin is pulled up to 3.3V either internally or with a resistor.
Probably not necessary to monitor both rails, then you can use only one diode and input.
But I think a setup with an optocoupler as some already suggested is the most optimal way of harversting the signal.
Ah I see, that's neat, thanks!
I don't know the PI2040 as well as AVR microcontrollers but if that MCU has timers and at least one of them has a capture pin¹, then you can let that timer time every transition instead of doing it in code. Then all you have to do is subtract the previously captured value from the current one to get the length, in clock pulses of the bit you're measuring.
I've also seen suggestions about optocouplers. They're not fit for the job, they're too slow. Instead you may need signal shaping/debouncing done in hardware - unless the Pico has hardware mechanisms to filter spurious pulses away, of course. Micropython may be too slow even with this approach though. You'll have to assess that as well.
¹ A capture pin is used to copy the current counter value of a timer into specific registers, named capture registers, when a transition occurs on that pin. These transitions may also trigger an interrupt, which is useful to signal the application firmware an event occured.
Thanks for taking the time to write up that extra information, and for reading through the other comments to see what people have said. Interesting about the optocouplers - quite a few people are keen on those. I'll give a few things a go and see what kind of results I get - if the code is successfully getting the instructions I think the controller should be sending, and with enough time to do something with it, then it'll achieve what I'm after 🙂
Good evening Jonathan! I thoroughly enjoyed your journey exploring the DCC signal! Your visualisations were really compelling, especially the locos pulling wagons of bits around the track! Very clever! Your end goal of creating a sound decoder is fantastic, as I'm hoping you'll eventually confirm that we are currently paying well over the odds for what's involved! In terms of speed, I think C / C++ is the only way to go for this type of task, unless you can find a compiler for Python! Another route would be to find something that converts Python to C, if you're not familiar with programming in C! Give me a shout if you need a hand with the programming! I'm a bit rusty with C, but programming is like riding a bike isn't it? :) All the best, Ian.
Morning Ian, thank you very much! I don't find it too hard to come up with ideas for visualisations most of the time, but it takes me an absolute age to actually make them, so I'm glad you liked them! I was particularly pleased with the bit wagons, and those were comparatively quick to do too 🙂
As an aside while mentioning wagons - when I pre-ordered some with The Model Centre the other day I noticed that adding to Trunk was a delivery option - turns out they've implemented a Hattons-style trunk service!
There are many unknowns for me with what I'm trying to do - I'm expecting I'll need to use some kind of circuit printing service - I know they exist and that it's possible to get custom circuits for a few dollars, and that common components can be included... but what it will all come to in the end is a mystery to me right now. We'll see!
Thanks for your offer, but I'll be OK - I prefer Python these days but I've done C and C++ before, so am familiar with pointers etc. Plus like you say, once you've done enough programming new languages aren't usually much of a hurdle 🙂 The main thing I need to research is just what to do specifically for the Pico, but I'm expecting to be able to find guides for that very easily.
@@endoorrailway - Ooh! A new trunk service? That's great! Hopefully they'll also adopt Hattons pricing too, as I always think TMC is a little expensive compared to other retailers! I follow a few people who've used custom PCB making services, and they work great apparently! The more PCB's you order, the cheaper they are! No problem with the programming help offer, and good luck! :) Ian
According to Digitrax each rail is measured separately. Rail A and ground on your command station gives one number for voltage and Rail B and ground should give the same number no matter what system you are using. Try this to see what it is reading. Then adding both readings gives you the voltage output for both rails.
Thanks
Nyquist in frequency domain, rather than real time edge detection?
I hadn't heard of it before making this video, but someone else mentioned Nyquist too. The highest frequency would be the shortest DCC "one", which is 52μs - that would make the Nyquist frequency 26μs.
With 26μs samples a DCC "one" of 64 could potentially be measured as lasting 78μs, but the shortest a DCC "zero" could be measured at is 104μs. But with a 29μs sampling frequency a similar thing comes out - max One is 87μs, minimum Zero is 116μs.
I think if the interrupts run quickly enough when programmed using C (which I fully expect they will, based on what quite a few people have said), then that's probably the most elegant way to program things.
Thanks for the comment 🙂
I would look into using the PIO on the Pico. You should be able to read data using zero clock cycles on either core. This mean MicroPython is completely viable
Several other people have mentioned PIO too, thanks 🙂
Keep updated please ad progress thanks you
I'm glad you're interested in how this is going - so far I haven't done enough more for a second video. I managed to get some C running on the Pi Pico and ran some basic timing code on it reading the state of an input, and as expected it was a lot, lot faster to execute that than the Python had been. I also found resistors that I can use as a voltage divider and bought various capacitors and Zener diodes, to try implementing things people have suggested. It's going to be a long and slow project I'm afraid, just like everything else I do with the model railway 😆
The HW is "right". Meaning, the rectifier bridge with the voltage regulator. Don't forget some decoupling capacitors. DCC is in kilohertz square wave.
The code must be much more robust. Ideally, in C or assembly, using interrupts and HW timers, not relying on execution speed at all. Good luck :)
Thank you for your thoughts. I'll definitely be moving away from the voltage regulator between the signal and microcontroller inputs! Execution time will always be relevant - even in an efficient language and triggered by interrupts, instructions must still be executed for anything useful to be done. But knowing that C is a lot more efficient, and from what others have commented, I'm expecting switching to that make a big difference. Thanks 🙂
@@endoorrailway Also, get yourself a Pico 2.
@bexhillbob I probably will at some point, partly because I'm interested in trying Rust, but I don't think I need the RP2350 for this project.
I guess zero stretching is for determining witch rail is witch... try listening for stretched zeros first on both flanks to choose witch flank to listen to later.
Using PIO may be worth looking in to - You should be able to programing PIO from python.
I don't think so - the stretched zeros could be on either rail, and actually both could be stretched equally so long as their sum doesn't exceed 12,000 microseconds. I'm fairly certain it gets used for controlling DC locomotives, by making the current flow mostly in one direction, though I didn't see that purpose mentioned in the specifications.
Thanks, others have mentioned PIO too 🙂
@@endoorrailway Controlling DC locomotives... make sens. A bit harder then.
Listening on both flanks and summing up the absolute difference of periods before and after each flank while trying to ignore stretched zeros. Then, if the difference is bigger for raising flank use that, if the difference is bigger for falling flank us that.
But PIO is probably the best bet... Should give sub ms precision if wanted without loading the CPU at all.
Your multimeter likely doesnt measure peak voltage in ac mode, since if it did it would divide it by the square root of 2 before displaying it (since this resulting voltage value is the equivalent of the dc voltage that would dissipate the same power in the circuit, but only if the ac waveform is a sine wave).
More likely you have a good multimeter that actually performs integration on ac waveforms
You know, I never even considered that I might have a good one! I _think_ proper signal integration in AC mode is the first explanation I've heard that seems to explain why it gets both the sine and square waves correct. Thanks 🙂
i wonder what the proper commercial approach to signal conditioning is? is there anything in the spec that describes appropriate circuits for picking up the signal from the rails? in my opinion voltage regulators and voltage dividers are not going to be enough, and will be noisy. i think you might have better luck with optocouplers. these use a light (or infrared) emitting diode across the input signal to turn on a phototransistor on the output side, and will automatically produce a 3v3 signal that is completely isolated from the rail power. if you install two, and connect one in reverse, across the rails, you can select the polarity you are detecting. because optocouplers more dependant on current than voltage, it should give a much more reliable pickup, i think, and i strongly suggest you look into this. however i really would like to know what the specification expects. as for interrupt driven decoding, you may want to consider that there are different priorities of interrupts and, unless you use the highest priority, your interrupts will be postponed by anything else the system thinks is more important, and this will skew your timing. thank you for introducing me to this topic, it is fascinating.
In what I was reading I didn't come across anything that suggested implementation solutions, it was just specifying what needs to be achieved, but I haven't read through most of the documents - I was just trying to get started somewhere. The various specifications are at www.nmra.org/index-nmra-standards-and-recommended-practices
A few other people have suggested optocouplers too - I'll have to take a look at what's available - ultimately I'd like to make something that fits into an N gauge locomotive, so small surface-mount components will be needed. I'm sure there's be optocouplers that fit that constraint though 🙂
There was a nice guide about interrupt programming I read that's part of the MicroPython documentation; I'm not sure what other interrupts would be going on, but it seemed to be saying that all of the same priority would queue up if they overlapped, so I just left them at default. Maybe there are others happening that I don't know about, but I think they'll also be affected by the voltage regulator potentially distorting the timing, so there seem to be a few ways in which I could improve things.
Thank you for taking the time to share that useful information 🙂
@@endoorrailway i tried reading the spec, thanks for the link, but it seems they do not concern themselves with the actual interface, and these are proprietary. must first admit my electronics technical degree was a very long time ago, and i am very out of practise, but i think you could use a PC817, with an appropriate current limiting resistor, directly across the track signal, and you could then connect the ouput directly (and safely) to your GPIO pin. if the track voltage changes, though, you would need a different resistor.
It didn't take you long to scan a lot of information there! With a degree like that you'll have forgotten a lot more than I'm likely to learn in this field. Thanks for the suggested component - I'll have to start making a list of the various things that have been suggested.
Electric interface is not optimal but the bit train is gorgeous
Thanks 🙂
Any cheap Arduino-based board + interrupts should make light work of this. I am currently trying to do something similar to emulate the tape interface of an old Casio 80s handheld computer. But that is painful for many reasons.
You're undoubtedly correct, but I think only if a fast programming language is used too - the Pico is a lot faster than the Arduino-based boards. Tape-based, eh? Personally as an end-user I'm very pleased to leave tapes in the past, and CDs for that matter 🤣 Thanks for the comment 🙂
Maybe consider using Rust, rather than C or C++, and gives comparable performance, and pushes most errors and bugs from run time to compile time. Sadly though Rust programs are likely to us more RAM than C code.
I am indeed considering it - besides a quick search a month ago I don't know anything about it, but if it's going to be a major language that is fast but removes lots of memory management errors then it would be useful for me to learn. It caught my attention when the Pi Pico 2 launched and advertised support for it. From what I found there's support for Rust with ATTiny microcontrollers too, though I don't know how good it is. Thanks for the suggestion 🙂
Nyquist's sampling theorem applies to your track signals: you must sample at least twice as fast as the shortest pulse, so given shortest = 52us, you have to [be able to] sample at 26us intervals. I would suggest you sample at a faster rate than this though: it's common with UARTs to sample at 16x the baud rate, and while that might not be needed, 4x is probably a good thing to aim for.
I would strongly suggest looking at the "PIO" units of the Pico. They are kind-of a dedicated I/O processor, and will be able to sample the input very effectively. You can program them from a high level language and then get the benefit of full speed processing. There are a number of example configurations available in the pico SDK - look for example at the I2C and UART setups for inspiration, as they are doing similar things (sampling a pin and decoding signals on it).
I knew there must be a formula, thanks! With 26μs samples a DCC "one" of 64 could potentially be measured as lasting 78μs, but the shortest a DCC "zero" could be measured at is 104μs. But with a 29μs sampling frequency a similar thing comes out - max One is 87μs, minimum Zero is 116μs. I must admit I keep having thoughts like this, but eventually find a scenario that proves me wrong. So far 29 is the largest I've come up with where (I think) there can't be an overlap in interpreting the longest One and shortest Zero.
Thanks for mentioning PIO - it's not something I'd come across before making this video (I've not got a lot of experience with microntrollers), but a few other people have mentioned it since. I think it's specific to the Pico, so I'm not intending to go down that route to start with because there are physically smaller microcontrollers around, so I'm expecting to translate what I learn to another architecture.
Thank you for taking the time to explain those things 🙂
Regulator is awful solution to match signals voltage levels. Resistor divider will be enough, eventualy optocopuller or specialised level shifting ic (old ones from RS232)or just transistor.
Thanks for the info 🙂 Ah OK - out of curiosity, what makes the regulator so bad for this? I'll definitely need to scale this down though, and I know it's possible to get small surface-mount resistors, presumably also transistors and optocouplers. But wouldn't the resistor approach rely on the track voltage staying the same? In practice it does, but according to the DCC specifications a base station would be allowed to produce a lower voltage, and decoders should be able to cope with it. Plus locos might get poor pickup on occasions even if the track voltage is consistent.
I came here to say the same 🙂 : Nobody uses voltage regs as level shifters. I have not looked at the signal on a scope, but I don't think their startup time/speed will be reliable enough for proper timing. The pico should be plenty fast (I think) for what you are doing. You can try with a resistor divider if you do not want to isolate the track and pico with an optocoupler.
The voltage regulator is not ideal - a step change on the input will result in a slope change on the output. I recommend you use a high speed optocoupler (6N137 is commonly used). This will also protect your PC from any damage. In your final decoder, you can just use a series resistor to limit the current into your microcontroller and rely on its input protection diodes to clip the signal to 3V3 or 5V.
@@endoorrailway I only add some to what colegues wrote.
Those regulators work stable when some substantial current is drawn from output and today's microcontroller inputs are not taking current at all almost. Also they have some kind of regulation loop and may became oscilatiors without decopuling and they are not suited for high freqency signals as one write it may generate substantial slopes, especially when load is almost not existent. It may be mitigated partially by pulldown resistor on 3.3v side and some capacitors but sincerely I'm shocked that it works at all 😉
@@CarstenBe about lower voltage - if you do divider 1:4 for example then if input drops 1v then output drops 0.25v also voltage value accepted as logical 1 is quite wide starting from 2V also most microcontrollers will accept more than 3.3v some even 5v without harm, eventually you can add zener diode to for safety. But optocupuler maybe most safe and small solution.
Was hoping this would be a reproduction of the iron tangle...
I try not to make misleading thumbnails or descriptions - if it looks like it was going to be something else it's by accident.
It’s likely your meter isn’t a true RMS meter, so instead of taking a proper average it just takes the peak and multiplies with 2/3 which would be correct for a sign wave, but is wrong for any other wave like the square wave.
Thanks for the theory; in AC mode it does measure the DCC track voltage (without any of my diodes in place) as the expected 13V, so it must be taking a proper average to get that. The readings where it was 2/3 of full voltage were when it was in DC mode - I don't think it should be doing any kind of RMS (or an approximation) for DC, if nothing else because it would never produce a negative value. In DC mode it does correctly measure normal DC signals, like the supply for my LEDs, or the terminals of a 9V battery, as being at the expected voltages. Maybe I need to put it into AC mode and see what it makes of a single track's signal through the diodes - I didn't do that because the current isn't alternating. This multimeter was about £7, so it's not going to be a fancy one.
@@endoorrailway If you were to give your multimeter on AC a 13V sine wave, the peak voltage is going to be 1.4 times the RMS value, and the meter is calibrated to tell you that the RMS is 13V. This is the cause of your 2/3 and 3/2 values, though they sound like the average, rather than the RMS. Try that AC read on a 9V battery and see what you get, compare the DC and AC readings, that should calibrate the reading in your mind.
Most multimeters measure AC by rectifying the AC to DC and then dividing by 1.414, the square root of 2 (or multiply by 0.707, the inverse, it's the same result). This matches the definition for measuring an AC value, that it should come out the same as the DC voltage that would deliver the same POWER. (if you have root 2 times the voltage, you get root 2 times the current, and volts x amps = power.) For most multimeters, your AC range will read 13V RMS AC as being 13V and it will usually do the same for 13V DC, though it may say 18.3V... A smart multimeter will recognise DC and scale itself accordingly, though most simple multimeters are not that smart. You could try this and it will be informative.
It would seem that when no instructions are being delivered to the track, it rests at 13V DC. You could tell by putting a DC-only engine on, it should go like Mallard...
Multimeters are a black art that I mastered in 1973, but now can't explain very competently. It's been a while...
@neilbarnett3046 thanks for the information.
The 9V battery test is odd - in DC it measures 8.5 or -8.5 swapping the leads, so that seems about right. In AC it measures 18.8V with the leads one way, and 0V the other way. I expected about 12V or 13V regardless of which way around the cables were, if it were applying the scaling to get equivalent DC power.
I think I'll need to do some proper reading up on multimeters, or maybe buy one that comes with detailed documentation - I'm going around in circles with what I'm understanding of what people are telling me vs what I measured, but thank you for taking the time to try and help me with it!
smells a little like 12v canbus in a car, your rail 1 would be canH and 2 as canL
This is the first time I've tried to work with a digital signal at this level, so it's all "DCC stuff" to me, but it seems likely the engineers who designed it were familiar with other similar things like canbus and took inspiration. That would also help other engineers understand it and work with it easily as there'd be familiarity.
@@endoorrailway yes true, in fact just about all signalling systems have evolved from another before, no matter how complex they make it once it passes through circuitry it all boils down to just 1's and 0's.
this one is fairly basic in that theres no error correction just bad packet skipping, you want an headache, look into a cd players data stream thats designed to cope with random flipped bits from noise/dirt of the disc, its amazing how they even came up with it and I'm glad i'll never have to try to code for it....
At this stage I'm pleased that the error detection is just skipping and not correction! Yes I've been impressed with how well CDs can play even with a decent amount of scratching on them. I think that's going to be at a complexity beyond what I dabble in during my hobby time 😉
I assume that micropython is doing some garbage collection, so you might try force a gc.collect() at a time that makes it suitable for you.
Python is not going to be a real time os. You might be better trying to run DMA transfers and processing that instead of trying to poll it.
Thanks. The polling wasn't my first approach, but it was the one that worked best in MicroPython. I'll be moving away from MicroPython for this - I was hoping it would do the job, but it doesn't seem to.
@@endoorrailway At least with python you gave it a try and got to know a bit better about whats happening.
Thanks for sharing the video
There's a wide range of Open Source DCC decoders so unless your doing it for the thrills I don't really see the point in re-inviting the wheel. Had you picked Arduino/Teensy as a platform there's even a library for DCC decoding.
Yes - I did a bit of searching and found a few, including one that's specifically for the RP2040 - they gave me the confidence that it's feasible. I'm doing it from scratch for the fun of it, but if I get stuck or lose interest then I can move over to one of the existing solutions 🙂
Have you considered assembly language?
No - whilst I enjoy programming, C is about as low-level as I like, so if that's not fast enough I think I'll be giving up on writing the code myself 🤣
@@endoorrailway with those kinds of timings I'd expect you'll be fine in C on a pico or any modern microcontroller tbh. I'd certainly be doing it in C.
@@_cheesestraws_ Using the Pi Pico PIO's are really well suited for reading and creating the timings required for DCC
Thanks - I've only watched two videos comparing assembly (x86 in that case) with C, and they were pretty close.
I didn't mention it in this video, partly because I did the audio recording several weeks ago and them spent the rest of my time since then making the visuals, but the RP2040 isn't my end goal for this - I think physically it's too big to go on a board with other bits and fit into N gauge locos. That's not to say it couldn't be used in accessories, but they aren't my aim, so I'm using the Pico to get an understanding and prove some concepts but will probably end up trying an ATTiny eventually. I hadn't come across the PIO stuff before - from what I just read it does look like this is exactly the sort of thing it's for.
your multimeter is averaging not true rms therefore the real voltage reading should be multiplied by 1,4 to get an actual voltage, if you pass it trough fill bridge rectifier you should get that minus 0,7v
i still need to build my n decoder because everything off the shelve is just a bit too big
also your instructions don't have to be mesured with any high accuracy, since bit 1 and bit 0 are different length you just need to check every 0,7 of the length of the shorter bit and if value fliped read 0 and if it didn't set 1 and set interupt for another rising edge , then reset timer and do read again
To follow up, averaging RMS meters assume a sine wave amd multiply their measured value by 1.11 to approximate RMS. ( (sqrt(2)/2) / (2/pi) )
So divide by 1.11 to get the average value of your measured signal. Since average and RMS for square are the same, you're done.
Should be measuring less than two thirds though, I cant explain that @ 3:55.
Thanks @kokodin5895 and @electrowizard2000 for the information - this afternoon I looked up what RMS is and came to the same conclusion about the square wave, explaining the track output in AC mode. I don't think the multimeter would need to do RMS to measure DC, though - in fact it can't be, else it would never produce a negative reading, so for now I think the two-thirds thing remains a mystery.
@@electrowizard2000 this is not sine though, it is square wave alternating via h bridge from single positive voltage
if a meter has small bandwidth even if it is averaging it would measure much less than normal ac, most cheap meters is bandwidth limited to less than 1khz because ac they are ment to measure usually is 50-60 hz, the best way to measure this kind of voltahe is to put full bridge on it and measure dc and better yet use something like texas instruments active bridge rectifier and it would spit out 1/10 of rms voltage as a dc, i made meter like that to measue 14khz pulse voltage used in crt tv's as a heater voltage for the crt