LED Oscilloscope Mk. II

Revamping a classic

Similar projects worth following
This is an update of a project I built in my youth - a real-time oscilloscope using an LED matrix display. Don't tell anyone, but it's really just a toy.

Around 1985 I built a 10x10 LED oscilloscope based on one of the Forrest M. Mims III designs. It used a CD4017 Johnson counter for the horizontal sweep and an LM3914 bar-graph driver for the vertical driver. The display was coarse, and I never measured the bandwidth, but it was OK for the audio tinkering I was into at the time - and was all I could afford.

Over the years, I've considered re-doing this design with faster components. LEDs can be driven pretty fast (laser diodes even faster if it comes to that), so the display shouldn't be the limiting factor. I've been playing with 74AC logic lately, and that coupled with a flash or pipelined ADC, I think could yield speeds of 80 MSps - theoretically enough to visualize up to 40 MHz signals. Realistically, you'd want more points per cycle - you'd get 10 samples/cycle at 8 MHz.

I haven't given much thought to the analog sections (front end and trigger) or the timebase yet, but have started playing with a design for the horizontal and vertical drivers. The basic initial design is detailed in the first build log.

I also haven't chosen LEDs yet. My initial thought was to use ultraviolet LEDs and a phosphor screen for analog-scope-like persistence. I think instead, I'll make the screen connectorized so that I can try different LED matrices easily. I also want to test the LEDs for switching speed (with an avalanche photodiode detector) before committing to them. The whole project depends on the LEDs switching fast enough.

As for the display resolution, I haven't decided yet. I first thought about 32x32 (1024 LEDs), but then backed off to 16x32. I think I'm going to capture some waveforms on a modern digital scope and write a quick program to render them on a simulated LED matrix to see how it works at different resolutions.

I realize that a digital storage oscilloscope is probably not much more complex to design than the mess I'm creating here, but I really want to stay true to the original real-time scope concept. In case it's not obvious, this is not intended to be a practical oscilloscope design; for that, you'll have to look elsewhere.


First sketch of horizontal and vertical LED matrix drivers

