Another LED Driver: simple, scalable, controllable

One of the steps in improving my build (original posting, needs updates) was to improve the quality of light. Somewhere in the process I became intrigued by the discussions on stacking algorithms, and given that I rely on DigicamControl for managing the camera, one simple way to do so would be to give the arduino the ability to control the light (for more info on the workflow see this post). The forum has a few postings on the struggles of controlling LEDs, so thought this posting would be helpful to all.

To dim by switching or to dim by changing current… that’s is the question
The human eye basically does not see flickering when the light is switched above a certain frequency. That is the principle of CRTs rendering an image. However the eye-shutter is much slower than what is available in cameras, so it is possible that while we see the light dimming, a camera with a faster shutter would see a portion of the frame lid, and a portion dark, or lines, or dots.
Controlling the light by rapidly switching on-and-off is possible, but it requires that the switching and the camera shutter are coordinated, making the LEDs and the diming dependent on the camera shutter settings.
Another alternative for an LED produce less light, is to lower its operating current. Making current constant, just less current, results in making less light.

Microcontroller control options
Basically it boils downs to Digital-to-Analog block. It can be an integrated DAC (serial or parallel), or a DIY DAC with an R-2R ladder. Another alternative is to convert a PWM into an analog voltage, basically an R-C circuit/low pass filter of the pulses becomes a DC corresponding to its proportion high/low.

PWM is common, and available in Arduino or Raspberry Pi. Some Arduinos provide 12-bit PWM and even the old Uno and Mega have work arounds for 16 bit outputs. Additionally, there are simple ICs/boards with multiple 16bit PWM, such as this one from Adafruit.
PWM solves the scalability issue, specially when some builds are looking to control R-G-B-W-Ir, and even multiple Rs or Bs.

Integrated Solutions
As mentioned in the Sasquatch 70mm scanner there are integrated solutions such as the AL8805 or its evaluation board made by Sparkfun, the femtobuck.
Why would one want to reinvent the wheel? It is fun… and because some of these may not be available where the film is at?

Control with PWM drive with constant current, scalable
Based on the above preamble, I created a driver configuration with transistors, to make a constant current-mirror driver controlled by a PWM.

Some advantages:

  • Transistors are everywhere, chips are in shortage.
  • Scalable both in the number of LEDs that can be controlled, and the colors-channels.
  • Configurable to supplies of 12V, 24V or more. LEDs work in series but with typical drops around 3V, the number that can be in the same string is limited to the power supply voltage.
  • Modular design. The configuration is simple enough that more LEDs can be added in series, or in parallel (the mirror transistor). Multiple channels can use the same design topology.
  • In line with Kinograph philosophy: simple components, available worldwide.

Using some particular LEDs (almost 1W each), I made a proof of concept and was very pleased with the results. It is a linear circuit, so ripple/noise on the power supply translates into visible noise. Because of it, I added a linear regulator on the PCB, can be used or not.

I’m behind on what I would like to do to simplify the work if anyone wishes to use the configuration, so at this time there are schematics with 12V and 24V examples, and PCB (through-hole). I ordered some components to assemble the PCB, and once completed, I will make some additional postings on how it works, and how to change values to adjust to your build. All documentation will be on with progress postings on this trail.

Schematic Summary
Here is a quick explanation of the blocks, to make the schematic simple to understand. Open it in PDF here

The building blocks are:

  • Level shifting of the PWM - Q1 switches whatever PWM levels on J2 (light blue in the scope screenshot above), to the internal regulated voltage VR. Basically, if J2 receives 0-3.3V or 0-5V, Q2 makes it compatible with the regulated voltage VR by switching the voltage divider of R5-R6 or R5(R4 || R6).
  • RC converts PWM to DC the output of the level shifting is low-passed with a couple of R-Cs, the time constant set is much higher than the typical PWM period, so the circuit is a bit slow to react for the benefit of a quiet DC output.
  • Emitter follower - The DC output is passed through the Q2-Q3 emitter follower, which provides the isolation for the higher currency that is used to drive the current mirror Q4 (yellow in the scope screenshot above).
  • Current Mirror - LED Drivers - R9 || R10 || R11 || R13 set the current on Q4, the current mirror configuration makes the current at the collectors of Q5, Q6, Q7, Q8 the same, as long as the mirror is within the compliance range. R9 || R10 || R11 || R13 may be replaced by a single high power resistor. Depending on the current required by LEDs and the voltage power supply, the resulting resistor will likely be higher than 1/2W.

In short, PWM is converted to DC with minimum and maximum values of DC chosen to keep the current mirror operating. The current is set by the parallel of R9 || R10 || R11 || R13.

