Success! Thermally regulated linear driver

Yes, eeprom can probably work too, but you still need a few bytes of noinit comparisson to reliably see the long press. Once you're setting a few bytes to the same value, might as well set them to the value that matters. If you need multiple sets of all bytes, like a clear and an increment, then maybe that starts to get a little more costly in terms of instructions, depending where it's done and if the variables are still in regeisters from the set when the clear is done(Ok, clear doesn't need the value but anyway some details may matter...) Of course a problem with any multi-byte thing is there can be interruption in the middle of it, but the odds on that are also pretty slim, and can be made slimmer with assembly programming, if one really wants.

Also eeprom is very slow (like multiple ms, which probably implies worse interruption concerns), and it has limited writes. Bistro adds wear leveling to anything written to on every single click (presently just the mode inex) to avoid writing to many times to a single byte. Maybe that's overkill, maybe not (100,000 writes max by spec), but you'd need more code if you want to do this to more variables as the wear leveling code isn't very general.

It's definitely option, and probably more than one way to skin this (including using attiny25's and OTSM) but each may have its own issues as gchart notes.

Very cool GC.
I can do the solder work but exactly as loneoceans posted above I need a translator most of the time.

BTW, I’ve got the multi-byte noinit stuff working just fine in the manner that Flintrock described. For proof of concept, I only used two bytes, but adding an extra one or two wouldn’t be a problem at all.

I need to remember to check and see how much extra space that takes up. I’ll report back later.

And yes, there’s all sorts of ways to address this. But I’d like to see it work on the typical nanjg drivers that are so prevalent… no OTC mods or anything necessary. Especially with the several reports of Biscotti acting funny due to the current noinit implementation, this should solve that.

But I got my 47uF tantalum caps and low leakage diodes now and will put together an OTSM build with bistro, of course not nanjg or attiny13.

Cool, yeah, the cap related comment was not aimed at this case.

Ok, I’ve done some initial fast_presses redundancy size testing. I can’t say these are the most optimized, but it should be pretty good. The code can be found here. I’m open to suggestions… looking at you, Flintrock :wink: You’ll notice I was also testing out your variable-length mode groups, FR. With the current mode groups set up, it was adding about 14 bytes. But if I wanted groups longer than 4, I bet I’d see efficiency over making all the groups longer.

No redundancy: 984 bytes (control program)
Using 2 bytes: 1010 bytes (+26 bytes from control)
Using 3 bytes: 1028 bytes (+44 bytes from control)
Using 4 bytes: 1044 bytes (+60 bytes from control)

cool, 60 bytes sounds reasonable to me. I was hoping for 50, but that was kind of just my guess. Yes the variable mode-group length has a little buy-in price. I haven't looked yet, will soon, so not sure how this translates to the tiny13 firmware, but the next biggest savings was probably all the array looping of the menu variable operations, save, restore, and toggle. The easiest savings were probably

a) going through every function and trying with and without inline as the compiler doesn't optimize this as well as you expect even though it's only supposed to be a hint, and it's not always as obvious as it seems which way is best.

b) Changing some key variables to register variables. (and it matters which register is used).

really it would be great if we could figure out how to include the attiny13 software as a subset of bistro(already setup that way in principle, but in practice may be hard now to get a small enough configuration). I might look at it. Then these changes don't need to be maintained in two places. But it's good this way too. It's not like it's a huge program.

Yeah, I just went thru the inline / no-inline exercise on every function. Can be a good amount of savings there. Now that I’ve refreshed myself on inline functions, I’m using them more to make the code easier to read. It had been about 12 years (college days) since I last used C for much.

I’ll have to take another look thru your code. I’m not real familiar with the register variables

One thing I was shocked about is how much space can be saved by using local variables instead of globals when hitting it frequently. Like in count_modes(), swapping out solid_modes for a local variable when iterating thru.