Adobe Portable Document Format - 14.01 kB - 01/16/2017 at 20:47


  • Better bezels through g-code

    Ted Yapo02/22/2017 at 04:46 0 comments

    I couldn't get Slic3r to generate really nice segmented bezels at this scale, so I wrote a python program to generate g-code commands to send to a 3D printer directly. As a result, I can make cells with exact 1-extrusion-thick walls and minimal blobbing. The code is checked into the GitHub repo, but you might need to tweak it to match your printer/filament settings - oh, and be prepared to yank the plug if you got anything wrong :-) Here's the result:

    This display uses the new 3D printed bezel, the Rosolux 116 tough white diffuser, Roscolux 26 red filter, then a black mask laser printed on overhead transparency stock. At some point I will gather enough courage to run the Roscolux sheets directly through the laser printer and see what happens - they are intended for theatrical lighting, so are heat-resistant, but I'd hate to screw up a laser printer. No guts no glory, I guess (but also no goop in my printer). I suspect printing directly on the diffuser or red filter (or both) might fix some of the bleeding around the pixels.

    The python code is pretty simple; it just generates a grid of 1-extrusion wide cells. For the printer I used, this means 0.42 mm wide walls. The code uses alternating zigzag patterns in the horizontal and vertical. Even though there is theoretically twice as much material deposited at each corner, this doesn't produce too much of a blob. You might be able to improve this by slowing the extrusion right at the corners, but I'm not sure if that will introduce other issues.

    The output of this program can be sent directly to the printer, which is a little scary. I have a kill switch on the power supply from previous experiments like this. I didn't need it this time, but maybe I just got lucky. One way to be safer with this kind of thing is to use a g-code previewer. There are a few on the web - I've started to like this one, which rendered this preview of the 16x32 bezel:

    Here's the printed result for the 16x32. I still haven't built anything to drive the display yet :-)


    I'm going to try putting a sheet of the diffusing material on the 3D printer bed to see if I can get the bezel printed directly on to it. That might work out really well...

  • I'm going to feel this in the morning

    Ted Yapo02/20/2017 at 03:38 12 comments

    The 16x32 display boards arrived yesterday from OSH Park. I spent some quality time at the bench this evening.

    The LEDs all work, although they got mounted with the wrong polarity - I got the first one wrong, and was very consistent after that. It will take a few inverters to make this work with the original circuit idea, but that's easier than re-working the board :-)

    The really scary thought is that I have 2 more PCBs like this one.

  • Filter Madness

    Ted Yapo02/04/2017 at 20:42 5 comments

    I've been playing with filtering the display for contrast and filling the space between pixels.Here's how the display looks without any covering, with a 0.15" thick bezel, and with the bezel plus a 116 Tough White Diffusion and 26 Light Red filter.

    Out of all the many combinations I've tried, I like this last one the best. You lose some light, but the LEDs are really beginning to look like pixels. In the photo, the filters aren't held tightly against the bezel, either, which improves the display a bit. I think the final assembly will need a thin acrylic sheet over the top for protection and to hold the filters flat against the bezel.

    I love Roscolux filters - they're made for theatrical and cinematic lighting, but are very useful for general optical hacking. They're relatively inexpensive, come in hundreds of shades, and you can get a free swatchbook full of samples if you go to a theatrical supply store (you might end up having to pay for one online). Once you determine the ones you want, you can order them in big rolls. I found a few dozen useful ones for diffusing and filtering the red LED prototype display in the pack:

    Also shown are the 3D printed bezels with a square hole for each LED.

    There are two issues I'm still working on. First, there is a significant amount of light lost. I think I can regain some by adding a white silkscreen covering the PCB, and using a white bezel (currently printed in black). I will try printing the bezel in white, but I wonder if it will allow leakage from neighboring pixels. If all else fails, I'll try painting the black bezel white - that should block light from adjacent LEDs while reflecting more of the center pixel.

    The second issue are those annoying dark corners in each pixel cell. Printing this bezel is just at the edge of what's possible with my printing setup - each wall in the grid is only one extrusion wide. Unfortunately, the slicer isn't doing a great job of path planning, and the print head makes a little jog in the corner of each cell. You can see it here in the gray lines:

    Those gray lines are moves (without extruding material), but the extrusion doesn't stop on a dime, and a little string of filament ends up in those corners - enough to cause those distracting dark corners seen above. You might be able to clear them out with a hobby knife, but I don't think that's practical for larger displays.

    I'll play a little more with the printing toolchain, then I might try writing g-code for this bezel directly. I wrote a package a few years ago for 3D printing from Javascript, so I don't think it would be that difficult. For an object like this, the imprecision of triangular modeling and subsequent slicing starts to outweigh the convenience, and custom-written g-code to print the grid might work a lot better. In that case, you have complete control of the path of the print head, and can keep it from making those silly corners.

    Another possibility would be to design the grid with semi-octagon cells, which intentionally have four dark corners. It might be that those can be printed consistently. But, I really would like edge-to-edge square pixels...

  • 16x32 Display Design

    Ted Yapo02/03/2017 at 18:28 11 comments

    UPDATE 20170207: I forgot resistors! Fixed in the addendum below.

    I painstakingly drew the schematic for 512 LEDs in this display, then endured the drudgery of laying out the board. The whole process took about 45 seconds. Yes, I wrote a few Eagle User Language Programs (ULPs) (elapsed time after the scripts were written and debugged). The previous time I wrote one was last century to lay out a circular LED clock face. I figured it was about time I regained those skills. The code is here on GitHub. You can edit the scripts to produce any size array. The "led_matrix_schematic.ulp" code generates the schematic. Here's the 16x32:

    The default board (auto-generated by Eagle) looks like this:

    A second script ("led_matrix_layout.ulp") re-arranges all the components and adds traces, vias, and silkscreen programatically:

    The silkscreen matrix is there to act as a reflector. I have been experimenting with 3D printed segmented bezels and diffusers which make the 0.1"-spaced tiny-die LEDs look like a closely-packed array of pixels. I'm still experimenting with a number of different diffusers from a Roscolux theatrical lighting gel swatchbook - I'll post images in an upcoming log. The short story is that you can make these matrix displays look like a nice pixel array, but at the cost of some efficiency. I think that using the silkscreen to reflect light off the board will improve the brightness - and it's free, so why not. There's a flag at the top of the script to turn off all the reflector silkscreen segments if you don't care for them.

    The scripts rely on an Eagle library ("led_matrix.lbr" - also in the GitHub repo) I created that contains only three parts: the 0603 LED, a 1-pin 0.025" header, and a #4-40 or (M3) mounting hole. You need to add this library to your project before running either script. The mounting holes aren't automatically placed, so you'll have to do those manually, as well as sizing the board and adding any desired text.

    If you run this script, you may be concerned to find "unrouted" airwires on the board (shown below).

    The problem is that I can't figure out how to programatically "route" nets to Eagle's satisfaction. Instead, I draw traces on the appropriate layers. In some cases Eagle recognizes the electrical connection, and in other's it doesn't. Part of the problem is that the LED package is metric, while the board is in inches. Add to that the irrationality of rotating the LEDs 45 degrees, and the imprecision of floating point representation, and it's not surprising that Eagle loses track of things. If this concerns you, you can verify for yourself that all the tracks are in order.

    If you make one of these boards, you will also want to adjust your design rules to "tent" the vias - cover them with soldermask. This should enable them to carry the silkscreen, too.

    Here's a rendering of the final test board. I am going to wait a day before sending this out just in case I think of anything. I usually do.


    I forgot to include resistors on the board - I'm glad I waited to send this one out! I just updated the GitHub repo with code that adds 0805 resistors in each row and column. At low speeds, you really only need one or the other, but I am planning to use both on higher-speed versions to damp ringing on the row and column lines. It's not really possible to maintain a controlled impedance on the lines, and I'm concerned that any ringing may end up visible as ghosting on the LEDs. By splitting the required dropping resistance across the row and column lines, I may be able to hide these effects.

    Now I'll send it. Sent!

    In the two weeks before the boards return, I can look at fast sweep generation with 74AC164's and some simple ADC tests with an AD9200 ADC (because I happen to have about a hundred of them lying around).

  • 10x10 0603 Display

    Ted Yapo01/31/2017 at 03:13 5 comments

      The PCBs arrived today from OSH Park, and I had the opportunity to populate one after dinner.

      It works, and it is smaller, but there were two things I don't like about this display. First is the extra space between LEDs; I think it's distracting. I am considering:

      1. Decreasing the space between LEDs (which may make it more difficult to populate the board
      2. 3D printing some kind of bezel to be used with a sheet of ground glass (or equivalent) to fake closely-packed pixels

      I also found the contrast lacking, so I added a sheet of standard #2423 colored acrylic, which I've used on other projects for LED contrast filters. This helps a lot.

      I've seen some really tiny LED matrix displays on - how close can people get the LEDs reliably? Mine are on 100 mil centers.

      I applied solder paste with a 1 ml syringe and 25 ga blunt needle, then placed the LEDs with tweezers. The whole assembly took less than an hour, including several magnified checks before skillet reflowing the board to make sure none were on backwards. I applied a little too much paste, which caused some solder balls to form, so I spent ten minutes prying them out of the flux with a dental pick.

      As with the previous display, it looks better in motion:

      I have two boards left, and some green and UV LEDs to try. I picked up cans of fluorescent green and glow-in-the-dark spray paint to experiment with making a phosphor screen for the UV LEDs. I'd really like to see if I can simulate the feel of an analog scope screen.

      I also figured that I probably couldn't do a 32x32 array in one sitting. 100 was easy enough, and I might be able to do 200 at once with minimal fatigue, but then I'd have to take a break. I'll probably paste-and-populate 200 or so each day for a week or so, then reflow the board. That might be difficult to do with a stencil, but with a syringe, I can take a while to get all the parts on there.

  • Remaking the original

    Ted Yapo01/29/2017 at 19:54 12 comments

    I saw an email notification that my 10x10 0603 LED PCBs are supposed to arrive Monday. This inspired me to make a 10x10 with 5mm LEDs so I didn't have to wait. Some parts were just as much of a pain as when I first did it 30+ years ago.

    One of the issues was the little lip at the bottom of the LEDs - this keeps them from packing closely together. I know you can get LEDs without the lip, but I used what I had at around midnight last night. Just as I had done before, I ended up filing this lip off each LED, which took most of the time. The soldering fun more than made up for this inconvenience.

    The matrix is connected underneath, with the connectors brought out to 0.1" headers, like on the PCBs:

    After assembling and testing the board, I've determined that I have about a 1% error rate in inserting LEDs correctly. One of them got soldered in backwards, and I had to unsolder the neighbors to replace it. Not too bad, I guess considering it was a late-night adventure.

    The test driver uses an LM3914 to drive the vertical and a 74HC4017 to drive the horizontal sweep. Using a dual-channel DDS to drive both makes testing a breeze. With the horizontal set to 10x the vertical frequency, the display is rock-stable, since the DDS outputs have a constant phase relationship. Here are sine, triangle, square, and pulse waveforms displayed:

    I found that the LM3914 seemed to start skipping LEDs with a sine wave of about 50 kHz or above. I seem to remember them being faster before - although this one was an ebay purchase, and could be a fake, I guess. For audio frequencies, this seems like it would be fine. I'd like to go 1000 times faster :-)

    The display is about how I remember it - due to the low resolution, a slowly-scrolling display seems easier to visualize than a steadily-triggered one. By setting slightly different frequencies at the DDS outputs, crawling displays can be made, too. Here are the same waveforms in motion:

    Comparing this to the build from my teens, I have to admit, some of the magic is gone. I still remember the first waveform I saw on the thing - it was 60Hz power-line hum. I left the thing on overnight like a night-light with that slowly-crawling sine on it.

    As with most things, the cure here may simply be MORE LEDs...

  • First test: 10x10 display

    Ted Yapo01/17/2017 at 17:31 0 comments

    I figured I'd start small - I haven't used 0603 LEDs before, so I ordered some cheap ones off ebay and designed this board:

    The LEDs are on a 100 mil grid, which makes the connectors easier. I probably should have used smaller vias, but at least I tented them, which should help avoid shorts. In the next iteration, I'll shrink the vias a little.

    The display is 10x10, which will allow me to re-create the original circuit as a first step. I have some 74HC4017's which are a definite improvement over the original CD4017 and even some LM3914's kicking around. I won't bother with any of the analog front end, and will probably just drive the clock and analog inputs from a 2-channel bench DDS generator to see some waveforms on the LEDs.

    I'm also realizing that larger displays might not fit in the light version of Eagle. At 0.1" pitch, a 32x32 display is 81.28 mm wide, which is more than the 80 mm Eagle light version limit. I could get away with a 24x32 display in 80x100mm, though. That's 768 LEDs - a challenge to populate by hand. Fun.

  • Basic LED scanning design

    Ted Yapo01/16/2017 at 20:47 5 comments

    Here's a first sketch for the digital parts of the design (a pdf version can be downloaded here).

    The horizontal sweep is done with a series of 74AC164 8-bit shift registers, so the horizontal resolution can be expanded in multiples of 8 columns (you can also use less than 8 columns on the last register). This method is faster and easier than a decoded counter, but requires that a single "1" bit is inserted into the shift register to start each sweep. Three 74AC74 d-flops form the inserter, which starts a single "1" bit rippling through the columns when the trigger input goes high. No retriggering is allowed until the "1" exits the shift register.

    The vertical driver starts with a flash or pipelined 8-bit ADC. I haven't chosen the exact ADC yet, but the AD9057, and AD9293, and ADS831 are on the list to consider. The lowest few bits out of the ADC are discarded, and the most significant four or five bits (depending on the chosen vertical resolution, TBD) enter a delay line made from 74AC174 d-flops. This delay line keeps the trigger point on the display, as opposed to being off the left edge - in classic Tek scopes, an analog delay line served the same purpose. In this case, it centers the trigger point, but doesn't let you adjust the horizontal position - which is fine with me. Depending on the display size and the amount of pipelining inside the ADC, a different number of delay stages will be required.

    The output of the delay line is decoded into a 1-of-N active-low output by a number of 74AC138 decoders (added as required for the number of display rows desired). The 74AC138 allows up to 32 outputs to be decoded (4 ICs) without additional logic. These decoders feature active low outputs, which make the row lines the LED cathodes. A number of 74AC574 d-flops register the outputs of the decoders and drive the LED matrix rows through a set of current-limiting resistors.

    The 74AC logic gates will drive 24mA, which should be enough to light high-efficiency LEDs to a decent brightness. Even though the LED matrix will be large, only a single LED in each row and each column is lit in any "frame", so I'm guessing the brightness will be OK.

    I'm thinking of prototyping a 1D version that just shows a digital signal on a line of LEDs to test the horizontal sweep circuit.

    I'm still thinking about the timebase. DDS is easy, but getting one that goes up to 80 MHz may be expensive. A 100 MHz oscillator with a chain of divide-by-2 and divide-by-5 counters would make a decent 1-2-5 timebase, although with a lot of components.

    I'm also still thinking about the analog front end and trigger circuit. I might start with a 50-ohm front end for simplicity, then add a high-impedance buffer of some sort.

View all 8 project logs

Enjoy this project?



zakqwy wrote 02/20/2017 at 18:24 point

Just noticed your bit in the description about a phosphor display and UV LEDs. Last year I bought a sheet of PhosphorTech material -- it's the yellow stuff that is used in conjunction with blue LEDs to make them white (in this case, ~5500 K). I haven't done much with it beyond putz around, so I'd be happy to donate a 2"x4" (or whatever size you need, within reason) bit to the project. You should be able to use one of your spare 16x32 boards, just swap the red LEDs for blue. Could make a pretty neat effect. Yay more soldering!

  Are you sure? yes | no

Ted Yapo wrote 02/20/2017 at 18:52 point

Thanks!  I might take you up on that.

I have soldered up a 10x10 array of 0603 UV LEDs as a test, and have been playing with various screens, but haven't written it up yet.  I've been experimenting with screens laser-printed on transparency material, then spray-painted with glow-in-the-dark spray paint.  The results aren't great so far because the "normal" paint has very few phosphor particles in a clear carrier - the result looks very grainy.  I have to pick up a can of the "premium" paint, which costs twice as much, but I suspect uses a higher concentration of active material.

Is the PhosphorTech material fluorescent or phosphorescent?  I've tried some purely fluorescent material, and they do a good job of down-converting the UV to visible, but turn off as soon as the LEDs do, with no persistence. Ideally, I could find some medium-persistence phosphor like used on the face of a CRT oscilloscope.

I have some activated ZnS powder, too, from spinthariscope experiments, but it's opaque to visible light, so you'd need a very thin layer of it to make a screen.  This may be the problem the spray paint manufacturers are facing.

  Are you sure? yes | no

zakqwy wrote 02/20/2017 at 19:01 point

It's phosphorescent, but I'm not sure what kind of persistence it offers -- probably worthy of some experimentation. This is the datasheet of the stuff I have: Online Datasheet.pdf

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates