
Nikola Tesla News
The Tesla Swarm Controller
Around this time last year, I began contemplating a new Tesla coil project. As some of you know, I find as much enjoyment building Tesla coil control panels as I do the actual building of the coils. I enjoy logic and automation. Developing Tesla coil control panels gives me an outlet for this. I've also had the desire to truly understand MIDI, and specifically, driving Tesla coils with MIDI. So I decided to develop my own controller.
Note: Historically, I've used Phillip's MPTCC controller. This is a 4-channel, bi-directional, C-based controller with a nice OLED display, four encoders, four switches and an SD card socket. It provides multiple drive types, such as: standard, ARSG emulator, MIDI input, MIDI file, etc. It's been a solid device that never lets me down. I can't speak highly enough about it and it greatly inspired this project.
I envisioned several new features for the controller:
- Level save function
- Ability to assign more than one output to a track
- Master level control
- Support more than four outputs
The first two months I spent just trying things. I took advantage of Black Friday last year to buy all sorts of microcontrollers and peripherals. I studied communications protocols, compared different hardware for performance and tested, tested and tested some more. I had so many versions of the controller, I ended up needing to develop a profile loader for the hardware so I could maintain the codebase across all the versions.
I looked at Arduino, ESP32 and settled on Raspberry Pi Pico 2 as my microcontroller of choice. The primary reasons were: fast RAM, dual core, and fast bus speed. I also picked it for its compatibility with MicroPython, which I had been looking for an excuse to learn for years.
At some point in this process, I happened across one of those videos where drones are used to paint objects in the sky using LEDs. They were being called drone swarms. It occurred to me, what would it be like to have a swarm of Tesla coils? I wondered how many coils I might possibly control with my project and make my own Tesla coil swarm!
So then it became a quest to see just how many outputs I could drive with the tiny RP2350 in the Pico 2. The data sheet for the device touts a whopping 24 PWMs! Could that mean I could run 24 coils from one Pico 2? Hardly! The truth is, a single RP2350 can only provide 8 unique PWM outputs, period, end of story. CircuitPython actually won't allow you to create the objects, it throws an error. MicroPython makes you think it's working, but it's not.
The whole input situation is another big dilemma... To provide level controls for even 4 outputs, using basic encoders chews up most of the available GPIO pins, so those were out of the question. We need those pins for the 8 outputs. Plus, we've not even gotten to the display and SD card reader. The solution was to use I2CEncoders! The I2C bus allows you to chain many devices, each having their own address. And best of all, only requiring three GPIO pins. I have a 16-channel prototype and the I2C encoders work great, that is, once I learned what mutexes were. That's a story for another post.
The next dilemma was the display. For the Pico 2, you typically have two choices: SPI or I2C. The big difference here is SPI is way, way, WAY faster. The drawback is SPI devices aren't addressable. An SPI bus can be shared with some devices, but sharing logic must be handled in code and sharing doesn't work with devices that need to be in use simultaneously, like an SD card reader and a display! Doh!
There's also the problem of just how many output level percentages you can display on a given screen. And sure, you can use I2C muxes, or other methods, to provide multiple displays, but there's a catch... They're slow! Display frame buffers are big and I2C is slow. This causes the controls to be sluggish and there's noticeable delays in output adjustments. In my opinion, the 256x64 is the largest display you should consider for the RP2350, and it just so happens you can fit 8 output levels on the screen very nicely.
In my mind, this settled it. A Pico 2 can be used to control a maximum of 8 Tesla coils. The PWM hardware and practical display options limit them to this number. But how might we work around this? I'm not sure 8 Tesla coils could be considered a swarm. Another thing to think about is that most MIDI files don't even have 8 tracks, or if there are that many, a lot are drums, which aren't typically desirable for Tesla coils. But what if we could have multiple copies of the same 8 outputs and what if a track could be assigned to more than one output?
I played with I2C-slaved external PWM devices, and even I2C-slaved Pico 2's, for a while, but they were just too slow. When considering MIDI music, a lot of things can happen at once when working with multiple tracks. Only the most staccato-like songs can be played on more than four outputs using I2C. The other thing is that I2C has a limited range, measured in inches and we need feet. I2C is just not practical for outputs.
This really boils down things to the SPI bus, but of course, this comes with another dilemma. The RP2350 only has two SPI interfaces. Remember, we've got the display and the SD card reader, both of which need to be interacted with simultaneously. For the real nerds, this is because the umidiparser class being used does incremental reads and keeps the MIDI file open the entire time it's decoding. It must do this because only the smallest MIDI files can be read into memory all at once. I wondered if this sealed the fate of any chances of going beyond 8 Tesla coils at once.
During my hours and hours pouring through MicroPython forums and examples working on this project, one name kept popping up, over and over. That name is Peter Hinch. I drew a lot of inspiration from his work and the help he provided others. When it became apparent I needed to use asyncio to process I2CEncoder inputs, lo and behold, come to find out, Peter wrote it!
I reached out to Peter early on and for months now, he's bailed me out several times. I explained my dilemma with the SPI buses and Peter alluded to using PIO or DMA to emulate a third SPI interface. There was an existing RP2040 PIOSPI example in a GitHub repo. Peter helped me tune it up and get it going, but it was hardly faster than I2C and caused the same sluggishness with the controls. I showed the project to Peter anyway and somehow I inspired him. Much to my surprise, a few days later, he emailed that he'd gotten it to work with DMA. I created a new display driver to work with the DMA-emulated SPI interface and it worked so well, I can't really tell any difference with the native SPI bus. It's great and best of all, freed up a native SPI bus we can use for outputs. But what type of SPI device would I use?
My first consideration was an SPI to CANBUS interface. I liked the sound of noise immunity, long runs and addressable devices. But in running the numbers, CANBUS is hardly better than I2C, speed-wise, even on SPI. Plus, if we're talking about driving multiple outputs with the same 8 channels, what would be ideal is putting out a single instruction that applies to all outputs at once rather than sending instructions to each device separately, by address.
Then, a eureka moment! What I was contemplating was beginning to sound a lot like UDP! This is a protocol provided by the TCP/IP stack in networked devices. It includes a broadcast feature allowing the same packets to be received and processed by any devices within the same subnet. If this would work, it would mean I could control 253 Pico 2's each having their own 8 outputs! SPI ethernet was the answer! A 2,000 Tesla coil swarm! Now we're talking!
We'll continue talking in part two of this post. In the meantime, you can check out the world's first-ever, 64 Tesla Coil Swarm here: