mamot.fr is one of the many independent Mastodon servers you can use to participate in the fediverse.
Mamot.fr est un serveur Mastodon francophone, géré par La Quadrature du Net.

Server stats:

3.5K
active users

#neopixel

3 posts3 participants1 post today
Simple DIY Electronic Music Projects<p><strong>Forbidden Planet “Krell” Display EuroRack&nbsp;Module</strong></p><p>This project uses my <a href="https://diyelectromusic.com/2025/01/25/forbidden-planet-krell-display/" rel="nofollow noopener noreferrer" target="_blank">Forbidden Planet “Krell” Display</a> and the <a href="https://diyelectromusic.com/2025/03/30/forbidden-planet-krell-display-pcb-design/" rel="nofollow noopener noreferrer" target="_blank">Forbidden Planet “Krell” Display PCB&nbsp;Design</a> but with some slight variations that means it could be EuroRack mounted with a control voltage (CV) input.</p><p><strong><em>This is a DIY module only for use in my own DIY system.</em></strong></p><p><strong>Do NOT use this alongside expensive modules in an expensive rack. It is highly likely to cause problems with your power supply and could even damage your other modules.</strong></p><p><a href="https://makertube.net/w/qJqgTxxsEznTuF2DRVZT9o" rel="nofollow noopener noreferrer" target="_blank">https://makertube.net/w/qJqgTxxsEznTuF2DRVZT9o</a></p><p><em><strong>Warning!</strong> I strongly recommend using old or second hand equipment for your experiments.&nbsp; I am not responsible for any damage to expensive instruments!</em></p><p>If you are new to microcontrollers, see the&nbsp;<a href="https://diyelectromusic.wordpress.com/getting-started/" rel="nofollow noopener noreferrer" target="_blank">Getting Started</a> pages.</p><p><strong>Parts list</strong></p><ul><li>3D Printed EuroRack format Krell Display unit.</li><li>Waveshare Zero format board – <a href="https://diyelectromusic.com/2025/02/17/waveshare-zero-pimoroni-tiny-and-neopixels/" rel="nofollow noopener noreferrer" target="_blank">details here</a>.</li><li><a href="https://diyelectromusic.com/2025/03/30/forbidden-planet-krell-display-pcb-design/" rel="nofollow noopener noreferrer" target="_blank">Forbidden Planet “Krell” Display PCB</a> built for EuroRack use (see below).</li><li>Additional companion EuroRack power PCB (see below).</li></ul><p><strong>EuroRack 3D Print Design</strong></p><p>This is an evolution of my original <a href="https://diyelectromusic.com/2025/01/25/forbidden-planet-krell-display/" rel="nofollow noopener noreferrer" target="_blank">Forbidden Planet “Krell” Display</a> box, but fitting into EuroRack dimensions: 128.5 x 60, which essentially makes it a 12 HP module.</p><p>It still takes the same inserts however, but now also includes options for holes for jack sockets or potentiometers:</p><pre>show_eurorack = 1;<br>show_eurorack_support = 1;<br><br>alg_pot1 = 1;<br>alg_pot2 = 1;<br>alg_cv = 0;</pre><p>I’ve also included a special “supports” option for use with the PCB and the EuroRack case.</p><p><strong>Krell Display PCB – EuroRack Build</strong></p><p>To build one of my <a href="https://diyelectromusic.com/2025/03/30/forbidden-planet-krell-display-pcb-design/" rel="nofollow noopener noreferrer" target="_blank">Forbidden Planet “Krell” Display PCB&nbsp;Design</a>s for use with a EuroRack, follow the previous <a href="https://diyelectromusic.com/2025/03/30/forbidden-planet-krell-display-pcb-build-guide/" rel="nofollow noopener noreferrer" target="_blank">Build&nbsp;Guide</a> but note the following differences:</p><ul><li>The MIDI circuits are not required when used as a CV input device.</li><li>The lower potentiometer should be replaced with a CV input circuit.</li><li>The upper potentiometer is optional, but I’m omitting it for my build.</li><li>Power will come via the 5V jumper headers from an additional EuroRack power PCB (details below).</li><li>Low-profile (e.g. 9mm high in total) headers should be used for the Waveshare Zero, but once again note the errata about the footprint on the PCB being too wide.</li></ul><p>Here are some build photos of a build for EuroRack use. For this build there are only two diodes (the two BAT43) and two resistors (22K and 33K). Also note that none of the 100nF ceramic capacitors are required either.</p><p>Both electrolytic capacitors have been soldered into position on their sides as show below.</p><p>The Thonkiconn style mono jack shares the footprint are of the lower potentiometer on the LED side of the board, but be sure to get use the correct mounting holes as shown by the orientation below.</p><p>Nothing has been soldered to the power jumper yet. See the discussion below for how to link this to the power board.</p><p><strong>Krell Display Companion EuroRack Power PCB</strong></p><p>Bill of Materials:</p><ul><li>Waveshare Zero “Krell” Display EuroRack power PCB (Github Link below).</li><li>L7805 TO-220 format regulator or equivalent (see discussion below).</li><li>1x 16-way DIP EuroRack shrouded header.</li><li>1x 1N5017 Zener diode.</li><li>2x 47uF electrolytic capacitors.</li><li>1x 100nF ceramic capacitor.</li><li>2-way Jumper header socket and pins (probably need extended pins – see discussion).</li></ul><p>I’ve opted to use a DC-DC converter with a 7805 physical footprint as shown below.</p><p>If a 7805 regulator is used then a heatsink will almost certainly be required. I’ve oriented the regular to allow for a “tab up” mounting which hopefully leaves plenty of room for some kind of heatsink to be used.</p><p>Here are some build photos.</p><p>There is an option on the PCB to install a 10R resistor as is sometimes recommended for EuroRack modules. From what I’ve read this seems to be to allow it to act as a “fuse” in the case of an incorrectly wired module. As I’ve discussed before (<a href="https://diyelectromusic.com/2025/02/22/minidexed-eurorack-pcb-design/" rel="nofollow noopener noreferrer" target="_blank">see here</a>) I’m not sure this is so relevant for me, so I’m using the provided solder bypass bridge to leave it out.</p><p>Note the orientation of the DC-DC converter.</p><p>I’ve used extended pin headers for the power link between the two boards, but due to an error in positioning, they’ve had to be bent over slightly – more on that later.</p><p><strong>Physical Build</strong></p><p>A completed unit has the following parts:</p><ul><li>3D printed case, PCB supports, and two “krell” inserts.</li><li>Main PCB built for EuroRack use as described above.</li><li>Power PCB as described above.</li><li>M2.5 spacers and fixings as follows:<ul><li>4x 6mm M2.5 brass fixings.</li><li>4x 15mm M2.5 nylon fixings.</li><li>4x M2.5 nylon screws.</li></ul></li></ul><p>The power link between the two PCBs has to be trimmed and slightly bent as shown below.</p><p>Once the whole thing is put together, there isn’t room, at least on my build, for the nut to be put on the jack socket. Also, the 6mm and 15mm spacers might be slightly too short, depending on how far off the PCBs the LEDs ended up. Some experimentation and “encouragement” is probably required to get everything together.</p><p><strong>The Code</strong></p><p>The code is relatively straight forward, and is largely a mix of the analog and neopixel test code from the <a href="https://diyelectromusic.com/2025/03/30/forbidden-planet-krell-display-pcb-build-guide/" rel="nofollow noopener noreferrer" target="_blank">Forbidden Planet “Krell” Display PCB Build&nbsp;Guide</a>.</p><p>One quirk is scaling the analog read from 0..65535 to a useful 0-10 to allow for zero to 10 leds to light up. I’ve allowed for a range of values to be “basically zero” too to allow for some jitter or noise.</p><p>As I only write out to the neopixels when something changes, this code seems to be quite responsive.</p><p>This requires the following Adafruit Circuitpython Library Bundle libraries:</p><ul><li>neopixel.mpy</li><li>adafruit_pioasm.mpy</li><li>adafruit_pixelbuf.mpy</li></ul><p>In fact, the entire Circuitpython code is given below.</p><pre>import time<br>import board<br>import neopixel<br>from analogio import AnalogIn<br><br>cv_in = AnalogIn(board.A3)<br><br>pixel_pin1 = board.GP2<br>pixel_pin2 = board.GP3<br>num_pixels = 5<br><br>pixels1 = neopixel.NeoPixel(pixel_pin1, num_pixels, brightness=0.3, auto_write=False, pixel_order=neopixel.RGB)<br>pixels2 = neopixel.NeoPixel(pixel_pin2, num_pixels, brightness=0.3, auto_write=False, pixel_order=neopixel.RGB)<br><br>col = (80, 35, 0)<br><br>lastcv = -1<br>while True:<br> cv = cv_in.value / 256<br><br> if (lastcv != cv):<br> lastcv = cv<br> led = cv / 25<br> for pix in range(5):<br> if (pix &lt; led and cv &gt; 5):<br> pixels1[pix] = col<br> else:<br> pixels1[pix] = 0<br> <br> if (pix+5 &lt; led and cv &gt; 5):<br> pixels2[pix] = col<br> else:<br> pixels2[pix] = 0<br> <br> pixels1.show()<br> pixels2.show()</pre><p><strong>GiHub Resources</strong></p><p>There is now an updated version of the OpenSCAD code for the case on GitHub and the PCB and code are also now available.</p><ul><li>OpenSCAD code and STL models: <a href="https://github.com/diyelectromusic/sdemp_3dprints/tree/main/KrellDisplay" rel="nofollow noopener noreferrer" target="_blank">https://github.com/diyelectromusic/sdemp_3dprints/tree/main/KrellDisplay</a></li><li>PCB: <a href="https://github.com/diyelectromusic/sdemp_pcbs/tree/main/WaveshareZeroKrellDisplay" rel="nofollow noopener noreferrer" target="_blank">https://github.com/diyelectromusic/sdemp_pcbs/tree/main/WaveshareZeroKrellDisplay</a></li><li>Code: <a href="https://github.com/diyelectromusic/sdemp/blob/main/src/SDEMP/CircuitPython/KrellEuroRackDisplay.py" rel="nofollow noopener noreferrer" target="_blank">https://github.com/diyelectromusic/sdemp/blob/main/src/SDEMP/CircuitPython/KrellEuroRackDisplay.py</a></li></ul><p><strong>Closing Thoughts</strong></p><p>This isn’t a perfect build in mechanical terms, but I’m not sure I ever do anything perfectly anyway, especially where mechanical things are concerned, but the final result is pretty pleasing.</p><p>The video shows it running with a Pimoroni RP2040 in the driving seat. First a potentiometer provides a 0 to 5V input, then I’m using my <a href="https://diyelectromusic.com/2024/05/07/educational-diy-synth-thing/" rel="nofollow noopener noreferrer" target="_blank">Educational DIY Synth&nbsp;Thing</a>‘s LFO to provide a 0 to 3V3 input.</p><p>Kevin</p><p><a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/circuitpython/" target="_blank">#circuitpython</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/eurorack/" target="_blank">#EuroRack</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/krell/" target="_blank">#Krell</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/neopixel/" target="_blank">#NeoPixel</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/potentiometer/" target="_blank">#potentiometer</a></p>
Ian Neill<p>I have hit a tough spot in an existing project, so while I think about it, how about a distraction project!</p><p>Behold a NeoPixel clock ⌚</p><p>An abstract (to me) clock using 2 NeoPixel rings to indicate the time using the position and colour of the pixels.</p><p>I added a TM1637 based 6-digit 7-segment display too, because it was on the table beside me, and why not?</p><p>More ideas to implement, but pleased with it so far.</p><p>All the code on GitHub. Enjoy!</p><p><a href="https://github.com/ilneill/NeoPixelClock" rel="nofollow noopener noreferrer" translate="no" target="_blank"><span class="invisible">https://</span><span class="ellipsis">github.com/ilneill/NeoPixelClo</span><span class="invisible">ck</span></a></p><p><a href="https://mastodon.ie/tags/Arduino" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Arduino</span></a> <br><a href="https://mastodon.ie/tags/NeoPixel" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>NeoPixel</span></a> <br><a href="https://mastodon.ie/tags/TM1637" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>TM1637</span></a></p>
Andy Warburton ❌❌❌<p>I think I’m happy with this enclosure design! All goes together with friction. No screws needed! <a href="https://mastodon.social/tags/3dprinting" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>3dprinting</span></a> <a href="https://mastodon.social/tags/3dprinted" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>3dprinted</span></a> <a href="https://mastodon.social/tags/wled" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>wled</span></a> <a href="https://mastodon.social/tags/rgbled" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>rgbled</span></a> <a href="https://mastodon.social/tags/rgb" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>rgb</span></a> <a href="https://mastodon.social/tags/neopixel" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>neopixel</span></a> <a href="https://mastodon.social/tags/maker" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>maker</span></a> <a href="https://mastodon.social/tags/makers" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>makers</span></a> <a href="https://mastodon.social/tags/electronics" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>electronics</span></a></p>
Simple DIY Electronic Music Projects<p><strong>Forbidden Planet “Krell” Display – MIDI Notes – Part&nbsp;2</strong></p><p>As I mentioned in <a href="https://diyelectromusic.com/2025/01/26/forbidden-planet-krell-display-midi-notes/" rel="nofollow noopener noreferrer" target="_blank">Forbidden Planet “Krell” Display – MIDI&nbsp;Notes</a> I’m building a simple (in function, not in execution it would seem) MIDI note display out of my <a href="https://diyelectromusic.com/2025/01/25/forbidden-planet-krell-display/" rel="nofollow noopener noreferrer" target="_blank">Forbidden Planet “Krell” Display</a>.</p><p>The first attempt showed there is potential, but I was rapidly reaching the limits of what an Arduino could do for me using the off-the-shelf common Adafruit_NeoPixel library.</p><p>In this part, I’ve taken forward one of the possible optimisations and I’ve split the display up into separate strips of LEDs. It seems to work a lot better.</p><p><a href="https://makertube.net/w/tVb2dGqAFarS8mB14t9JSR" rel="nofollow noopener noreferrer" target="_blank">https://makertube.net/w/tVb2dGqAFarS8mB14t9JSR</a></p><p><em><strong>Warning!</strong> I strongly recommend using old or second hand equipment for your experiments.&nbsp; I am not responsible for any damage to expensive instruments!</em></p><p>If you are new to Arduino, see the&nbsp;<a href="https://diyelectromusic.wordpress.com/getting-started/" rel="nofollow noopener noreferrer" target="_blank">Getting Started</a> pages.</p><p><strong>Parts list</strong></p><ul><li>Completed <a href="https://diyelectromusic.com/2025/01/25/forbidden-planet-krell-display/" rel="nofollow noopener noreferrer" target="_blank">Forbidden Planet “Krell” Display</a>.</li><li>Arduino Nano or Uno.</li><li>MIDI Interface, e.g. <a href="https://diyelectromusic.com/2021/03/16/diy-midi-interfaces/" rel="nofollow noopener noreferrer" target="_blank">DIY MIDI Interfaces</a>, <a href="https://diyelectromusic.com/2020/11/30/ready-made-midi-modules/" rel="nofollow noopener noreferrer" target="_blank">Ready-Made MIDI Modules</a>, and so on.</li><li>Breadboard and jumper wires.</li></ul><p><strong>The Circuit</strong></p><p>As I mentioned in part 1, there is a significant limitation due to the time it takes to scan all of the LEDs in eight connected rings. For all 56 LEDs it takes almost 2mS and interrupts are completely disabled during that time meaning that MIDI data is getting lost.</p><p>But by splitting those rings up into groups of two, I can cut the scanning time down to less than 600uS. This compares favourably with the time it takes to process and store a single byte of MIDI data. At 31250 baud that is around 320uS and one character can be stored within the UART hardware while another character is being received.</p><p>Consequently, each pair of LED rings is now connected to its own Arduino GPIO pin. I’m using pins D8-D11 for my four rings.</p><p><strong>The Code</strong></p><p>A lot of the code is similar to the <a href="https://diyelectromusic.com/2025/01/26/forbidden-planet-krell-display-midi-notes/" rel="nofollow noopener noreferrer" target="_blank">prevous post</a> but I’ve had to add in an additional layer of abstraction to cope with the fact that the led array is now spread over four separate Adafruit NeoPixel controls.</p><pre>#define LED_BLOCK 5<br>#define LED_RINGS 8<br>#define LED_COUNT (LED_BLOCK*LED_RINGS)<br>#define STRIP_BLOCK 7<br><br>int ledpattern[LED_BLOCK] = {1,0,5,4,3};<br>int leds[LED_COUNT];<br>int ledState[LED_COUNT];<br>bool ledUpdate;<br><br>#define NUM_STRIPS 4<br>int ledPins [NUM_STRIPS] = {8,9,10,11};<br>int stripCounts [NUM_STRIPS] = {2,2,2,2};<br>#define STRIP_FORMAT (NEO_GRB + NEO_KHZ800)<br>Adafruit_NeoPixel *strip[NUM_STRIPS];</pre><p>Now, I’m using an array of NeoPixel objects, which will be dynamically created as part of the startup routines. There is the ability to define the pin and number of rings per strip too. In the first version I had three strips defined of 2, 4 and 2 rings respectively, but the 4-ring strip was still causing lost notes. Eventually I settled on four pairs and that seems to work.</p><p>Initialising the real pin numbers is a little more complicated now as each strip has to restart from 0 when mapping my 5 LEDs over to the 7 physical LEDs per ring.</p><p>Each strip is initialised as follows:</p><pre> int blockstart = 0;<br> for (int i=0; i&lt;NUM_STRIPS; i++) {<br> strip[i] = new Adafruit_NeoPixel (STRIP_BLOCK*stripCounts[i], ledPins[i], STRIP_FORMAT);<br> strip[i]-&gt;begin();<br> strip[i]-&gt;show();<br> strip[i]-&gt;setBrightness(50);<br><br> if (i &gt; 0) {<br> blockstart += stripCounts[i-1];<br> }<br> for (int j=0; j&lt;stripCounts[i]; j++) {<br> for (int k=0; k&lt;LED_BLOCK; k++) {<br> leds[LED_BLOCK*(blockstart+j) + k] = ledpattern[k] + STRIP_BLOCK*j;<br> }<br> }</pre><p>The leds[] array is still a single array with an entry for each “virtual” LED (i.e. one of each of my 5 in use LEDs per ring) and it still has to be initialised with the pattern of real LEDs. This has the benefit that the core interface to the LEDs still gives the impression of a single list of LEDs in a single virtual strip. The only slightly more complicated bit is when it comes to updating the strips from the internal record of which LEDs are on or off.</p><p>I know have a new function to scan a single strip</p><pre>int startled;<br>void scanOneStrip (int ledStrip) {<br> if (ledStrip == 0) {<br> startled = 0;<br> } else {<br> startled += LED_BLOCK * stripCounts[ledStrip-1];<br> }<br> int numleds = LED_BLOCK * stripCounts[ledStrip];<br> strip[ledStrip]-&gt;clear();<br> for(int i=startled; i&lt;startled+numleds; i++) {<br> if (ledState[i]&gt;0) {<br> strip[ledStrip]-&gt;setPixelColor(leds[i], strip[ledStrip]-&gt;Color(80, 35, 0));<br> }<br> }<br>}</pre><p>The trick here is to calculate the correct starting LED in the virtual array for this strip and then act accordingly.</p><p>There is one dependency that it would be nice to get rid of though – this assumes that each strip will be scanned in order – it calculates the start LED based on the cumulative addition of the strip lengths so far. If this is called out of order, it will probably break.</p><p>The controlling function presents the same interface as before, but now allows for repeated calls to scan each strip in turn. Remember a key point of doing things this way was to allow the strip updating to return to allow more MIDI message processing inbetween scanning each strip.</p><pre>int currentStrip;<br>void scanStrip () {<br> if (ledUpdate) {<br> if (currentStrip &lt; NUM_STRIPS) {<br> scanOneStrip(currentStrip);<br> currentStrip++;<br> } else {<br> ledUpdate = false;<br> currentStrip = 0;<br> }<br> }<br>}</pre><p>Notice how the ledUpdate flag is only cleared once all strips have been scanned.</p><p>One indication of how much better this approach is, is that I’ve been able to implement a note count – I now keep track of the number of NoteOn vs NoteOff messages for each note, meaning that the lights won’t go out whilst a note is still hanging on. If there were any issues with stuck notes now, these counters would get out of sync very quickly (which they were doing when I tried to have one strip of four rings – hence going down to two).</p><p>I’ve kept the global inactivity timer though, just in case.</p><p><a href="https://github.com/diyelectromusic/sdemp/tree/main/src/SDEMP/ArduinoKrellMIDIDisplay2" rel="nofollow noopener noreferrer" target="_blank">Find it on GitHub here</a>.</p><p><strong>Closing Thoughts</strong></p><p>Whilst obviously a fair bit more complicated both in code and wiring, I was surprised at how well this seems to work.</p><p>In the video you can see my Lo-Fi Orchestra arrangement of Sky’s Toccata and it is possible really start to see the shape of the music in the display.</p><p>Still completely impractical of course – I mean I’m attempting to map 12 musical “units” (of pitch) onto a display that has 10 display “units” (of LEDs) so it isn’t a natural fit.</p><p>But it does now seem to work, and I feel now that if required, and power limits not withstanding, several more pairs of rings could be added each with their own GPIO driver pin and performance ought to keep up fine.</p><p>So the question is – do I keep trying other solutions or move onto something else…</p><p>Kevin</p><p><a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/arduino/" target="_blank">#arduino</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/define/" target="_blank">#define</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/forbiddenplanet/" target="_blank">#ForbiddenPlanet</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/krell/" target="_blank">#Krell</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/neopixel/" target="_blank">#NeoPixel</a></p>

Forbidden Planet “Krell” Display – MIDI Notes

This is my first attempt at some kind of MIDI related visualisation for my Forbidden Planet “Krell” Display. I thought I’d start easy and simply map MIDI notes onto the segments and create a simple display. That turned out to be an awful lot more involved than I imagined…

In fact, this is quite sub-optimal – it largely works but does suffer still from the occasional missed MIDI message, which will almost certainly lead to stuck notes at some point.

In this post I talk through what the issue is and the various mitigations I’ve put in place to attempt to minimise the problem. Finally I present some alternative ideas that I’ll follow up in future posts.

Fundamentally, these days there are much better options for this than an Arduino Nano or Uno.

https://makertube.net/w/qwM4gzPpDSthHY1Mkutr4P

Warning! I strongly recommend using old or second hand equipment for your experiments.  I am not responsible for any damage to expensive instruments!

If you are new to Arduino, see the Getting Started pages.

Parts list

I’ve started with an Arduino Nano, but as we’ll see later, choosing a single-core, 8-bit microcontroller is certainly playing this game on “hard mode”.

I’ve written up what I have for my own interest as it is an interesting problem to solve and interesting to me to see how far I can push it, but if you’re after a more useful solution it is probably worth waiting for a later post where I can show how to use a more suitable microcontroller for this task 🙂

