Attiny25/45/85 FW Development Thread

Here's my attempt at regulation. I don't have time to test it on a light but I have tested the code on a PC and it appears to produce a decent ramp. It's 80 bytes on AVR as a function, probably a few less once inlined. Hopefully the comments are enough explanation but feel free to ask questions. Just don't expect too many answers before tomorrow.

The values I put in there for V_ZERO_AMP and V_FULL_PWM are placeholders, you'll need to figure out your own for a given driver and LED.

/* 
    This requires a linear voltage reading. So if the voltage divider is after 
    a diode, the diode drop must be added to the voltage readout (and voltage 
    constants below). 
V_ZERO_AMP is the voltage where the LED would produce 0A if the regulation 
curve was extended all the way to 0A. In practice, there will still be 
light there because the curve becomes very nonlinear at low currents. To 
get this value, project the part of the Vf/A curve where you want 
regulation to work all the way to 0A, in a straight line. Using one of 
djozz's awesome graphs makes this easy :)

V_FULL_PWM is the voltage below which there is no more regulation (ie. PWM 
is left untouched). 

The final PWM value is 
    in_PWM * (V_FULL_PWM - V_ZERO_AMP) / (Vcc - V_ZERO_AMP) 
when Vcc > V_FULL_PWM, otherwise it is unchanged (no regulation). 

*/
#define V_ZERO_AMP 135
#define V_FULL_PWM 200

#include <stdint.h>

/*
This does a * b / c, with the intermediate result being 16-bit to avoid
overflow. The result is still 8-bit so it could overflow if b > c.
*/
static
uint8_t u8_mul_u8_div_u8( uint8_t a, uint8_t b, uint8_t c )
{
uint16_t tmp = 0;
uint16_t wa = a;
uint8_t i = 8;
while( 1 == 1 )
{
if( (b & 1u) != 0 )
tmp += wa;
if( --i == 0 )
break;
b >>= 1;
wa <<= 1;
}
uint16_t wd = (((uint16_t)c) << 8) >> 1;
uint8_t result = 0;
i = 8;
while( 1 == 1 )
{
if( tmp >= wd )
{
tmp -= wd;
result |= 1;
}
if( --i == 0 )
break;
wd >>= 1;
result <<= 1;
}
return result;
}

/* Takes vcc reading and pwm value and returns "regulated" pwm. */
static
uint8_t regulate_fet( uint8_t vcc, uint8_t pwm )
{
if( vcc > V_FULL_PWM )
{
pwm = u8_mul_u8_div_u8(
pwm, (V_FULL_PWM - V_ZERO_AMP), (uint8_t)(vcc - V_ZERO_AMP) );
}
return pwm;
}

I don't get the resistance.

In a 100% FET mode you can't regulate it period. We're talking about having regulated middle modes. We already have that for the all 7135 mode but it just depends how many 7135s you have on how long that can stay in regulation, and when it goes out, so do all the modes under it above one 7135. You MUST at least take into account pwming all channels even in fet modes or you just won't get this right at all, but if you don't take into acount in one way or another the 7135 output, you'll also end up with modegroups that are a confusing out-of-order mess that depends on battery level. The thing that kept them in order was leaving the 7135s on full while the FET is on, but you just can't do that now, well not without even more work to sort it out. And then you might as well just do things right:

This is what makes sense:

#define ALL7135_MAXVF // the Vf expected at the current level provided by all 7135s

#define ONE7135_MAXVF // the Vf expected at the current level provided by one 7135s

target_vf=vf_targets[mode_idx];

while (1){

actual_voltage=get_voltage();

if(target_vf>actual_voltage) {// Set a target we can actually reach. Correct for voltage sag next time around.

target_vf=actual_voltage; // better yet would be to lock out a mode once the target_vf of the next lower mode is>= voltage

}

if (target_vf>ALL7135_MAXVF){ // More than 7135's can handle, use everything.

PWM=light_output(target_vf)/light_output(actual_voltage);

PWM_ALL_CHANNELS(PWM);

} else if (target_vf > ONE7135_MXVF){// Using all 7135s

// compare desired light to what we'll actually get at the lesser of this voltage or the max 7135 voltage

// Note if target_vf is set equal to ALL7135_MAXVF we'll still have a no PWM mode.

PWM=light_output(target_vf)/light_output(actual_voltage);

PWM_ALL7135s(PWM);

} else { // Using one 7135

.. ok using voltage down here in the weeds probably doesn't make much sense.

.. just translate these to fixed single PWM levels.

}

// loop to keep up with voltage sag and drain.

}

