Flashlight Firmware Repository

Thanks Flintrock for this answer that helped me at several points. Although I’m looking for 13A firmware. Bistro and your HD is way above my head. I looked at HD briefly, too much code I don’t yet understand and it takes me way too long to google every unknown part.

I just compiled (all with -Os) my old fashioned, ‘Star’-based firmware with LVP to 950 bytes. Then I deleted the flash before stepdown and got 826 bytes. Wow. That alone eats a lot of space.
Then I changed the rest of the LVP part to the code from biscotti (not WDT based) and compiled to 722 bytes.

Now I understand how TK could cram so much into the 13A…

But as I understand that Sleep-Mode-Idle and WDT really saves some mA, and I don’t need strobes, I will try to keep WDT unless all I want to add exceeds 1k.

Hmmm, you firmware people really have been busy in the last 2 years…
Thanks for sharing, to all of you.

Sure, yeah WTD should be fine for idle if you don't need strobes. For sleep mode idle you don't need to see all that code, just the fr-delay.h, but I doubt you need to see it. You know how to use WTD and how to enter sleep.

Bistro HD actually has attiny13 support. In fact it has a biscotti-HD configuration already built in the Makefile, (and somewhat customizable from its config file) that comes in a few bytes smaller than original biscotti with a couple of added features. I don't recall if I have the sleep mode enabled. It's the OTSM_powersave option, which actually works even if OTSM is not used (I should change the name of that control).

It does seem that I've put a warning and an undefine for this option in attiny13. But now I can't remember or see any good reason why. I just uncommented that and compiled it with that option and it compiled fine, so it must not be using anything undefined for attiny13. maybe I just did it to save bytes. Hmm.. It does bring the biscotti build up to 1032 bytes, but if nothing else just removing the added turbo-timeout feature will get it back down. I really can't see why I disabled that option now. Maybe I'll un-disable it. hmm..

The bistro HD code does start to look a bit overwelming. I tried to avoid code re-organization becuase there was a tradition of single file compilation without even function prototypes. This makes it easier for some simple compiling methods and was fine for bistro, but it starts to get close to its limit now, and is bending the rules a bit.

Anyway, one thing I did add is the makefile produces preprocessor output for all builds, stripped of comments. Other than some ugly MACRO expansions of things like PORTB and pgm_read_bytes(), these put the code into the lean and clean form after all preprocessor configurations are factored in. Maybe I'll start including those in the distribution.

So my single-cell battery charger had been way under charging recently and I hadn't noticed or cared much. But that explains this light not getting hot. (I thought I had others I'd been using before that got hotter). Now it runs at 3.5A (on still slightly less than full Pannies) and the thermal protection kicks in. But it is very on and off. It hits the limit and marches way down to 1st mode... cools off a while, and marches straight back up, repeats. Probably related to poor thermal path.

The thing is though really nailing feedback problems like this in a general way, is very very difficult. You can do it with just a proportional gain (probably what Dr.Jones does), but there's probably no one gain that will work well for every light. You'd probably need to work out a response time and extrapolate curves to predicted temperatures, correct, re-measure, extrapolate the correction... Not easy, especially for an attiny.

I wonder though if just having it somewhere inbetween bistro and BLFA6 would be good.

Update: ok, so the problem is that the goal isn't even clearly defined. There are really two very separate uses. One is someone wants to be able to see something with the most light possible once in awhile. That's true turbo mode. Two is someone wants to get the maximum sustainable power out of the light, possibly in changing conditions (this is biking mode really) For option one, finding the stable power level isn't even useful, going to that level prevents ever returning to turbo because you keep the light maximally hot. And dropping down way low, and automatically returning to turbo also isn't useful. You're not going to be able to know when the user needs turbo again anyway, and bouncing up and down is silly. So timeout, or temp-out and bump up makes tons of sense for option 1. Dynamic regulation doesn't make sense for option 1. For option 2 you never need to even reach turbo. The best system would analyze the heat curve and zoom in on the sustainable target without ever overshooting it in the first place. You could overshoot a little and then settle in, but I don't see much point. These might even be ideally different modes, although every mode should probably have the temp regulation applied, for safety.

Option 1 can be modified so it "times"-out on temperature instead of time. That would be nice, but it's still then just a single big step down and wait for the user to bump it up.