@matthewepler is testing the circuit (actually 4 times the above, one for each led color RGBW). After I get components and assemble, will post additional pictures/information with measurements of the board.

Keep in mind
As with any project/part there are some trade offs.

  • The amount of light LEDs produce is not linear to current. Keep that in mind when writing the steps for the PWM. A look up table can make the range more useful depending on the application. That is one of the reasons why 8 bit PWM may not give enough resolution for fine-dim-control, consider using the alternatives for 12 or 16 bit PWM control described above.
  • The PCB was made as through-hole. The mirror transistors were chosen considering that for the LEDs I selected are about 1W each. If LEDs require less or more current, Q3-thru-Q8 may be adjusted accordingly.
  • The LEDs I use in this project have a Voltage Drop of 9V, that is about 3 times the typical LED. Depending on the particular LEDs and the power supply, one of the mirror-transistor may be able to drive multiple LEDs in series. In the 24V example depicted is only two (9V forward drop each).
  • Four mirror outputs were chosen for the particulars of the LEDs on my project. In certain cases two or even just one may be sufficient, so only use Q6-Q7-Q8 as needed.
  • The 16 bit timer is used by other arduino libraries (servo library for example) so it is wise to confirm that you have the processor timers available when doing the workaround to make the PWM 16 bit.

Sorry for the long post. Information provided as-is, use as you see fit. Hope this design is helpful to the community and assist you in getting your project moving and selecting the components to your built.

Again, PCBs and schematics are at, more documentation to follow (when time permits).

Updated with language corrections, additional references, and illustrations


Here is the actual PCB. Found that the large transistor pinout was reversed, will be updating the PCB so the revised version has the correct orientation -metal facing the edge- for the option of heat sinking.
Nothing like a quick video to see how it works, so here it is.
The blue line is the PWM output (16bit timer), the yellow line corresponds to the Emitter of Q3, the voltage that set’s the current at Q4.

Pending further testing, but promising results.


As I mention before, the goal is to change the light for different exposures with the purpose of letting the arduino do the bracketing for the stacking takes.
Additional testing, this time one stop overexposed to test pushing the lower levels.

Some additional information, the Linear regulator runs a bit hot, while it is running with 3.5V differential the total current is close to 500 mA at maximum, so a bit of heat sink is in order to keep fingerprints from disappearing when touching the regulator. Alternatively, this may not be an issue when turning full power only for the exposure, instead of the slow increase for testing.
At lower levels, power/pwm noise is more visible in the resulting picture I am very pleased with the results after adding the onboard regulator, the noise seen on the protoboard is gone.

PS. Keep in mind that the integrating sphere is an oversized ping pong ball.

1 Like

To adjust for eye logarithmic response, the 16 bit PWM = pow(x,1.33337), where x range is 0 to 0xFFF (12 bits).
By using this function, linear increments of x result into exponential increments of the PWM.
The video below is the initial control testing (including the function above) for up/down through 10 preset. The steps were captured using a potentiometer to then create an array of the steps which the video runs up/down in a loop.
Looks like we have pretty decent control.

1 Like

– fantastic results!

I think your approach driving the LEDs with constant current is superior to using for example a Femtobuck driver, as the later will always have some high-frequency ripple in the LED-current, which is hard to quantify and to come by.

As it is visible in your above clip, the response curve (light output vs. applied current) is usually different for different LEDs. So you will probably need to use actually three different mappings from intensity to LED current (or PWM value), for each color a different one.

I encountered this issue in my approach as well and resolved it by doing a white balance on each of the five (fixed) exposure steps I am using. My current calibration for my five exposure steps looks like this:

RedLED     = [ 106, 220, 487, 1011, 1919, 0]
GreenLED   = [ 138, 303, 734, 1760, 4095, 0]
BlueLED    = [  52, 112, 246,  500,  912, 0]
LEDs       = [RedLED,GreenLED,BlueLED]

I am using only 12 bits, so 4095 is full brightness. As you can see, the actually currents for a given exposure setting which result in a whitebalanced output are quite different for the LEDs - for example, the blue LED typically runs with only half the current of the red LED, and both have lower current than the green one. The reasons is that the LEDs are indeed quite different from each other.

Thank you @cpixip.

In this case I am controlling white LEDs only, but as you point out it seems that the color balance changes with current.

1 Like

That is interesting! So your test shows to me that the whitebalance of a white light LED changes noticibly with different driving currents. Something to expect, but I have never checked it. This will make it difficult to use an illumination system based only on white light LEDs at variable light intensities.

After additional thinking, I think what we are seeing is a combination of black clipping and white clipping, in addition to a gain difference between the colors. In the following test, using the same current steps as before, I decreased the amount of light using the lens aperture. What -I believe- can be seen now is that there is a difference in colors, which is proportional to current (basically the gain of green, red, and blue is slightly different) and it shows that it was probably the knee and clipping of the camera that was compressing the previous test. Also, we are measuring the result of the entire system led source-current control-camera, and the camera sensor plays a role too. So one would have to be mindful of the non-linearities of the camera and the particulars of the sensor when using a light that is off-balance. But, with the additional test, I am wouldn’t conclude that it would be difficult to use White LEDs only when using current control, the same behavior would happen if using color LEDs that are not perfectly balanced. So my initial conclusion is slightly different, color balancing of light can decrease (or avoid) issues of camera non-linear compensation systems (knee/clipping).

1 Like

A couple of additional information points.

  • The video is captured using an HDMI to USB device. OBS provides some settings for a proc-amp on it, so there may be some differences between the live camera output (captured by the device) and a camera recording/capture. I did a white-balance on the light, and still see a bit of off-green.
  • The test below was done after doing the camera white balance on the light source, and while the colors remain slightly apart, the variation at different current levels are quite small… it is consistently off through the current range.
1 Like

That could very well be the case! And: good if the whitebalance does not shift too much (as your later tests indicate) when changing the current.

Indeed. You already pointed out the knee and shoulder deviation one would have to expect. Actually, one can circumvent this issue in two ways. One is to use the raw image data coming from the camera, if available. This is what I am using occationally, but it is rather inconvient for various reasons. What I am usually doing is working in the center of the camera’s curve (around values of 128 for 8bit-channel data, for example). I adjust the whitebalance for every one of the five exposure steps I am working with; the corresponding current values are simply stored in an array (see the example given above).

Here’s a log-plot of those currents, showing the deviations between the driving currents:


The efficiency of the green LED is noticibly reduced at larger currents compared to the red and blue one (the later need less driving current than the green one).

As I am using separate red, green and blue LEDs, I have to make that whitebalance adjustment for every exposure value I am using. Your results seem to indicate (at least for the white light LEDs you are using), that in this case, a single whitebalance will be sufficient - great!

Thank you @cpixip.

The workflow that I presently use for capturing uses RAW. Described in this post.

Back to the driver, the good news is that the design performs well, and by its modular nature, if one wishes to do white only or RGB or RGBW is just a matter of building more of these and setting the resistor for the operating current of the particular LED. Thanks again to the exchange of information at this forum, and the insightful discussions, suggestions and feedback.

We are not seeing ripple in the output current of the femtobuck, when the femtobuck’s dimming is controlled with an analog voltage (vs direct PWM). Can you elaborate?

Well, let’s see. The Femtobuck driver uses a AL8805 which, according to the data sheet, “is a step-down DC/DC converter designed to drive LEDs with a constant current”.

Now, the AL8805 is a switching regulator, basically connecting the power rail to an inductor for a short period of time until the requested current level is reached. After that, the switch is opened, but the inductor keeps supplying a somewhat decaying current to the LED. After a short while, the decaying current is sensed by the chip, and the power rail is again switched on. This switch-on-and-off cycle continues at a fast rate to provide an approximately constant current to the LED - albeit with a small ripple, simply because of the principle of operation.

Note that this has nothing to do with the way the input of the IC is driven (be it analog input or PWM), but with the basic principle of operation of this chip.

The ripple inherent in the operating principle will certainly not matter if this IC is used for home illumination purposes, as our human eyes will have difficulties to resolve any frequencies higher than, say, 100 Hz and the on-off cycle of the IC is much much faster than this. But I am not so sure if we are talking about cameras operating in the msec and faster regime.

With this small cutout from the AL8805 datasheet:

Screenshot 2021-10-20 181518

Let me also cite directly from the datasheet:

Reducing Output Ripple

Peak to peak ripple current in the LED(s) can be reduced, if required, by shunting a capacitor C2 across the LED(s) as shown already in the circuit schematic.

A value of 1μF will reduce the supply ripple current by a factor three (approx.). Proportionally lower ripple can be achieved with higher capacitor values. Note that the capacitor will not affect operating frequency or efficiency, but it will increase start-up delay, by reducing the rate of rise of LED voltage. By adding this capacitor the current waveform through the LED(s) changes from a triangular ramp to a more sinusoidal version without altering the mean current value.

So, even the datasheet is talking about output ripple, and ways to reduce it. And the last sentence indicates that it will never really go away (just be “more sinusoidal”).

This is in contrast to the LED driver described in this thread (or the driver I designed and described elsewhere in this forum) - here, the current supplied to the LEDs is indeed constant over time, without any intrinsic output ripple.

1 Like

We have not yet found a downside to using the femtobuck in terms of image quality, but that may be in part due to the way our scanner works. There are quite a few built-in delays which would hide things like the time it takes to ramp up power. For example, the sequence to snap an image, issued entirely from the control software, is:

  1. Tell the controller to turn on the color channel at the specified brightness
  2. Wait for the controller to tell you it’s done
  3. Capture the frame
  4. Tell the controller to turn off the channel you’re using
  5. Wait for the controller to respond

We’re communicating via TCP, which has been incredibly robust, but there is a tiny bit of lag. Doesn’t matter too much in terms of overall speed, and our exposure times are likely to be around 20ms/image. So my bet is that any ramping up is happening while we’re waiting for the controller to tell us the lights are one, and ripple is getting averaged out over the exposure time. I’ve done quite a bit of testing on the images we have captured and don’t see anything that could be attributed to that. Of course, in a system that’s pulsing the light from a camera trigger and working at much faster speeds, there’s no time to wait for power to ramp up, and exposure times are so short there may not be enough to cover the ripple.

@PM490 - I might be interested in trying out a version of this sometime soon. We need it to be 36V @ 330mA (max current). Each string of LEDs is a bit different in terms of the forward voltage requirements, but they almost all have the same current requirements. What would need to change in your design to accommodate these requirements?

@friolator when operating in similar power range, it would be changing the values of R1 -changes the operating voltage of the LM317, and the current at the mirror is set by the four parallel resistors at the Emitter of Q3.
36V and 330mA per string (4 strings in the circuit) would not allow the use of the on-board regulator, no big deal if the power supply is clean.

This may require an update on Q4 and good heatsinking. Since this is linear power, what doesn’t come out as light comes out as heat. So it is good to have a sense of the number of LEDs and the forward voltage to verify that the transistor handling the string is adequate. Let me know and I’ll draft some numbers.


Red1: 12x 1.99Vf, 350mA
Red2: 12x 2.05Vf, 350mA
Green: 6x 3.3Vf, 350mA
Blue: 10x 3.3Vf, 350mA
IR: 12x 1.4Vf, 20mA

The IR channel is a special case, and we haven’t started testing with this yet as it’s a low priority. The plan is to knock the current down with an inline resistor, which is why we have a current-set jumper block built into the design. But we didn’t hardwire the resistor onto the board at this time, because it will require some experimentation to determine the right amount of IR light to create a dust map.

Thank you @friolator.
For colors other than Ir, the power on the power in the current setting resistors would be between 1.5W and 3W each (multiply times 4), that is a lot of heat. The mirror would also require higher power transistors.

For Infrared, the design would work well, understanding is only one string. I am a bit short of time until next week, but if you are interested in trying it I can give you the specific values for Ir then.

Let me know if you wish to do about the higher power strings, it may not be a good fit for a single string, but if you like to try it let me know… and give me some time to look up some higher power transistors.

Thanks. Heat would be my concern as well. The current setup runs quite cool and is in a box on a DIN rail with several other things, so we’d want to avoid things getting too hot. Though we could put it on an aluminum PCB, and heatsink it, but we’d want to move it out of the box with the other stuff, if it generates too much heat. We’re in no rush. It’s something I’d try out at some point, but the system we have now works fine for us.

If you have a lower-voltage higher-current power supply the numbers would work better. The led strings (as in the schematic) can be adjusted for the desired number of LEDs, and a bit less heat would go into the sensing current resistor.

For reference the schematic configuration is close to 8W of light on 100mA LEDs, a bit more than the total green light (7W) from the numbers on the LEDs you shared.

Having more LEDs provides the ability to split into different sources on the sphere, and/or to physically distribute the LEDs for source pattern or heat management.

From the narrative on the scanning sequence, it sounds you will manage the light heat by only turning on for exposure… if should work. Let me know if you need any additional information.

thanks. Heat on the LEDs hasn’t been much of an issue for us. In part I think that’s because we’re only turning them on momentarily as you say. but also, the LED board is mounted directly to a 1/2" thick slab of aluminum, which is how it’s attached to the chassis. That alone will wick away a ton of heat. And we have mount points in that block for a fan, should we need it, but so far we haven’t.

I’m focused on other stuff now that we have the LED stuff mostly nailed down to our satisfaction, but may come back to this. Really curious to see how it performs relative to what we’re doing now.


1 Like