light_output is the normalized lumens expected at a particular Vf. We rarely see this curve actually, but we have vf vs current curves and current vs light curves so you can combine them and work it out. I've never seen it.

The ratios are the thing to be approximated and can probably be done by

255-(actual_voltage-target_vf)*LED_CAL

Instead of by division.

It seems that multiplication by a constant isn't very expensive. The optimizer works out a a fixed algorithm for it.

I think it's multiplication or division of two variables that is expensive.

The hard part here is just knowing what the Vf corresponding the current of your ALL7135s is.

That depends on how many 7135s, and both that and LED_CAL will depend on the LED in use.

If configured right this will keep all the modes in order and all regulated as long as possible.

edit: removed a redundant comparison in second conditional.

Most drivers have a max of 8 regulators. Which is 2.8amps. In bistro there are four levels higher than this number. They add a bit of fet duty cycle for each. We are wanting to keep these leds under 5-6amps for a single and 10-12amps for a triple. Never will the fet be on when regulated under 2.8amps. So all regulation needs to take place above this number which is only the influence of the fet. If we were to say that we only want a max amps of 2.8, then the fet should be 0 and the regulators left alone. These new leds might stay regulated at 2.8amps all the way down to 3.3-3.5 battery voltage. So there is no situation where the regulators need to be regulated.

So say I want a nichia 219c to run at 5amps. The regulators will bring it to 2.8 then I would wat the fet to pick up the slack. The fet will be needed less when the battery is full and more when it’s empty. All modes under 2.8 will remain unchanged. All modes above 2.8 will be powered by 2.8+FET*%

When the battery is really low all regulators and the fet will be at 100% to create as little resistance as possible and give the led whatever the battery can give. At this point there will be no difference between the few highest modes but this is to be expected.

Right?

It's not the important point, but yes there are situations where it's useful to regulate the 7135's even without the FETS. A 50% all 7135 mode will drop out of regulation once the battery is low enough, and that happens to be the same level where 100% all 7135 mode drops out, not later, and it doesn't need to, because it's still only 50% of what you've got. The PWM'ed 7135 modes are NOT maximally regulated. You can keep it in regulation much longer. So it's just not true that there is no useful situation for that.

The bigger issue though, is what do you mean by "leave the 7135s alone" You mean leave them off or leave them as they are now now?

Ok.. addressed your comment on that more directly two posts down. Basically leave them on flat and worry about their contribution to the power curve or you PWM them together with the FET and worry about mode ordering. Either way you have to take their output into account in the math.

Fixed confusion in second sentence above.

This is the thing. What is 2.8+FET%? This is a duty cycle. When the fet is on the 7135 doesn't matter. The light is 100% on. When the fet is off, you're at 7135 power. So this means 50%DF*100%LIGHT + 50%DF*2.8amps worth of light.

Ok, but yeah, we can probably deal with that too in principle. I think the calculation is, well nobody has written it out yet. I'll play with it. You're still going to have to account for the 7135 output though. It's not like you can just ignore it. There is no approach where you get to just ignore it.

Flint I think you are overthinking it a bit.

In the latest 3 channel drivers there are very few mode groups that even PWM the 7135’s at all, they are pretty much always at 100% except for moon and low, which would not be effected until th battery is so low it does not matter.

The end all point is that the 7135’s will regulate the current until the voltage drops to a point where keeping regulation longer is not really an issue worth worrying about unless it takes up very little extra space and can be disabled.

There is nothing wrong with having the ability to software regulate the 7135’s and for the new driver as I said it needs to be able to regulate multiple channels anyways.

Which since the test yesterday went ok I guess I can say a little about the new design, it is an op-amp based design, basically think open source LD-3. In this case it will not need any software regulation for the op-amp channel (it will for the others) as the opamp will take care of that internally.