The further problem though is that option 2 is very very difficult to actually achieve in a general way for every light you might flash the firmware to. Gain feedback probably needs to be tuned, or needs to be very smart. So is it even sensible to have any mode that dynamically regulates on a generic firmware? Maybe it makes sense just to have a defined COOLDOWN mode and any time any mode maxes out on temperature it resets to there, with ability for bump up (but this time with timeout?). That adds safety to all mode levels, and provides option1 functionality, but doesn't attempt to provide option 2, and certainly doesn't attempt to mix them, which I think just doesn't make sense really.

Ok, nuff talking stuff done.

attiny13 idle

Regarding powersaving in attiny13 I had disabled the attiny idle sleep aparently because it didn't compile on the 13 and it just got it going, but the reason was that Atmel decided to do entertaining things like call the timer 0 interrupt TIM0_OVF_vect on attin13 and TIMER0_OFV_vect on attiny25, just to mess with us. So some macro defines sorted it. So biscotti-HD for attiny13 can now have pwersaving and actually it does fit (confused myself earlier). I consider that one of several customizable bonus features though.

Thermal turbo boost

Regarding thermal control. I threw together a quick BLFA6 like turbo except it applies to all modes and it jumps down based on temperature not time. Otherwise it's like BLFA6 though, not like bistro. When too hot, it jumps down to a predefined mode (default RAMP_SIZE/2 for now). A fast tap bumps it back up. I thought it might be nice to switch to timeout control after the bump-up but that probably adds more code, and actually I like it this way. You still get 4 seconds minimum because that's how long it spends verify the overtemp, but then it will pull you back down again if it's still too hot. 4s is enough to see something in a pinch. I could somehow pad it with initial time to increase minimum time without further increasing the first overheat delay. I really like this setup. The auto multi-step down auto multi-step up alternative just starts doing its own dance that doesn't really help me use the light. This just protects the light, and then puts me back in control. Oh and it came in 10 bytes lighter.

I'd consider a true temp regulated mode as a different thing and a more difficult task, and something to be added in addition to this. I might play with it. I think you can roughly predict the final temp as linear combination of the last two readings. It doesn't need to be a good prediction so long as it converges correctly. The tough part is figuring out the correction gain. This is predictive though not reactive, and so hopefully wont oscillate, but it still probably can oscillate in some conditions. Anything mathish like this though tends to take a bunch of bytes.

Hey FR, I’d love to take a peek at that attiny13a interrupt code. Do you have it posted anywhere?

It's in HD:

https://budgetlightforum.com/t/-/44344

Nothing actually changed in the code, just some of ATMEL's register macros. As I recall TIMER0_OVF_vect had to change to TIM0_OVF_vect and TIMSK and to change to TIMSK0. there might ahve been another one but it will be obviouus when you try it.

So I change them to _TIMER0_OVF_VECT_ and _TIMSK_ and in fr-tk-attiny.h

add

#if ATTINY == 13

#define _TIMSK_ TIMSK0

...

you get the point.

I'll post this new version up soon though, but that's all I change, oh and removing the override on that on option.

Oh yeah, the relevant part of the code is in fr-delay.h. You need the interrupt there, and the initialization is mostly done in the delay function, although as I recall actually configuring and enabling timer0 is done in init_mcu in bistro.c You can ignore the PWM4 stuff. Basically if PWM4 is engaged I have another interrupt waking at known intervals anyway, so I use that instead and don't setup another one, but you can just ignore that.

I've made a post for the thermal control discussion (if any) here:

This is the sort of thing a nicer MCU would really help with. However, given the attiny25 as a target platform, getting it to work is … unpleasant.

The standard method is PID, which is far fancier than what bistro does. Kalman filters might be an even better method, or a complementary method. I doubt there’s enough room to do either of those properly though, so I was thinking of upgrading to 10-bit sampling and doing something with the first or maybe even second derivative of the temperature readings. That way, it could react based on whether the temperature is rising or falling, or even if it’s accelerating, instead of just whether it’s currently too hot or not.

A first derivative would be pretty simple (even on attiny)… just subtract the previous measurement from the current measurement. Then add, say, two or four times that to the current temperature to predict where it might go in the near future. If the prediction is too hot, ramp down. If the prediction is too cold, ramp back up. Both adjustments can be proportional to how much the value deviates from the target.

