Step 5: Firmware

The main function of the firmware is to monitor the brightness control (via VR1, serial port, or IR remote) and control the output. At start, the brightness control via the potentiometer is read via A/D(analog-to-digital) converter and used as initial brightness/dimming level.

Main loop
The controller creates reference voltage V-REF (see "Reference Voltage Generator" circuit of the schematic), which connects to one of the built in comparator's positive input. Current sense voltage C-SENSE is compared against this voltage by the comparator. The microcontroller turns on the Q1 for a quick moment, then see if the inductor current was high enough to "trip" the comparator (which means that L1 current reached or exceeded the desired level). If the comparator did not trip, the "on-time" is increased and the cycle is repeated until the comparator trips. If the comparator trips, then the "on-time" is reduced a bit, then the loop continues. This forms a simple feedback-loop controller. Essentialy the output level is set by the reference voltage.

Reference voltage is created by outputting (software) PWM signal of duty cycle proportional to the desired voltage. The PWM output from the microcontroller is voltage clamped by a diode (to the same scale/level as the current sense voltage), then smoothed by R15 and C8 (RC filter). This reference voltage stays between 0 to 0.6V.

A/D converter is not suitable for reading the inductor current because of the (lack of) speed. Inductor gets short bursts of current, in microsecond intervals. Comparator can respond to a peak current like this, while A/D converter requires the input voltage to be stable while sampling.

The "on-time" signal is generated by the hardware PWM module. It is configured to generate PWM frequency between 32kHz to 175kHz (configurable). The frequency changes according to the dimming level. The lower the brightness the lower the frequency. By changing the frequency, the effective duty cycle of the output also changes. Combining the duty cycle change to the current change via the switch mode converter, much better dimming curve is achieved.

Output over voltage protection
When the output is open (i.e. nothing is connected, bad connection or dead LED) or too many LEDs are connected in serial, the output voltage can get too high for the MOSFET to handle. MOSFET used here can handle up to 60V between Drain and Source. Higher voltage can destroy the device (rather quick smoking death as I experienced a few times during development).
The output voltage is attenuated so that the voltage is safe for the microcontroller (below 5V), then fed to the comparator module. Internal reference voltage is set so that the comparator trips at about 59V (configurable in about 3V steps). The comparator is connected internally via hardware to "shutdown" PWM output when trips. So this output over voltage protection works instantaneously as it should. (Another reason I needed comparators built-in) When the protection kicks in (via hardware), the firmware detects it, and stops the operation, then blinks the status LED. Only power cycling can reset this condition.

Supply Voltage Sense
Supply voltage is read by A/D converter and the value is used to compensate for the output level, so that the output power is consistent over a range of supply voltages. Also, supply over voltage protection kicks in at xxV (configurable in firmware).

IR Receiver
IR remote signal is detected by the sensor and generates interrupts. The signal is decoded by the ISR (interrupt service routine).
You can control the brightness/dimming level, output on and off via the IR remote. When the brightness is changed via IR remote, the potentiometer is disabled until it moves again.
Only Sony remote protocol is supported at this time (of course you can always add other protocols).

Button switches are polled about every 4 millisecond and debounced in firmware. Brightness up/down function is implemented for now. (but they can do anything you want)
When the brightness is changed via the buttons, the potentiometer is disabled until it is moved again.
You can also connect external buttons via SPI port for quick & easy remote control. (see the schematic)

Bi-directional Serial/SPI Control
SPI style serial can be used to control this controller. Only brightness/dimming change is supported now. The 8 bit brightness data is sent out via the same port when you move the potentiometer. So if you connect two or more of this controllers via SPI port, all of the controller can be controlled by just moving one of the potentiometers (gang dimming). This comes in handy when you have a bunch of controllers to light a large room.
SPI port and the button switches share the same I/O ports, so the firmware determines the source of the signal by the duration of the pulse. Since humans can only push buttons so fast, pulses that are longer than about 47 microseconds are considered button push, and shorter ones are decoded as SPI signal.
The data format is straightforward - just send the brightness level in 8 bit format. That's it for now - maybe expanded to do other things...

Open Source
You can download the source code as well as the HEX file to program the microcontroller. I'd love to see someone extending my code.

I was thinking about using a DAC to generate the reference voltage on a laser diode driver I'm working on. The design is based on the PIC12F752. Have you ever tried doing it like that?
I haven't done it, but using the DAC would make the software a bit simpler. But the problem with the DAC contained in 8 bit PIC is that its low resolution. If I remember correctly the DAC only has 5 bit or so. Some PIC24 series have 8 bit DAC and that would be perfect.
Yeah, it is a 5-bit DAC. 31 dimming levels probably aren't enough for fading effects, etc, but it's more than enough for modes in a flashlight or laser pointer. It looks like the PIC16F1704 and 1705 have an 8-bit DAC. The 16F753 has a 9-bit DAC. Getting more bits than that would force us to use packages with more than 14 pins.