So basically what I am getting at is that the FET (and other channels with the same setup) are what we need to worry about, at the very least the channels need to be activated/addressed individually.

We are not looking for perfection here, we simply won’t get it. We are looking for a small code space option to improve the FET drivers and get the most out of the latest gen low Vf LED’s.

A very simple multiplier per .1v of voltage change is enough for what we need IMHO. Anything better that doesn’t take a lot of space is a great bonus.

I am not sure how it works exactly but it looks good.

So when you say Zero_amp, that would basically be a dead battery? It will increase the FET as voltage drops until it reaches 255pwm, regardless of the starting duty?

Can multiple channels be selected/use this?

How much space does this take up? It would also need to be selectable for which channels it effects, in the new driver it can not effect 1 of the channels or it will totally screw with how the light works. It also must be able to adjust the remaining channels “individually”, aka, if one of them is set to 0, it will need to stay at zero.

So basically I think the code outline I have is a good starting point regardless of these arguments. Gchart and I actually aren't far off in our lagnuage. He references the voltage where his curve hits 100% (what I call the target_vf) and the PWM level for 4.2V. Equivalently use target_vf and a slope (PWM drop per V). You could use 4.2V PWM level and slope, but you can get from one to other and it's all the same in the end.

The biggest question is how will things work switching from Vcc mode to normal mode. Right now we don't really have a voltage number. In normal mode the ADC could at least be proportional to voltage but in Vcc mode it's definitely not and the voltage we're generating now is too course for this (you don't want big step downs). The ADC is not even linear with voltage. I'd say fine, just use the inverted ADC number anyway and set adc_targets and PWM vs adc slopes. But then you'll need two sets of calibrations for these slopes and levels. And if you do want to regulate lower modes (I would) you'll need a third calibration for that since it will have to be done differently.

You do add significantly more non-linearities with this mixed mode approach. However you do guarantee that the FET modes won't cross below the ALL7135 modes, because the ALL7135's are always on full in them.

Cross posted. My biggest question is how does it deal with swtiching between ADC modes. The two ADC modes behave very differently.

I think it's pretty small. Maybe not 25 small. Not much is. The whole point of that approach is adjusts all the channels you want to use equally. But you can use or not whatever channels you want. I'd have to look at the driver to make it final of course, but I don't see a problem. Then again I have no idea what you've done that's so special about one channel. If this is anything related to your op-amp ideas I don't know why you'd care about fet regulation. Anyway, I don't know what I don't know. It's just a code sketch at the moment though. It could be selectable for many things. It also still hasn't dealt with the issue of switching betwen ADC modes yet, although it's a bit easier in the PWM-everything-in-use-equally approach than the leave-the-7135s-on-full-blast-and-just-PWM-the-FET approach, but still needs some calibration defined for both.

The zero amp voltage is more of a hypothetical figure, if you were to draw the Vf/A curve as a straight line. For example, using djozz’s 219C test it would be about 3V. It has an effect on the shape of the ramp after V_FULL_PWM.

And this works the other way around: it reduces PWM value when Vcc is above V_FULL_PWM. So you should be able to leave the modes mostly as they are now, pick V_FULL_PWM where you think the light is as bright as it should be and the code will try to prevent it getting brighter. For example, if you pick V_FULL_PWM of 3.8V, then a PWM value of 255 will remain 255 below 3.8V, might turn into 235 at 3.9V, 220 at 4.0V, 205 at 4.1V and 195 at 4.2V (these are just guesses but it does look something like that).

And yes, you just call the function on whatever channels you want to, right where the PWM value is set. In bistro, that means changing something like “PWM_LVL = pwm1;” to something closer to “PWM_LVL = regulate_fet( get_voltage(), pwm1 );”. Although the diode drop probably needs to be added to get_voltage() too.

Edit: I was tired when I wrote that code so the constants are pretty badly named. V_FULL_PWM would probably be better understood as V_REGULATION_CUTOFF or something similar. And perhaps V_ZERO_AMP as V_CURVE_ORIGIN or something else which doesn’t give any wrong ideas.

I don’t know the details but why keep multiple channels at all? If you’re operating the FET in linear mode (which I imagine you are if there’s an op-amp involved), it can do everything from the lowest low you can imagine to fully on as we currently have.