So bistro-HD seems to compile for attiny13 just fine and I guess the nanjg layout that I essentially copied over from previous bistro, should work. I see that there are some things missing for making it a true BLFA6 replacement, example timed turbo (attiny25 doesn't need it of course, so the opposite of your issue), and star configuration. I don't know if I'll get around to adding that or not, but I'm making a separated config file for a BLFA6_EMU build. Partially I wanted to start breaking out config files like this anyway, because it seems it will be useful for other various builds. I'm not sure how the size of bistro-nanjg13 compares to BLFA6 because the options are setup exactly comparably yet, but it's at least possible to get something working in under 1K.

deleted, momentarily confused. I saw OTC in blfa6 and forgot that you said you modified it specifically for not using that.

Local variables can be allocated on a stack frame, and then probably aren't really better than globals that need to be fetched from the RAM "heap". However, in my testing the compiler is pretty decent at keeping locals entirely in registers until you have too many of them. Then if they really are temp variables, there's no loading and saving them, so that saves some instructions.

This is the same reason why changing a global to a global register vairable can help. However, it reduces registers available for local use, so it can hurt too.

Looking at the A6 firmware now. Ok, I see, with so few modes and so few options, optimization is an entirely different story. It's just so simple and efficient to sort of hard code everything there as done. Probably many of my optimization ideas don't apply, and also the idea of including BLFA6 as a config option in bistro kind of looks hopeless. It's probably too much overhead to produce a relatively much simpler driver in so little space, which I guess is why TK didn't do it too.

So mine came in at 38 bytes. It seemed like getting this part right may be where some savings is:

inline uint8_t check_presses(){
uint8_t i=N_SAFE_BYTES-1;
while (i&&(fast_presses_array[i]==fast_presses_array[i-1])){
--i;
}
return !i; // if we got to 0, they're all equal

The compiler unrolled it being only three compares.

clear_presses() and inc_presses() are just simple for loops, so that's kind of all there is.

inline for inc and check but not for clear.

Anyway, it seems in HD this is presently only useful for the HD-biscotti build, but that has zero free bytes.

To me though it's better to have it stable and drop a strobe mode. Maybe I'll find 38 more bytes though. That's seeming pretty hard. I can imagine 20, and I can drop this to 3 bytes for the HD-biscotti build.

Because I started out with only a 2nd redundancy byte, I also checked to make sure they were <=15 as an extra failsafe. It appears that this was costing me more that I thought it would… around 14 bytes?!

inline uint8_t we_did_a_fast_press() { return (fast_presses == fast_presses2) && (fast_presses <= 15); }

If I remove that check (for all but the single-byte version) and convert them into array-style as you have done, I get these results:

No redundancy: 950 bytes (control program)
Using 2 bytes: 968 bytes (+18 bytes from control)
Using 3 bytes: 970 bytes (+20 bytes from control)
Using 4 bytes: 990 bytes (+40 bytes from control)

I’d call my +40 consistent with your +38. I’m not sure why going from 3 bytes to 4 costs and extra 20 bytes of code when going from 2 bytes to 3 was only an extra 2 bytes. Given that, I’ll probably stick with 3 fast_presses bytes… should be pretty safe with 3 bytes.

I also played around with the variable-length mode groups and got my count_modes function down small enough (only 6 bytes or so over static-length) that I decided to switch over to it. I don't know if this is any help to you, but I'll go ahead and share it. It doesn't account for hidden modes or reversal (I just have extra modes for reversed order), so you'd need to address that.

inline void count_modes() {
    uint8_t group = 0, mode, i, mc=0;
    uint8_t *dest = modes;
    const uint8_t *src = modegroups;
    for(i=0; i<sizeof(modegroups); i++) {
        mode = pgm_read_byte(src+i);
        // if we hit a 0, that means we're moving on to the next group
        if (mode==0) { group++; } 
        // else if we're in the right group, store the mode and increase the mode count
        else if (group == modegroup_number()) { *dest++ = mode; mc++; } 
    }
    num_modes = mc;
}

Yeah, my latest build strips things down some (not quite that much) in count modes when moon mode and reversal aren't used. I had to do that to get a HD-biscotti build to fit in 1024. It's only if all three of moon, reversal, and hidden aren't used that the pointer trick really saves much as far as I can tell. Else you still have to step over the mode group to make a copy, in varying degrees of complexity depending which are enabled.

Oh, never mind, I guess you always have to make a copy, it's not in real memory to start.

I dont understand how you guys do what you are doing but just wanted to say following with interest. Excellent work. :+1:

I like so I’m suscribed… :+1:
Chips stacking: flux(simple fluid smd flux) all legs and back pin on both(old and new chip), pre tin each of them with favorite tip and gentle touch of good solder(koester stannol or similar) on 350 C, super glue new to old guy(use the best sg you can find), solder back and then solder legs, a bit bending of legs helps and can be done with screwdriver but when good pre tining preparation is done you’ll not need to bend them. Maybe it sounds complicated but it ain’t and that should be 10-15minute work for 4 stacked chips.

I tried paste way but it is messy cause paste when burned leaves some nasty sticky fluid and I am always afraid that it can short something on the driver…

This is always interesting to see(done by Andi in 2011):

So gchart, I think you've got a point there.

So bistro counts in three steps (well not including the last two steps lol)

1) Find the start of group

2) Find the length of gruop

3) copy group

with variable mode lengths each one has a pgmreadbytes command in a loop or two.

With fixed modes 1 was just an assignment and with reverse modes 3 had to be separated from 2 anyway because you must know where the end is before you can reverse the copy. With no reverse or moon I've combined 2 and 3. Technically it may be possible to do that with moon and no reverse but it's probably ugly and a pain at least. I don't know. Working out that index madness in hd's big copy statement was a bit painful.

Ok but I can maybe always combine 1 and 2 and then maybe combine all three then if there's no reverse. Yes, this might save something.