The Circuit

As detailed in my previous post I can just about get away with powering my 8 LED rings from the Arduino provided I keep the power levels down and don’t drive the too much.

I’ve actually used a ready-made MIDI module with a hardware MIDI THRU, again for reasons that will hopefully become clear as I talk about the performance later on.

Using THRU allows me to send data into the Arduino and use that same data to drive a sound source too.

The Code

Once again, I’m using the LED “mapping” technique from my original Forbidden Planet “Krell” Display test code, so that side of things is largely unchanged.

I’m adding in basic MIDI handling using a NoteOn and NoteOff parser to indicate that the LEDs need turning on or off. In this first version I’m just using simple logic as follows:

void handleNoteOn(byte channel, byte pitch, byte velocity) {
if (velocity == 0) {
// Handle this as a "note off" event
handleNoteOff(channel, pitch, velocity);
return;
}

int led = pitch - MIDI_NOTE_START;
ledOn (led);
}

void handleNoteOff(byte channel, byte pitch, byte velocity) {
int led = pitch - MIDI_NOTE_START;
ledOff (led);
}

There is some bounds checking added too, but that is essentially it. The downside of this approach is that if several NoteOn messages are received, the first NoteOff message will turn the LED off even if another note is still hanging on.

By default I’ve set it to listen to all channels, but a single channel can be set at the top of the function if required, along with the range of notes to recognise.