It is not that it is anything super special with the new driver, as super basic actually. In a nut shell moon will be controlled directly from the MCU and it will need to have voltage compensation on the PWM output. It will also have an FET channel that needs regulation for the same reasons we need it now.

What I have come to find with flashlights is that precision in light output is not all that important. Particularly in the high modes. Our eyes simply can’t register the change we would see. Heck 800 vs 1100 lumens is hardly noticeable by eye, you have to go back and forth quite a few times to figure it out if you don’t already know.

This is why I am just not worried about it being super precise, our eyes will not notice it anyways. I just hate thinking that there is another 30% duty left on the table for turbo as the voltage drops that is wasted for the entire life of the battery. Having the mid range FET modes for triples have some regulation is great as well.

The code is over my head but here is what should happen at the most basic level:

Increase PWM for selected channels (they can be controlled by the same multiplier if needed) by a (user adjustable) multiplier as voltage drops.

Anything past this is a bonus only needed if the space usage is worth it (or those features can be disabled if not needed).

The next most important thing I would say would be a further multiplier for the lower voltage ranges as those areas might need to be adjusted at a faster rate. It could be as simple as use X multiplier from 3.6-4.2V and use Y from 3v to 3.6V. The key is simple and space saving

As far as the 7135’s go, I am simply not worry about controlling them with software regulation. If it can do it with very little space used and can be disabled, then that is great although I find in the TA drivers that the mode spacing is quite good by simply turning the 7135’s on full blast after you get past moon and low.

If fixed it’s code is only 70 bytes then that is a much more feasible option IMHO, although like I said I don’t understand either one of ya’lls code. So I will leave it to the expert on how to do it.

The key is simple and small.

It boils down to heat, cost and space constraints. To get it to do everything with the op-amp would require very expensive components that are not available in small enough footprints to fit on a 17mm driver. Also according to DEL, to get a true moon mode out of the op-amp at all would be quite difficult.

The reason for the FET channel is that the op-amp and “regulated” mode can only dissipate so much heat, so you can not dissipate 5W in the driver, the driver will literally melt down (the negative wire desoldered itself from the FET today with only 3W of dissipation).

So once you reach the max that the driver can regulate / dissipate as heat you are stuck, you can’t go any higher.

So this is why the FET is PWM directly. This way it doesn’t overheat the driver but still allows for almost unlimited amounts of current.

It is a compromise but the best we can do with the constraints we have. If people were willing to spend $15-20 on the parts for the driver alone then other options could be pursued but that not a practical option for a group buy light. Doing it this way cuts the cost down drastically.

The real difference of this vs the TA drivers will be space savings, you can easily use retaining rings on all your lights. Adjustable output with no PWM in place of the 7135’s and it will be able to work with 3v LED’s all the way up to 12V LED’s without having to change anything but a resistor or 2. So it will power things like the XHP35 without a hitch (which is what it was designed for actually).

According to djozz’s test, 3V will be about 1A of current to a 219C and 400 lumens?

So this code will not increase the PWM as voltage drops? Only decrease it as the voltage rises?

Either way I suppose some modes will have to be adjusted but ideally only the last few of the ramp table would need to be adjusted (those that limit the duty to keep current in check).

I also want to say thank you very much to all of you for working on this. I am a bit of a perfectionist and like to understand how things work, not just that they work, this can cause me to come across as ungrateful or unhappy when I am actually exactly the opposite.

I just like to understand things and sometimes that requires breaking them down a a few levels for it to sink in.

Ah sorry, I thought the op-amp was used to amplify a sense resistor or something similar. It sounds like it’s instead used as a better 7135. I don’t know much about op-amps so I’ll leave it at that and wait until the whole thing is released. I wish I had free time to design my own driver, it certainly seems fun.

Maybe, does not really matter. That value is only to define a straight line which is used to approximate the graph in the area where regulation happens (ie. in the 3A+ range, presumably). What the graph looks like below the regulation threshold is unimportant as I don’t do anything about it.

Yes but it really amounts to roughly the same thing when you think about it. The only difference is what PWM values you have to start with and how you calibrate the whole thing. Either your modes/ramp have lower PWM values which get increased by regulation or they have the higher PWM values which get decreased by regulation.