Replacing the LM3914/LM3915/LM3916 with a PIC
Most designs you see for audio level LED bargraph displays use the LM3914/LM3915/LM3916 series chips that are no longer made. However, the chips are simple, so we can replace them with a PIC and build a nice LED bargraph driver on a single chip.
So why do you need this thing?
You need this if you want to display an audio level and make sure it doesn’t go above some well-defined threshold, usually the level at which clipping occurs.
My personal situation was that I’ve been working on project that has a variable overdrive circuit, followed by a level control. This is then followed by some other circuits, like a reverb, and I’d like to avoid the drive circuit causing clipping in the following stages, which is possible if you turn both the Drive and the Level up at once. It occurred to me that I needed a simple audio meter circuit, one of those little LED bargraphs that show you how loud things are. Putting such a thing between the overdrive stage and the rest would enable me to see easily when the level was good for the next stage, and help me balance clean and overdriven sounds. Furthermore, more blinky lights is better, right?!
Most of the designs you see for such things use the LM3914/LM3915/LM3916 series chips by National Semiconductor. NatSemi were bought out by Texas Instruments in 2011 and the LM391x chips are no longer produced. There’s still few around, but it didn’t seem like a bright idea for a new circuit to use a discontinued chip. The chip itself is very simple though, so I thought it’d make a quick PIC project. This page describes that project.
How do the LM3914/LM3915/LM3916 chips work?
So…what do the original chips do? They’re basically all the same, consisting of a resistor string creating threshold voltages which are fed to comparators that compare the given threshold to the input. The comparator outputs drive individual LEDs. The chips contain ten comparators and thus drive ten LEDs. The only difference between them is the values used in the resistor string: LM3914 is linear, LM3915 has 3dB log steps, and LM3916 is set up with the typical steps for a VU meter. There’s a good YouTube video that compares the responses of the three chips. Which do you like best?
There’s also current limiting on the chip, which means you can connect the LEDs directly without needing a series resistor. We’re not going to be able to do that unfortunately, but a few resistors isn’t a big deal.
PIC-based LED bargraph driver: hardware design/schematic
My first step for this project was to sketch out the schematic above.
This was pretty straightforward. I needed 10 output pins and 1 input pin, so that’s 11 IOs. Adding a couple of power pins makes 13 pins, so a 14-pin chip like the 16F1503 was going to be the smallest device that would do the job. Since RA3 is input-only, it would have to be the “extra” pin, and I sketched a switch connected to it for some option (the original Nat Semi chips had a “bar mode” and “dot mode” that you could select between). Audio is AC-coupled via a small capacitor to an ADC input held at a midpoint voltage by a simple voltage divider. This is the same scheme I used on the DigiDelay, so I know it works. The LEDs I had around have Vf of 2.1V and 2.2V, which gives a resistor value around 1.45K for 2mA current. You can check this on this useful LED series resistor calculator if you like. In the end, I used 1K2 for all the LED resistors, but it obviously depends on the LEDs you choose. Don’t go for anything high-current, or the poor PIC will get cooked.
Having got some basic hardware worked out, it was time to look at the firmware.
PIC-based LED bargraph driver: firmware design
Since I initially assumed what I needed was a VU meter, I did a bit of research by looking at the LM3916 datasheet. This gave me the threshold voltages its comparators use, which I was able to convert into 8-bit numbers. That helped. It also made me realise that the original chip is literally just the comparators and the threshold voltages . The chip on its own provides an instantaneous read-out, with no damping or smoothing or anything. I’d assumed that some filtering of the input would be required, but it can definitely be regarded as “optional”. This gave me a “first draft” for the firmware. My plan was:
- Read the audio input using the ADC at a decent audio sample rate of 40KHz and 9-bit resolution
- Do a simple full wave rectification of the input signal (turning a 9-bit bipolar signal into an 8-bit unipolar one)
- Use the rectified waveform to drive the LEDs by comparing its level to the thresholds from the LM3914 datasheet.
The initial version of this was hacked together very rapidly. I got working code producing a pretty lightshow.
The LM3916 datasheet shows many external circuits to add rectification and smoothing to the input. This enables the chip to meet various standards for audio measurement ( a “genuine” VU meter, or whatever).
Consequently, I did a lot of experiments to see if adding filtering to the rectified waveform helped since that’s what genuine VU meters do, but I didn’t like the results. It makes the output very laggy, and it reduces the number of LEDs that light up.
It also made me realise that I needed a Peak Hold dot on the display so that I could more easily see the maximum input level (since that was my primary motivation in the first place!). I asked about VU meter algorithms on the Synth-DIY list as part of my research too. Ben Bradley suggested a Peak Hold algorithm in his reply that sounded good and simple to implement, so that’s what I started with. Brian Willoughby mentioned a problem in the original algorithm which causes it to sometimes miss a peak, so I tweaked it to remove this issue.. I also decided that the Pin 4 option switch should turn the Peak Hold feature on or off.
My final code looks like this:
- Audio Meter with optional Peak Hold 0-5V bargraph driver 16F1503 code AUDIOMETER.ASM
- Compiled version of the above for programming onto 16F1503 chip, AUDIOMETER.HEX
- Schematic for the Audio Meter with optional peak hold
This implements a full-wave rectifier on the chip, so you just feed audio to it as per the schematic above. The Peak Hold feature is enabled by tying pin 4 to ground. If this is not used, the pin can be left open.
Since there’s a plethora of standards for every different purpose, I didn’t feel the need to adhere to any of them. Instead, I looked at my needs (avoid clipping, produce a nice display). I consider that the LM3916 produces the best display so I started with the standard “VU” points of +3dB, +2dB, +1dB, 0dB, -1dB, -3dB, -5dB, -7dB, -10dB, and -20dB. However, my meter was really intended to measure with respect to full scale, so it makes more sense to consider these points as 0dB, -1dB, -2dB, -3dB, -4dB, -6dB, -8dB, -10dB, -13dB, and -23dB. In the end, I tweaked them a bit to give me 0dB, -1dB, -2dB, -3dB, -4dB, -6dB, -9dB, -13dB, -18dB, and -24dB.
Tweaking this for your application
Altering the thresholds where the LEDs come on is simple to do. The thresholds are listed explicitly in the code around line 150. You can calculate the required threshold value from a negative decibel value (the maximum is regarded as 0dB) with this equation:
Threshold = 255 * 10^(dB/20)
Alternatively, if you express your required thresholds as a number x from 0 to 1, you can simply multiply by 255 and round to the nearest integer:
Threshold = round(255 * x)
I hope this helps you adjust the code to do exactly what you need! Enjoy your pretty lights!
Feedback and comments
Any feedback or comments on the code, the project, or just relevant to the topic are appreciated! Get in touch from the contact page.
The AUDIOMETER project, code and schematics by by Tom Wiltshire for Electric Druid is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Here’s the legal stuff.