Wednesday, October 24, 2012

Ultimate Flashlight Code

For quite some time I’ve had two lights that use a really cool mechanical arrangement called Piston Drive that allows the light to have a switch at the back of the body that is a momentary switch connected to the driver instead of interrupting power to the whole light. My two lights are the Nitecore D10 and EX11. Sadly they’ve discontinued these lights since I bought them. Piston Drive is really cool, but I found that I never really used the lights because I didn’t like the way they were programmed. Well that has gone on long enough…

Modifying these two was a good opportunity for me to finally put into writing all of the ideas I have had over the years for flashlight firmware. I have always really liked the user interface on Novatac and HDS lights, so many of my ideas are stolen from their user interfaces. There are things about those lights that I wanted to change, though, and some new features that I would like. I also know some people that I will be sharing this code with who have their own preferences, so I wanted configurability. After a lot of thought I settled on this poorly-written description:

smart momentary
tactical momentary (reset by power cycle) w/ selectable mode
logarithmic level ramp
configurable, NVM-saved primary mode
novatac-style shortcuts to max (from on and off)
randomized strobe
emergency beacon mode
locator beacon mode
configurable strobe (?)
battery level monitoring(? this would require automatic detection of cell type)
temperature monitor & protection

required microcontroller features
software-configurable WDT
internal Vref for ADC (?)

1,2 power
4 temp ADC
5 temp divider supply
6 switch
7 battery voltage monitor


on power up, read in NVM, including user-configured primary mode, set it to current level. enter standby
in standby: if configured for locator beacon, set WDT and sleep, waking to flash beacon. else sleep with 
only wake source as switch. wake on switch change
wake: immediately output current level. measure press time to determine whether to latch on 
(smart momentary). long press: stay on in momentary, return to standby when released
short press: latch on at current level. if switch is pressed again within double click time, 
go do second press action
second press action: immediately output maximum. measure press time. short press: latch on
at maximum. long press: momentary maximum, return to standby when released
all momentary modes override temperature protection

while on: if switch is pressed, take no action immediately and measure press time. long press:
begin ramping brightness. if current level is <10%, always begin ramping up; if level is >90%, 
always start down. between 10% and 90%, ramp in the opposite direction of the previous ramp action, except 
that the first direction in any new session is down because there is no shortcut to low levels.
short press: turn off and wait for subsequent presses. if none, enter standby. if pressed again,
turn on again at last level and measure press time. short press (double click): go to primary mode
long press (click press): go to maximum mode
after double click monitor for further clicks. a triple goes to strobe mode. in strobe mode, functions
are similar to normal -- on and off are the same including momentary. double click or click-press to get 
back to normal modes. a press and hold (ramping command) changes to other special modes (so far just beacon
strobe). triple clicking while in strobe goes to configurable strobe mode

a quadruple click from on enters the setup menu
setup menu:
similar to novatac. click to advance to next option. press hold to activate an option
first option is tactical momentary. shows a single blink to indicate.  
once activated, output will be momentary only, in the last used light level (or strobe).
second is set primary level. indicate by double blink. when activated, it will store the last used 
level as the primary mode. 
third is locator beacon, indicate by blinking dimly like the locator. activating this will toggle 
locator on or off
fourth is force momentary to max. indicate with a long blink. if activated, all smart momentary outputs
will be at max level instead of last used level

configurable strobe(TBD):
config strobe is a one-time function, so double-click commands will go back to normal mode. on/off won't
work because single click has been reassigned. power cycling can also be used to go back to normal.
if double-click is used to exit, strobe settings are maintained and they will be the initial state the 
next time config strobe is entered. a ramp command changes the speed or duty cycle, and a click toggles 
between adjusting speed and duty

It turned out that planning the functions was the most difficult part. I wrote it for the PIC12F1822,  which is Microchip’s newest 8-pin part. Since µC cost is not a deciding factor for such a project, I had no reason to use anything other than the most capable micro I had available. After I had a complete plan, coding and debugging the software only took a few hours. Understanding the D10 and EX11 drivers, however, was fairly complicated. Both of them had an 8-pin microcontroller on the driver to control the output. The EX11 had a clearly marked PIC12F683 running it (a great choice of microcontroller; if I had known this one was on there I would have developed my code on the same part so I could just reprogram instead of replacing it). The D10, however, had some weird chip on it with power pins in non-standard locations and the markings were scraped off.

Both drivers use boost to generate power for the microcontroller from battery voltage. The EX11 has to be buck-boost to accept rechargeable cells, and I suspect the D10 is also. I really only investigated the aspects that were critical to developing the application firmware, though. Both lights use some kind of regulator to drive the LED that is controlled (or maybe just switched) by a PWM signal from the micro. The D10 is simple, it’s just switch input and PWM output, with a fairly fast pwm at 31kHz. The EX11 is more complicated as its PWM has a narrow range of 41% to 75% duty from min to max, and it has an extra output from the microcontroller to enter a low power mode in standby.

After working out all these hardware details by scoping the existing chips and then breaking out connections to my protoboard, I finalized code and installed my own microcontrollers. On the EX11, the chip is a direct replacement. On the D10, the new chip is floating and the four connections are wired into the old chip's pads. 

I have a version of the code for each light, and the EX11 version has an extra setting in the configuration menu that turns off ramping and uses 4 discrete levels. Here’s a video showing the user interface:

Code is here: D10 EX11. It’s my hope that this can easily be applied to many different lights (as I will be doing soon) so that other people can use it.

No comments:

Post a Comment