Flashlight Firmware Repository

That sounds nice. I also thought that it should be just a simple loop,
something like:

- start from 0 end at 255

- delay (milliseconds) //to slow the ramping down a bit

  • increase by 1

But I didn’t start from the scratch because most of the available codes have low battery warning and cut off which is very useful so I wanted to keep that (I mostly use unprotected batteries).
Intended driver is Nanjg105 with forward clicky switch.

Sounds like a fun little project. I might try throwing something like that together in the next few days.

Any thoughts on how long (seconds) the ramp should take?

I was aiming at something like 2-3 seconds!

FWIW, I made a ramping UI for clicky lights last night. I’m not completely done with it, but there’s not much left to add.

I call it “Crescendo”. It should work on Convoy’s lights, or any nanjg driver, or (with some small changes) pretty much any BLF driver. Instead of mode groups, it provides a smooth ramping UI. The basic use is like this:

From off:

  • Click to turn on; enters ramping mode starting at moon. Follows a zigzag pattern indefinitely, with brief pauses at the top and bottom. Ramping takes however many milliseconds the #define at the top specifies. Default is 2.5s.
  • Click-tap to go to moon mode.
  • Click-tap-tap to go to turbo.

In ramp mode:

  • Tap to stop the ramp and enter “normal” mode.
  • Double-tap for turbo.

In “normal” mode:

  • Tap to ramp up.
  • Double-tap to ramp down.
  • Triple-tap for turbo.

After reaching turbo, tap to advance to blinkies:

  • Battcheck
  • Biking
  • SOS
  • Whatever else it’s compiled with; will have commented lines at the top to add/remove blinky modes.

Any time the user does a long press, it starts over. When turned on it’ll go back to ramping mode starting at moon.

So, that much is working (though I haven’t really tested LVP yet). I’m debating whether I should try to add an option for memory. Any thoughts?

The code is currently only in my sandbox, until it’s more complete.

Edit: If I add a memory option, that would mean it would start in the last-used mode instead of starting in the ramping mode. But currently it uses no eeprom and remembers nothing for more than half a second or so. I’m not totally sure how the UI should work with memory enabled. Basically just put the last-used mode onto the beginning of the sequence and treat it otherwise the same? (memory -> ramp -> normal -> turbo -> blinkies) And to turn memory on/off, I’m thinking it’d have a “memory toggle mode” at the end of the blinkies? It’d be similar to short-cycle memory so there’s no need to go through all blinkies to get back to the beginning, regardless of whether memory was enabled. Anyway, kinda just thinking out loud here. Would love to hear what people think of it so far.

Crazy timing, TK. I was just testing a ramping UI. It’s nowhere near as complete as yours. Here’s a pastebin: http://pastebin.com/Paepe7f0

Mine has a few config options, but I stripped out all blinkies for now:

  1. Mode 1 - ramp from moonlight to turbo, stops at turbo if the user hasn’t stopped it
  2. Mode 2 - ramp from moonlight to turbo and back until the users stops it with a short tap
  3. Mode 3 - like Mode 2, except it has memory and turns on in “stopped” position
  4. Turbo timer toggle
  5. Reset to defaults

The modes pause at moonlight and turbo for a second before continuing with the ramp. Once the user has stopped the ramping, it can be started again with another short tap. I like your idea of double-tap to ramp down, or triple-tap for direct turbo.

Two things that were bugging me that I need to change:

  1. I started at PWM 1 and tried playing with Phase/Fast and the prescaler. But it makes noticeable “bumps” in the ramping. I see you started at PWM 4, used Phase for all levels, and left the prescaler static as well. I might need to play more with that.
  2. Instead of defining PWM levels along a pre-defined ramp, I just incremented/decremented linearly. I knew this wasn’t going to look good, but I was anxious to test something. And yeah… because our curved (logarithmic?) interpretation of light, it just looks “plain bright” for all too long. I need to borrow your curve. :wink:

Oh, I started the PWM at 4 because that’s the lowest level which activates the LED on the test light I was using. I have several decapitated tube lights with the drivers hanging out, purely for development and testing, and the one with a nanjg driver happens to light up at 4/255 in phase mode.

I considered adding PFM as well, to smooth out the bottom few levels… but I’ve done that before and it’s both complicated and unreliable due to being voltage-sensitive… and it doubles the space the ramp needs. But in ideal conditions, it can dramatically smooth out the stair-steppy low levels. I still use it today on my Roche F6 (Ferrero_Rocher/Ramping_UI_table.c).

I’d like to try it on a FET+1 next, and add memory, and change the active set of blinky modes. Kinda thinking of using this on my “good night” light, which needs a mode that gradually ramps down from low to moon for an hour and then shuts off.