This method would amplify any noise in the measurements though, so depending on how noisy the measurements are, a lowpass filter might be required.

TK, I'm not sure you need second derivative. You have the benefit of knowing that at least if the mode hasn't changed recently, heat tends to move exponentially toward an asymptotic limit, with a fixed relationship between first and second derivative. That means the end point is related to the sum of the preent value and something times the slope. The second derivative helps if there have been recent mode changes and there may be an overshoot hump coming, you could detect that. Yeah, that could help avoid oscillations, as you point out though, if you have the resolution for this kind of correction and the computing power. Notice if you do this well, predictively, you probably never reach turbo.

Oh, also the thermal delays can be large enough that you may already have two unavoidable humps queued up in the heat profile. Hard to predict that. But if you're doing things well from the start, maybe you don't ever have any humps, which is why I think first derivative might get close enough. I think the hard part is knowing the delay well. If you're reading recent changes and assuming you need to adjust but those changes are related to what happened 20 seconds ago, your adjustments are wrong and you're creating oscillations.

The hardest thing about all this is the timescales for the delay are similar to the time scale for the full range change. That spells trouble. Of course we know the reason, the sensor is in the wrong place.

Finally I will have time to play with the code.
I already started today.
Accomplished nothing.
C language is hard…

In bistro firmware, how do I add more modes? I can only get maximum of 9 modes including moon mode. I want 12 modes, should I add more numbers here?

Make sure “modes” array is defined large enough. And you’ll need to mess around with the count_modes function. Reconfigure these lines:

That “<<3” will need to become “<<4” and then you’d have to make yourself​ modegroups 16 bytes long instead of 8. This is a bitwise shift, not terribly obvious.

… Or you might take a look at Flintrock’s BistroHD’s count_modes. I think it handles variable-length modegroup sets.

I tried it but I can only get one mode, moon mode.

Perhaps put your code up on pastebin or some other public place so we can take a look?

Here it is https://pastebin.com/ZbTrMaRP
The first modegroup works fine. the 2nd modegroup is a mess and the 3rd modegroup is all moon mode.

All of the mode groups must be 16 values long with the exception of the last one. And I think your modes array needs to be bigger. Give those changes a try and let us know. And update your pastebin when you make changes. Good luck!

Oh ok.
When you said “make yourself​ modegroups 16 bytes long instead of 8” I thought it’s like this
for(solid_modes=0; (solid_modes < 8) ——change to—-> for(solid_modes=0; (solid_modes < 16) that’s why I changed the 8 to 16 :person_facepalming:
Ok I’ll try your last suggestion. Thanks.

Gotcha. Need to do both.

Now I’m trying to compile biscotti to adopt it to different drivers that I have (moon mode, blinking speeds, etc.) but I keep running into this:

“$ sh ./build.sh biscotti
avr-gcc -Wall -g -Os -mmcu=attiny13 -c -std=gnu99 -DATTINY=13 -I… -I…/… -I…/…/… -o biscotti.o -c biscotti.c
biscotti.c: In function ‘blink’:
biscotti.c:508:9: warning: implicit declaration of function ‘_delay_4ms’ [-Wimplicit-function-declaration] _delay_4ms(speed); ^
avr-gcc -Wall -g -Os -mmcu=attiny13 -o biscotti.elf biscotti.o
biscotti.o: In function `blink’:
/home/benoe/Sources/flashlight/biscotti.c:508: undefined reference to `_delay_4ms’
/home/benoe/Sources/flashlight/biscotti.c:510: undefined reference to `_delay_4ms’
/home/benoe/Sources/flashlight/biscotti.c:511: undefined reference to `_delay_4ms’
biscotti.o: In function `toggle’:
/home/benoe/Sources/flashlight/biscotti.c:561: undefined reference to `_delay_4ms’
/home/benoe/Sources/flashlight/biscotti.c:561: undefined reference to `_delay_4ms’
biscotti.o:/home/benoe/Sources/flashlight/biscotti.c:561: more undefined references to `_delay_4ms’ follow
collect2: error: ld returned 1 exit status”

I didn’t clone the whole repository but handpicked the files, but everything should be in place.