#define MIDI_CHANNEL MIDI_CHANNEL_OMNI  // 1 to 16 or MIDI_CHANNEL_OMNI
#define MIDI_NOTE_START 48 // C3
#define MIDI_NOTE_END MIDI_NOTE_START+39

I experimented with some simple note counting and that would work if the MIDI reception was reliable, but there is a fundamental problem with this code on an 8-bit, single-core, Arduino. The WS2812 LEDs require very precise timing and the Adafruit library has some very hand-crafted assembler running with all interrupts disabled, to achieve it. The longer the string of LEDs, the more time is spent with all interrupts disabled, and so no storing up of, for example, data received over the serial port (MIDI).

This means that I need to ensure as much MIDI handling is done as possible outside of the LED updating, and try to ensure that the actual writing to the LED strip is done as sparingly as possible.

The techniques I’m using to do this include:

  • Only allowing writes to the LED strip once every 16 or more so passes through the Arduino’s loop() function, but calling MIDI handling every time (eventually I went for once every 256 scans).
  • Ensure that data is only written out to the LEDs if something has actually changed. This means that the Arduino isn’t spending time updating the LED string with the same data, stopping it receiving the next set of MIDI messages.
  • Run the MIDI library with Use1ByteParsing = false. This means that each call to MIDI.read() will only return either if there is no data or if the MIDI library has a complete message. Without this, a single NoteOn message requires three calls to MIDI.read() before the message is complete.
  • Ensure MIDI THRU is turned off. For serial MIDI, by default, the library provides software-driven MIDI THRU handling which means processor (and serial port) time is spent sending out all MIDI data received. This can be turned off on initialisation using MIDI.turnThruOff().
  • Choose an IO pin that wasn’t part of PORTD to ensure no inadvertent clashes with the UART (which is PORTD 0,1). So that means using something in the range D8-D13 (which map onto PORTB for the ATmega328). This probably makes no difference, tbh, but also doesn’t hurt either.
  • Add a global inactivity timer to turn all LEDs off after any period with no MIDI activity to catch any stuck notes.