Anyway, I couldn’t sleep last night and felt like making a new thing, so Crescendo happened. I’m thinking of maybe sending it to Convoy as an option they could offer on their lights, if there’s a demand for that sort of thing. It’d probably be easier for RMM to add though, since he already includes firmware choice in his ordering process. For Convoy, it’d probably have these modes:

  • Memory (optional, skip if disabled)
  • Ramp
  • Normal/Steady
  • Max/Turbo
  • Battcheck (4 bars)
  • Tactical Strobe (only useful via memory, but whatever)
  • Biking
  • SOS
  • Memory toggle

For my own use, it’ll probably be more like this:

  • Ramp
  • Normal/Steady
  • Max/Turbo
  • Battcheck (Volts+Tenths)
  • Good night
  • Biking (med)
  • Biking (high)
  • Heart beacon (1Hz, heartbeat pattern)
  • Party strobes (12Hz)
  • Party strobe (24Hz)
  • Party strobe (60Hz)
  • Party strobe (variable)

… or maybe I’ll trade some blinkies for PFM, because PFM is very useful for the “good night” mode. Haven’t decided much yet.

Ahhh, much better. I went ahead and converted over to a 64-level ramp based on level_calc.py. I’ve had a few instances where an LED wouldn’t turn on at 4, so I started at 5. Otherwise worked pretty well. Are there any disadvantages in using Phase for the entire thing instead of Fast?

And how do you properly use a prescaler? Does going from 1 to 2 essentially double the PWM frequency? Could you halve the PWM value to attempt to compensate for it?

I messed around with the Fast vs Phase and prescalers a bit more, but anytime I transition between settings there seems to be a noticeable bump. I really need to get edumacated some of these technical details. I’m very much a noob in dealing with hardware. I can code all day long, but it’s usually for data processing, websites, etc. I could really use some pointers about Fast/Phase and prescalers.

Disadvantages in using phase instead of fast: Mostly, it’s half as fast. It makes a 8 kHz triangle wave instead of a 16 kHz sawtooth wave. I can see 8 kHz when I’m not really looking for it, and it’s also much easier to hear.

Disadvantages in using fast instead of phase: Shorter pulses make low modes even more voltage-sensitive, so moon might be 0.5 lm on a full battery, 0.05 at 3.7V, and won’t light up at all at 3.3V. Also, every loop will be forced high at the beginning and forced low at the end, regardless of the PWM value. This means 0/255 won’t be completely “off”, and 255/255 won’t be completely “on”.

So, it’s ideal to use phase for 0 and 255 and moon, and use fast for everything else. But, as you noted, changing mid-ramp causes a bump. I don’t like bumpy ramps.

About the prescaler, it only lets you decrease the speed. There’s the CPU prescaler, which can cut the CPU speed by any power of 2 from 1 to 256… but it’s not usually a good idea because it tends to make the MCU require special hardware to reflash it later. There’s also the PWM clock select bits in TCCR0B, which cut speed by 1, 8, 64, 256, or 1024. So you can drop from 8/16 kHz to 1/2 kHz… or lower.

But we generally don’t want the PWM to go even slower, because visible PWM is annoying.

The only way to make it go faster is to run the MCU at 9.6 MHz instead of 4.8 MHz (typically more like 4.0 MHz). This lets you double the pulse speed, but it also uses more power. It could be nice for running phase-correct mode at 16-19 kHz though, instead of 8 kHz.

I see I thought it's 32khz and 16khz. 8,000,000/256 is ~ 32,000 (in round powers of two anyway). Doesn't the timer update on every clock tick with prescale 1?

I should know this since I'm using the timers for _delay_ms, but actually to me my one second sleep feels somewhere in the middle of the two answers and I haven't bothered to get a stop watch to figure it out exactly yet.

Toykeeper, thanks for developing the clicky ramping FW. It will be nice to have this option. Crescendo sounds good so far and I hope to try it out tomorrow.

I have been enjoying using your ramping_UI_table FW on my e-switch lights. One of my favorite things about that FW is having both memory and the ability to go to moon mode from off. IMO the inability to do this is a disadvantage of most all clicky switch FWs. Your Crescendo description got me thinking about a way to get around this. What if, when memory is turned on, the light turns on in moon mode, but if you don’t tap within 0.5 or 0.7s or so it goes to the last used mode. Not sure if this is feasible from a coding perspective, but from a UI perspective I think this would add a lot of functionality, at least for me. What do you think?

With a prescale of 1, the PWM counter and main clock tick at the same speed. So you get one pulse every 256 or 512 clock ticks (for fast or phase mode, respectively). The actual clock speed tends not to be what it says on the tin, though. I’ve measured attiny13 MCUs running anywhere from 3.6 MHz to 4.4 MHz, and none at the rated 4.8 MHz. This is why I generally say 8 kHz or 16 kHz instead of 9.375 kHz and 18.75 kHz.

