alexvh's firmware. Update: Hidden strobe, Ramping and optional mode memory added.

Those strobes are calibrated to freeze motion, not to stun people… so yes, they’re not supposed to be terribly bright. The duty cycle is only 0.3 to 1.0 milliseconds per flash. I find it entertaining to see still frames of fast-moving water and such, so I built it into my EDC. It’s fairly easy to change though, just by editing a few numbers in the code.

The brass-edc firmware used to have short-cycle memory, but I changed it to use the memory retention trick described earlier in this thread. So, the end result is offtime no-memory. (also, I think there may be at least two different definitions of “short-cycle memory” floating around BLF)

The starry-offtime firmware requires an actual offtime capacitor in order to work, which the stock AK-47 driver doesn’t have. Also, it’s designed specifically for drivers with two independent PWM channels, which the AK-47 also doesn’t have. Probably not a good choice for this purpose. When I compile it locally, it works out to 1018 bytes, so it’s almost but not quite at the limit of 1024.

Not sure about the OP’s firmware. I took the flash out of mine to save space, but retained low-voltage step-down and eventual shutoff.

With a zener mod on the driver, almost any common attiny13a firmware should work. The only caveat there is that low-voltage detection might not function… and serial battery configs are significantly more risky than single-cell or parallel configs.

Beyond that, it mostly depends on what kind of switch you use (clicky or e-switch) and what you mean by ramping. I have a smooth-ramping e-switch firmware available (ToyKeeper/Ferrero_Rocher/Ramping_UI_table), DrJones has a clicky switch one (luxdrv), the OP of this thread implements ramping and the memory-retention trick for clicky switches, etc.

Personally, I like ramping with an e-switch and dislike ramping on a clicky switch. The e-switch means I can press-and-hold to ramp, then let go when it gets where I want. To ramp again, just press-and-hold again. Otherwise, you have to enter a specific ramping mode first, wait until it gets to the right level, then tap to select it as a steady mode. I’m not sure how you would enter ramp mode again after that, or how to quickly go to the highest or lowest mode without ramping.

Good points about the different switiches. Now does the “issue” with mechanical switiches apply to all as a class, or only to reverse clicky? I would think/hope/guess that a forward clicky could simply be released hopefully like an electrical switch?

And would a magnitic switch be considered Mechanical or Electrical?

I guess I made an incorrect assumption.

I thought I understood correctly that CC drivers were more efficent and did not produce as much drain or wasted energy in heat. I thought that Zener Diode mods were very inneffiecet at lower power levels(lost of wasted energy into heat), thus I thought that CC and Zener were mutually exclusive designs.

I guess I made a mistake but I dont know where?

There are basically two types of common switches in lights… one type works by cutting power entirely. This applies to basically all clicky switches, whether forward or reverse or other. It’s like a light switch (rocker switch) on the wall, on or off.

The other type works by continuously sending a “high” or “low” signal to the driver (shorted or not), and the power stays connected in both cases. This is the e-switch I was referring to, and can be magnetic or not. It’s like a button on a game pad.

Zener diodes tend to have a constant small drain whenever power is connected, so for an e-switch that means it would keep using power even when the light is off… unless you physically disconnect the power by loosening the tailcap or something. There are more efficient approaches, but I haven’t really looked into the details very much. I think wight has a driver or two specifically for this purpose.

Some lights have both, like the Convoy L4. It has an e-switch near the head and a clicky switch on the tail… so you can get the best of both worlds.

I’m leaving out other types of inputs, like Nitecore’s 2-stage e-switch and magnetic twisty rings like on the Jetbeam RRT01, and lights with multiple e-switches. We don’t have common firmware which supports those.

This works very well on the ATtiny85 too. I tested with brownout levels at 1.8V and 2.7V. Maybe there was a slight difference in window time with the 2.7V level, but note that I have a 4.3V zener on the PCB which might have an impact on the 2.7V level detection.

Edit: Hmm, there might be a difference in window time with the low voltage versions… Might test that someday. Will probably be too short to care about, if there is any difference at all.

Anyhow, this is good stuff. Thanks Alex!

This research paper details a technique that can be used to detect short versus long off-time. Look at Figure 1.

I’m going to test to see if this works, but the impatient may want to try this on their own.

Looks cool in general, but I get the impression that the attiny13a might not be able to use this trick. If I understand correctly, it is basically taking a sample of many bytes of “noinit” RAM instead of just one, and estimating time based on the ratio of decayed vs intact bytes. But that requires a lot of bytes in order to get a reliable measurement, and it probably needs a slower decay than what nanjg drivers have.

Maybe it could work if a significant chunk of RAM was set aside for it and we counted bits instead of bytes. But what we know so far is that a single byte decays completely in about 0.5s. I haven’t seen evidence yet to suggest that a larger sample would last significantly longer.

I could be totally wrong, but at a glance it looks like a long shot.

That’s interesting. We’d need to do some testing to better understand how the SRAM in the attiny13 decays. Maybe by using another microcontroller to switch the attiny off for a measured amount of time with a relay and counting the number of bits that have decayed when power has returned.