I added a timing GPIO pin to attempt to work out how much time was spent updating the LEDs. It takes just under 2mS to update the strip of 56 (7*8 – there are 7 pixels in each ring, and 8 rings, even though I’m only using 5 per ring myself). Interrupts are disabled for most of that time (from what I can see of the code in the Adafruit library’s show routine). Note, this is quite hand-wavy and the exact timings will depend on the data sent. I believe it is something like 1.2-1.3 uS per bit, so for a single 24-bit pixel (three colour values) that is ~30-35uS per pixel. For a string of 56 pixels that is around 1.7mS in total just for the data. There are some reset and rest times too, so that is where my “almost 2mS” comes from.

MIDI runs at 31250 baud, which I believe means receiving one bit over the serial port every 1/31250 or every 32 uS or so. A complete single byte in MIDI therefore takes around 320uS (there are 8 data bits, one start and one stop bit). So a typical three-byte message is just under 1mS. I don’t know for sure, but it seems like disabling all interrupts long enough to have received two complete three-byte MIDI messages doesn’t seem like a good thing to be doing…

I don’t really know much about the hardware buffer of the UART on the ATMega328 but from conversations on Mastodon (thanks Rue) and having a dig into the USART section of the datasheet, there seems to be a single character buffer, so a 2mS pause would definitely be enough time for 4 or 5 characters to be completely dropped.