However, the attiny25v running at 8 MHz seems to stay very close to its rated speed… like within 3%. Each one I’ve measured has been pretty consistent.

BTW, the clock speed can be measured pretty precisely by measuring the PWM speed and multiplying by 256 or 512. This is pretty easy to do on my fluke in “freq” mode with the leads connected to a spare LED. Normally, you send power to the LED and it lights up, but if you do it in reverse you can shine light at the LED and it’ll trickle out some power. The DMM can then measure the frequency of those power pulses.

That shouldn’t be too hard. I figure “memory” will be its own separate mode which is at the beginning of the sequence if it’s enabled. It should be able to do pretty much anything, including starting at moon for half a second.

I like having moon/max/mem all available from off, but I don’t know the best way to do it on a clicky. Anyone else have thoughts on this?

Without memory:

  • From off:
    • Click: Half a second of moon, then ramp up.
    • Click tap: Moon.
    • Click tap tap: Turbo.
    • Click pause tap: Steady mode at the ramp’s most-recent level.

With memory:

  • From off:
    • Click: Half a second of moon, then steady mode at the memorized mode/level.
    • Click tap: Moon.
    • Click tap tap: Turbo.
    • Click pause tap (or click pause tap tap): Ramp up (or down).

Seems simple enough. However, adding memory at all (and an option to toggle it) is going to take a bunch of ROM space and add complexity. With memory compiled in, I doubt it’ll have room for special modes on an attiny13.

Okay, I added memory. As expected, it used a lot of space. With the runtime option to toggle memory, it didn’t even fit on attiny13 any more. So, I made it a compile-time option only. It still uses a bunch of space though, so there isn’t as much room for other modes.

Still only saved in the sandbox; haven’t gotten it to a stable state yet:
http://bazaar.launchpad.net/~toykeeper/flashlight-firmware/sandbox/files/head:/ToyKeeper/crescendo/

I’m not sure I like memory on this. At least, not enough to sacrifice 200 to 300 bytes worth of other features. But I’m not sure I dislike it either. I’ll have to put it on an actual light instead of just a dev host, to see if it works well in practice.

Special modes can be memorized too. It still does a half-second of moon first though, which might defeat the point of memorizing a tactical strobe mode. Seems silly to give someone a gentle warning before going full-blast strobe on them. So perhaps it’s best to omit tactical strobes entirely on this UI, since there’s no way to get there immediately from off. I gave it a beacon instead.

In the one I threw together, there is a runtime option for memory. But as you said, I stripped out the special modes. I usually try to include them, but I never use them. Figured I could add them back later. In its current incarnation (updated to a 64-level ramp), it weighs in around 780 bytes.

Oh, and thanks for the explanations! I still have a lot to learn :slight_smile:

It sounds like I just overlooked what chip was being discussed. Sounds like a good trick for the frequency measurement. For me, I'd probably just set an interrupt to to count to 20,000 overflows and toggle the light on and off. Measure 60 blinks and you'd have a very good frequency measurement too. Of course an oscilloscope is the easiest.

I just flashed the hex file to a FET-only light and I love it. I think the delayed memory feature is great. I am actually quite excited about this because I have not been able to have these features together in a clicky light before now. Presumably this delayed memory feature could be added to regular mode FW like Bistro.

Now I will modify the code to get the low lower.

The ramping function in this clicky FW actually has an advantage over your e-switch ramping FW in that you can choose the ramping direction by single or double-tapping. With the e-switch ramping FW I find it often ramps in the opposite direction from what I want and I have to stop and reverse it.

For a FET driver, you should be able to comment out the current ramp and uncomment the one starting with some 1s. Hopefully there won’t be any issues with compiling it, but I could put a .hex up somewhere for it if you need.

The lowest level on a FET is going to be pretty bright though, and the bottom few levels will have a pretty chunky stairstep effect. A FET+1 would behave much better on the low modes.

I did lower the duty cycle for the lowest modes, but it is still a bit too bright. On another FET-only light I put a ~100 ohm resistor in parallel with the LED and it seemed to lower the lowest mode, but it doesn’t seem to be working on this light.

I did get it to compile, but it kept saying it overfilled the memory so for now I had to get rid of all the modes past turbo to get it to compile. Using an Attiny13A.

There would not be enough room on the Attiny13A for the second ramp of the FET+1, correct?

ToyKeeper, I have a couple of questions.

Today, I have built S2+ triple with driver taken from A6, and I’d like to use Crescendo. Is it using OTC or the same magic as new Simon’s drivers? The cap on my driver doesn’t like cold. Last time I was on a mountain, the light was almost unusable, so the new way of handling mode changes would be awesome. Can you give me any tips on generating modes table, because right now moonlight is more of a daylight.

Thanks!