Actually, we just check if the entire byte is still zero. Which just means that no bits have decayed before 0.5s, but at least one bit has decayed after 0.5s. So we can’t rule out this method yet.

We need to count bits that decayed, not bytes. So if we initialize a byte array to 0xff, we can then count how many bits are set to 1. This is what I intend to do and to try to get a correlation between percent of 1 bits and off time.

I used 10 bytes and counted the number of bits that changes after a power cycle. I found that the percentage of bits that change value converges to 50% pretty quickly and consistently.

My conclusion is that the time constant for data retention in SRAM is too low for our use.

OTOH, the off-time cap on one of my drivers still gives me a nonzero value after being powered off for like an hour.

I could totally put in an easter egg where if you leave the thing off between 20 and 21 minutes, it’ll blink out the morse code for “pants are optional”.

Looking at Figure 7 in the paper, the transition region labeled Stage 2 is too narrow to reliably detect between long and short off time. Furthermore, the duration of each stage is dependent upon the capacitance of the power supply smoothing capacitor, as shown in Table 5.

In Section 8 on page 13, the OTC method is described as an alternative.

Yes, exactly. I meant that we currently check a byte to determine a short press. Right now in my firmware I just check if the entire byte is still 0, if it is, that means that no bits have decayed to 1.

Also from the paper:

After some experimentation it seems about 74% of bits in SRAM favour a state of 1. Even after really long off time 74% of bits decay to 1 and the remaining % don’t seem to decay. So it is better to set all bits to 0 and measure how many have decayed to 1.

I’m still experimenting, but this method looks promising. I don’t have a way to shut off the attiny for a measured amount of time, but just doing it by hand I’m able to see that longer presses result in more decay. Short presses of less than 500 ms result in no decay, which we already knew.

Here’s some quick measurements:
off time | % of memory decayed
615ms 8%
780ms 33%
825ms 40%
925ms 56%
1250ms 67%
1600ms 69%

I think this method could probably work.

I used 32 bytes of SRAM in my test. I counted the number of bits that are equal to 1 and output it as pwm so I could read it as a percent with a multimeter or oscilloscope by measuring duty cycle. Here’s my code if anyone wants to play with it:

Cool, so maybe we can get 3 levels after all. :slight_smile:

I didn’t expect it to have a long enough decay window to be useful.

Alex, those are good findings. I performed my test on a breadboard and so there are differences such as capacitor values and lack of voltage divider for LVD. Both of these will affect the decay time due to dropping Vcc. So your results with actual driver trumps mine with breadboard.

Originally I had initialized SRAM to patterns with equal 1s and 0s. I then tested all 1s and all 0s and found that all 0s work best. This agrees with your results.

I think the stack is implemented using SRAM, so that may explain why you are getting 74% max decay rate. Can you try inlining the hamming_weight function?

I’m only checking 32 bytes, half of the total SRAM, and I declared it in my code. So I’m not checking any of the SRAM that would be used by the stack. I believe only 74% decays because the remaining SRAM just prefers to stay at 0. 74% of the bits seem to end up 1 whether I initialize to 1 or 0 so I think it’s just the hardware. I’d like to see some other people test this so that we can see what the decay rate for other attiny13’s is and how much it varies. If this is something that varies a lot and requires calibration there is probably no point to doing it this way, and the capacitor mod would be the better solution.

Also, does anybody know what off times correspond to short press and long press for firmwares that use the capacitor mod?

I’ve been using:

  • Short: < 0.5s
  • Medium: 0.5s to 1.5s
  • Long: > 1.5s

So, the measurements shared a few posts ago look very promising.

If this method works, and if it can work with a smaller array, I’ll probably add it to my no-OTC firmware. I never did fill those 262 bytes I freed up by switching from on-time to mem-decay… :slight_smile:

Good stuff! I’ll be testing this out on my ATtiny85 firmware tonight. Being able to do this will save me from using the reset pin as an IO, and that’ll be a major headache saver.

I did try something like this as soon as I had tested the simple 0 method, but I only tested with a single byte and only checked if the value was 0, 255, or anywhere between. I got some results but they where not reliable and put on hold. Counting individual bits in an array of bytes will give much more reliable results for sure. The ATtiny85 has 512 bytes of RAM so I can use more bytes for better resolution.

With the ATtiny13A one should pay a lot more attention to RAM usage when using this method as it only has 64 bytes of RAM. Adding a 32 byte array to an existing firmware with many features could exceed the 64 byte RAM capacity, resulting in unpredictable behavior.

I tried it with the attiny13 in my edc flashlight as well and it seems to decay to 70% 1’s. So maybe attiny13 SRAM tends to favour 1 in general.

It should be possible to use less bits for this. I just wanted to get a large sample size so I used 256 in the test.

I’m going to try to put this into a firmware soon and see if I can get it working reliably.

Getting 70% on the ATtiny85 too.

Been testing and it is working with three levels, but the testing made me realized that for me personally the decaying starts too late to use it for detecting three defined off time intervals. I’m used to my off time firmware where a medium press is well under half a second. For me it’s just easier to use double and triple clicks rather than holding the button for as long as it takes to get a reliable difference between off times.