This is about as far as I’ve gone using the Adafruit_NeoPixel library as is, with a single string of 40 pixels and MIDI. I have a few thoughts on where to go next, so I’ll explore those in a future post.

Find it on GitHub here.

Closing Thoughts

This works ok for relatively simple cases and is passable for more complex ones, as long as I’m after effect not accuracy 🙂

Some other things to try include:

  • Splitting the string up and using different IO pins on the Arduino to drive the separate elements. A single 7-pixel ring probably takes around 300uS to update – which is comparable with the time taken to receive a single MIDI byte.
  • Use a different library (e.g. FastLED) or even hard-code the updates myself (there is an excellent discussion here on how to do that).
  • Use a more modern microcontroller. The Raspberry Pi Pico’s PIO is perfect for things like driving WS2812 LEDs for example. Alternatively a dual-core Pico or ESP32 would allow me to split out the LED updating from the MIDI reception.
  • Put a microcontroller in each display unit and string them together with MIDI IN/THRU rather than as a single LED string.

That latter option is quite tempting anyway – a Nano (or even a Micro) equivalent is pretty cheap these days. I could possibly even using something like an ATtiny. This would be an excellent approach if I built a microcontroller PCB for the displays and used those mounting posts I added to the physical design. I could keep using cheap pixel rings or really go for it and mount LEDS on the PCB.

But to be honest, for what I’m doing, I could even get away with a non-addressable LED if I’m adding a microcontroller to each unit…

Kevin

Forbidden Planet “Krell” Display

If you’re not familiar with The Forbidden Planet, then it is an iconic 1956 Sci-Fi movie with an absolutely ground-breaking soundtrack of “Electronic Tonalities” by Bebe and Louis Barron.

In one scene, when the humans visit an alien (the “Krell”) science lab there is a large set of display dials around the room that logarithmically show the power being generated by the Krell machine and I’ve been thinking for a while I’d like to try to reproduce them in a way that I could then use for something musical.

This post details the 3D and electronic design for my version of the Krell’s power indicators. The musical bit will hopefully follow at some point.

https://makertube.net/w/wmXGgm9GUeztDXn1K3nhmG

Warning! I strongly recommend using old or second hand equipment for your experiments.  I am not responsible for any damage to expensive instruments!

If you are new to Arduino or 3D printing, see the Getting Started pages.

Parts list

  • 3D printed Krell display unit
  • Arduino Nano or Uno
  • Several 7-way “neopixel”-like WS2812 5050 rings of LEDs (one per display face)
  • Breadboard and jumper wires

Design and 3D Printed Case

I’ve opted to build the display in units of two or four. The original Krell setup has gauges one above the other as can be seen in this capture from the film.

I’ve designed the display in four parts as shown below (these are early versions, but you get the idea).

The required “neopixel”-like rings are also shown. I actually only need 5 LEDs per display, but I need them to map onto the 5 cut-out segments on the display. This means that the bottom and centre LEDs are not used, but the other 5 map on quite nicely to the other of the six segments in the display.

