Success! Thermally regulated linear driver

Nice. My problem with noinit as it is in bistro now, is that it assumes any valid value is.. valid. I tested a single randomly chosen slot in ram to see what resets to after decay, and it always reset to the same value, I think it was 72, or whatever, but not 0 or 255. I assume that's just how those particular 8 bits like to settle and I suspect a different 8 bits would settle to a different value. So on bistro anything less than I think 15 is considered valid (valid number of fast presses to get into menu), but nothing says that the settling value won't be 9 on a particular byte on a particular chip. It's not even that unlikely, 15/255 chance. There's a note in the bistro code about it being questionably reliable and I guess this is why.

The solution... is to use 4 bytes. There's a 1 in 2^24 (almost 17 million) chance of all 4 bytes being equal assuming they're independently random (needs a bit more testing, but kind of seems that way). That doesn't mean 2^24 times you turn it off, more likely one out of every 2^24 lights. So you check that all four bytes are equal, then you say it has not decayed and check the value. If they're not all equal, it has decayed and it's a long press. It's a little more code space, but not so much.

I’ve been bitten by to decay lottery on a driver or two. I’ve attempted to address it in a different manner using two separate one-byte variables: one for counting fast presses, and another one for decay detection. I figure that getting a byte that always decays to 0 is pretty unlikely. And I only check the fast presses variable if the decay detection variable is still 0.

well you've reduced the problem to one in 255, but only sort of. What are the chances your test byte has a bit decay first? What are the chances the data byte does? 50/50. That may be more try by try related than the other random draw (hard to say). These bytes don't decay fast. I don't think the odds of this biting are so low. Might as well make it 4 bytes and kill the problem.

As for single channel versions of things, I've tried to make HD very easily configurable for channel setup. It should be a few #defines to uncomment to drop into straight into this (as soon as I go find out the nanjg layout I can make a shortcut macro for it in about a minute; there's probably already one there, but it might not be right). However, I have not fixed the noinit issue. It is on the todo list, but what I have done is made plenty of extra space available for the few extra lines of code it will need.

I actually don't mind at all if HD gets accepted into "mainline". A lot of the point of it was to re-merge some of the different variants but I didn't want to be presumptive about it either so I renamed it. If we have one version that can be used anywhere with just a #define layout nanjg (this was toykeeper's concept, it just got fractured over time) then it's easier to keep all the upgrades together. If features can be removed or included with defines then nobody is forced to use a particular upgrade either... for the most part. I've also tried to tidy up some of that.

Anyway, I should follow your inspiration and get this all included.

I might try kicking it up to more bytes, it certainly can’t hurt if you’ve got the space. But an attiny13a can run short of that quickly.

1:255 odds would be correct if SRAM decayed evenly. And I have nothing saying it doesn’t. But in testing done by other members (here), bits appear to favor decaying to 1 around 70% of the time. With even a single byte, that would change the odds to be 1:15242 that a byte would favor decaying to 0.

Attiny13 hunh.. I thought you said you changed the chip to a 25. Anyway, it's not 1 in 255 even with even odds. You're missing my point. You're working with two bytes. One single bit will be the first to go. How long will it be in a state with only one bit wrong? How often will you click on during that time? Probably sometimes. You're relying on the fact that the first bit to go bad will be in the check byte and not the data byte. But there's 50% odds it will be the other way around. So that's 50% odds that at least sometimes when you click, you'll think the data is fine, but it isn't.

Well, yes… This thread is about using an attiny25 with noinit. But I’d wager that the other 99.999% of drivers currently in production that are using the noinit trick have an attiny13a on board.

And I think I get what you’re saying, it’s just a different approach than what I mentioned. Different isn’t always wrong. Your proposed method involves copying the fast presses counter to not one, but four separate bytes. First you check to make sure they’re all the same, then you can safely assume the data they contain can be used for a counter. Is that pretty close to what you’re describing?

Ok, I get your point about the 13. Yeah, I guess not many people are replacing 13's with 25's on nanjg. Anyway, yes that's it. And I agree it will take some significant bytes of code in the context of an attiny13. Even for the 25 version it was significant, but we've freed spaced and just not enabling one of the other methods (OTC or OTSM) now makes way more than enough space free to implement it without losing anything.

It’s definitely a good sounding method. Do you recall about how much space it takes up? For space-constrained applications, even doing that method with two bytes sounds far better than what Biscotti has.

I haven't actually implemented it yet. Just on my todo list.

I did work out that the check can look like if (a==b&c&d)

... but that's about as far as I got and actually while that looks tidy it probably doesn't optimize to much if any shorter than more verbose statements.

One trick I used to save some space is to declare a few key variables as global register variables. This avoids all the in LDS STS instructions for those data. If you do it too much (more than a few probably) it can result in more juggling instead of less though. I believe these are always noinit but I have no idea if they'd persist at all like ram variables.

As for two bytes, yeah, that's 1 in 2^8 so 255 for equal weighted bits. I started thinking this through with your idea first actually, then thought this other two byte trick, then figured, well, that makes it better but it will still be an actual problem so it needs 3 and might as well make it 4 (three would still hit someone someday). But three could be good for attiny13 if it will fit.

ah.. just realized that way of doing the check isn't as clever as it is cute. It's possible for that to pass with some not so hard to produce combinations of non-equal values, so it significantly weakens the check. Just have to do out long probably : if (a==b && b==c && c==d) Your claim of a weighted coin probably also weakens it.

I'm not quite sure what the main problem is, but if you're using an Attiny25, why not just use the EEPROM? This in conjunction with the RAM trick or an OTC would be very useful :)

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.