OpenSCAD Code

I’ve used OpenSCAD and the code for all parts is in a single file. This means that any definitions relating to dimensions and scale can be used by all parts. Which part gets rendered and shown is selected at the top of the code.

show_frame = 1;
show_insert = 0;
show_support = 1;
show_quadframe = 0;
show_quadsupport = 0;

The inserts are the (white) display faces, and two of these are required per twin display. They also need a frame and optionally a support (if using the LED rings).

There is also a “quad” version of the frame and support which allows for a four-way display, which naturally will then require four inserts printing.

I’ve just used standard white PLA for the inserts and that seems to diffuse the LEDs nicely once lit. The frame and supports I’ve just used black and blue PLA respectively because that was what I had to hand at the time.

Here are the key parts in OpenSCAD for the dual-display.

And these are the parts for the quad display:

The actual insert for each display panel is a pretty complex object and takes a while to render on the display when moving and zooming. And even longer to render as an STL. There is probably a better way to design this, but it works ok for me.

In terms of the OpenSCAD code, there are the following modules:

  • supports() – used to build the supporting partitioning for a single face of the display. This is called twice for a twin display and four times for a quad display.
  • krell() – builds the display face itself for a single display, but is also used for the cutout for the face in the main frame. Again used twice in the twin display and four times for the quad.
  • krell_mark() – used to create each of the four triangles that are part of each single display face.
  • pcbfixing() – used to create a pillar with a M2 sized hole that could be used to mount a PCB.
  • sector() and arc() – used to build the six individual segments. It is taken from https://openhome.cc/eGossip/OpenSCAD/SectorArc.html

It’s perhaps not the most efficient, and certainly is the cause of the longer rendering times for the insert, but I’ve made quite heavy use of difference() and union() to create the various cut-outs and masked-off areas.

The face panel was particularly challenging, using combinations of spheres and cylinders. I particularly wanted the spheres to be hollow so they didn’t show up darker when illuminated from behind. Packing the spheres in also involved calculating the vertical distance using the formula: vertical position = radius * SQRT (3) and then offsetting the start of the next row by a single radius.

Design notes:

  • I planned to allow for a PCB to be made and mounted in the case. This would make for a nice, self-contained unit, hence the PCB fixing points. But in the end opted for the “neopixel” style rings and jumper wires.
  • The supporting partitions originally included mounting points for the M2 holes in the rings, but they proved either too small and brittle or too large. I don’t know if that was an issue that could be solved by tweaking the resolution of the print, but in the end the rings wedge in fairly well without them.
  • There is little provision for wiring at the moment or for mounting a microcontroller. The units themselves are cases and LEDs rings only.
  • I’ve not found any dimensions online for the displays, but from photos of props that have been sold online, I decided on the ratio 65:100 for the displays, so used that in mm for my twin display. They “feel about right” to me.

Find the source and STL files on GitHub here.

Arduino Electronic Control

I’m using an Arduino Nano but pretty much any 5V microcontroller would do. If using a 3V3 microcontroller, then level shifting would probably be required as these LED rings really do nee 5V for power and signals.

The LED rings are collections of WS2812 or compatible 5050 (i.e. 5mm square) multi-colour addressable LEDs. Adafruit call these “NeoPixels” and have a very comprehensive guide for using them here: https://learn.adafruit.com/adafruit-neopixel-uberguide

The rings that I have, have two sets of three solder pads on the rear. Both sets have VCC and GND, but one is a signal IN and one is a signal OUT. This allows them to be chained together as shown above. Two rings are required for a single dual-face unit. Some rings might have pads, holes or even connectors.

The Adafruit Uberguide talks in detail about powering these rings, especially when used in long strings for large displays. As a general rule, the recommendation is to allow for 20mA per “pixel” up to a maximum of 60mA for full brightness with all LEDS on per “pixel”.

As the Arduino can support up to 800mA via its 5V pin and I’m planning on using 8 display faces, each with 5 LEDs per face, that gives an estimate of:

  • 8 x 5 x 20mA = 800 mA as a typical draw.
  • 8 x 5 x 60mA = 2.4A peak for full brightness, all LEDs.

I think I can just about get away with driving my 8 faces from a Nano as long as I’m not expecting to turn everything on at full brightness – more on that in a moment when I get to the example code.

If I wanted to support something nearer the peak current I would need a separate power supply providing 5V and around 2A to the LEDs. That could probably be wired to provide a 5V link directly into the Arduino’s 5V pin too. However, this is not recommended though due to the potential for mistakes, noisy signals, and interrupts in supply, as this bypasses the regulator and any protection circuits on the Arduino.

But if I’m careful, it will be fine as an option for me if I need it.

The Code

Driving WS2812 LEDs is pretty straight forward thanks to the Adafruit_NeoPixel library for Arduino which is easily installed via the Library Manager.

One complication I have is that I need to translate between the order and number of LEDs on the rings and the 5 LEDs per ring I want to be using.

The ordering of my LEDs is as follows:

But that might be different for different rings of course. The following code is a simple test to illuminate each LED in turn allowing me to find the order, and shows all the key principles of how to turn the pixels on or off:

#include <Adafruit_NeoPixel.h>

#define LED_PIN 6
#define LED_COUNT 14

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

void clearStrip () {
for(int i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(0, 0, 0));
}
}

void setup() {
strip.begin();
strip.show();
strip.setBrightness(50);
}

void loop() {
for(int i=0; i<strip.numPixels(); i++) {
clearStrip();
strip.setPixelColor(i, strip.Color(80, 35, 0));
strip.show();
delay(500);
}
}

The definitions used in the Adafruit_NeoPixel initialisation (NEO_GRB+NEO_KHZ800) work for my rings, but there are several options. Try some of the library examples and consult the Uberguide for details if the rings aren’t working.

In order to map this order over to just the LEDs I need to use for my Krell display, I need two “lists” of LEDs – the real one representing the physical order the 7 LEDs per ring appear on the rings themselves, especially when linked together; and a virtual one representing the desired order of the 5 LEDs per ring I’m interested in using.

I do that via the following definitions and code:

#define LED_PIN   6
#define LED_BLOCK 5
#define LED_RINGS 8
#define LED_COUNT (LED_BLOCK*LED_RINGS)
#define STRIP_BLOCK 7
#define STRIP_COUNT (LED_RINGS*STRIP_BLOCK)

int ledpattern[LED_BLOCK] = {1,0,5,4,3};
int leds[LED_COUNT];

void setup() {
for (int i=0; i<LED_RINGS; i++) {
for (int j=0; j<LED_BLOCK; j++) {
leds[LED_BLOCK*i + j] = ledpattern[j] + STRIP_BLOCK*i;
}
}
...
}

The ledpattern[] array lists which physical LED corresponds to my five virtual LEDs. The leds[] array will expand this list to the number of rings, giving offsets for all physical LEDs used to map onto all my virtual LEDs.

In order to allow this to be changed to match the number of rings used, simply by changing the #defines at the top of the code, leds[] is initialised in code as part of setup(). For two rings in a twin display, this maps virtual LEDS 0 to 9 onto real LEDS 0 to 13, with four of them being unused. For four rings in a quad display, this will map 0 to 19 onto 0 to 27, and so on.

In order to use this with the Adafruit functions, I just take my virtual LED number and use that as an index into leds[] to get the real LED number, for example:

  for(int i=0; i<LED_COUNT; i++) {
clearStrip();
strip.setPixelColor(leds[i], strip.Color(80, 35, 0));
strip.show();
delay(200);
}

I have some example code to test all LEDs. The simple version just illuminates each LED in turn, using the above code. An alternative version will read a potentiometer and use that to determine how many LEDs to illuminate.

With the correct wiring sequence and pattern of LEDs it is possible to mimic the order of the illumination of the panels in the original film.

A note on colour, brightness and power.

As previously discussed, I’m working on the basis that not all LEDs will be on at full brightness and so can get away with powering my display simply from an Arduino. For this to be true, I’m working with the following constraints:

  • No more than 8 rings are used. In my case that is two dual displays and one quad display.
  • Not all LEDs are used for the colours. I’m using: strip.Color(80, 35, 0) which leaves on LED of each of the three in each pixel off and gives a nice, nostalgic, colouring which to my mind matches that used in the film quite well.
  • Brightness is set relatively low, using: strip.setBrightness(50), which is less than a quarter brightness (the maximum is 255).

Find the test code on GitHub here.

Closing Thoughts

I’m really pleased with how this has turned out. It took a little trial and error to get the parts to fit and work, but the colouring through the white PLA is quite pleasing to me. The partitions also work well to allow individual control of the segments without the light bleeding through.

The simple code with a potentiometer control shows the potential. I have a few ideas for how to use this with MIDI, but those can come in a future post.

Kevin

First #PixelBlaze Feature Request:

Please place a prominent notice on the product page warning potential purchasers of the extremely addictive nature of this product.

I started with one #neopixel project and I now have ten more. Dangerously addictive. What's the bulk purchase discount? I may need to know.

I just made a digital fireplace in less than 15 minutes! 🤯

These things are LED crack!

And I made my first change to a mapper!

Continued thread

🤦‍♂️🤦‍♂️🤦‍♂️

Guess who's got another four strings of #neopixel fairy lights on the way?

And another #PixelBlaze Standard and Pico?

🤦‍♂️🤦‍♂️🤦‍♂️

150 LEDs per 1 meter high tree. And earlier I thought of a tree topper I can make with available parts. That adds another 33!

I suspect I will have to limit the overall brightness level to stay within 3 amps.
😎

I've never done anything like this so I was proud it worked. It's a #RaspberryPi Zero 2 W, I soldered on the headers myself and then soldered the cables to the #NeoPixel Ring. I wrote a small script in #Python to handle changing colors and to turn off the ring. I'm going to #3DPrint a small stand to put under my 1.5gal fish tank and will place the ring within the stand. I'll be sure to update this with a video of that but here's what I have so far!

The cauldron prop for our halloween concert seemed like it could use a fake flame effect ...

this is a meter of #neoPixel strip running a simple program that uses a range of reds, oranges & yellows randomly .. it uses #circuitPython

here I'm demoing it in my un-tidy basement. Will try it in the actual cauldron prompt next (last!) rehearsal