Hope things are going great for you!

So apparently the  PID regulated current source using a switching regulator is a pretty popular thing, something that is searched for online quite often, at least that is what the blog stats indicate.

In this post I will be taking things one step further, I will be discussing how and why I have ported the design to an ATtiny85 and most importantly the improvements I have made to minimize the steady state error to an almost zero. In case you haven’t been following I would recommend you to go through the two article I have published earlier leading up to this.

Arduino PID current source

Improving the PID code

For those of you who have been following and had the liberty to work with a PID controller would know very well that the time interval between each sample is very important as our integral and derivative results depend on it and if the time interval is known and fixed then that simplifies the PID calculations for the controller chip. With this as an established fact we can move forward on why this port was important.

Once again I would like to remind you that this is leading up the the universal programmable NiMh battery charger that I would like to  make.

Why Port The Design Over To An ATtiny85?

The approach that I am working with isn’t using a set defined time interval that the chip knows about instead I am cycling through the PID calculations without any delay() commands and letting the micro controller run free at the clock frequency set, this does in a way make the time interval known and constant as each instructions takes the same amount of cycles to get executed so every next instruction in the loop is reached at after a fixed amount of cycles, so in a way the controller doesn’t know about the time interval but still does, if that makes sense. This is a very important point and will help me to answer why I decided to port my design to an ATtiny85 from an Arduino UNO (ATmega328p) in the first place.

As mentioned these blog posts are a build up to a project I have taken up to build a universal programmable NiMh battery charger, earlier I had plans to use the ATmega328P as the only controller that would regulate the current using a PID loop, I was planning for the same single chip to present the user with an LCD interface where a current would be set before a charging is started and during the charge cycle the same chip would read the battery voltage and incorporate within the code an algorithm to terminate the charging using a -dV charge termination method, pretty neat huh? but! all the extra functionality needs more lines of code to be added along with the PID loop which changes the sampling time interval of the PID controller hence ruining all the effort I put into tuning the PID (which largely remains a mystery to this day), but that isn’t it, due to the nature of the LM2576 switching regulator the sampling time can’t be delayed or the current values will be all over the place and there will remain no point in having a closed loop control, you see current varies almost instantly so the sampling has to be fast to account for any rapid changes.

This was enough reason to have a separate dedicated PID block that would eventually communicate with the master controller using an I2C bus and will go about doing its work once it has received a set point from the master (which will be the ATmega328P in my case).

Since I wasn’t ready to throw in another dedicated ATmega328P for the closed loop control therefore I opted for a chip like the tiny85, the final design ends up using all the pins so that is an efficient utilization of resources I would say.

Making The New Controller Efficient And Accurate

It wouldn’t have been justifiable had I just replaced the Arduino UNO with the ATtiny85 just to take over its functionality, The first and even the second iteration of the PID controller that I had built had flaws and even this, my third iteration with all the improvements it promises introduces new issues that need to be addressed, but I am getting there slowly, this time around I have made improvements in the following two areas,

1- Improved the current feedback system to increase overall controller accuracy, completely eliminating the steady state error which became more and more pronounced with higher set points

2- Decided to move away from the internal 1.1 Volt ADC voltage reference and use the internal 2.56 voltage reference available on the ATtiny85 (however resorted to an external 2.5 V reference due to issues that will be discussed)

3- Minor tweaks in the code to get stability

We’ll look into each of these aspects briefly and discuss what I have learned with my experience and it just might help some lonely soul out there who is probably as frustrated as I was at one to hopefully find a solution.

Improving The Current Feedback Circuit

Use better OP-AMPS! when dealing with precision applications like this one always go with one with the least input offset voltage value! Yes I can’t stress this point enough as I have had nightmares with an LM324 and having practically no exposure to working with op-amps in the field before I was really scratching and hitting my head against the wall when finally people up at the arduino forum pointed this out to me, moving away from the LM324 I looked for an op-amp with a respectable input offset value and was able to get an AD820 which does the job reasonably well.

I will try to explain what input offset voltage is for those of you who might be wondering, the basic operation can be summed up in a sentence, in a negative feedback configuration the output of the op-amp must maintain a voltage such that both the -ve and +ve inputs to the op-amp are at the same voltage. Sadly we live in the real world and there are imperfections during the manufacturing which doesn’t let this happen, however the maximum possible difference between the +ve and -ve inputs to an opamp is defined in the datasheet so one can choose an appropriate device that can serve the purpose, this difference in voltage is known as the input offset voltage.

The input offset voltage of an LM324 is a maximum of 7 mV

For an LM324 having an input offset of 7mV will cause a big error in the final achieved set point since we are using a 0.1 ohm sense resistor as feedback for the op-amp the voltages we are dealing with are already in milli volts so having a deviation of 7 mV can really ruin the day for us, where as an AD820 on the contrary has input offset voltage of around 0.7 mV which is still manageable.

Second most important point when setting up a precision gain amplifier is to always use precision resistors! yes this needs to stressed upon as well, I can’t explain how much time I spent trying to tweak my PID code (courtesy to very little experience with circuit designing) only to narrow down the problem to the 5% tolerance resistors I was using for my feedback loop. Also for the current sense 0.1 ohm should be a 1% tolerance or better even less, I had to ultimately use 10, 1 ohm 1% resistors in parallel since I couldn’t find a 0.1 ohm with a 1% tolerance, can you believe it?!

At this point lets just look at the new circuit diagram we are working with.

The new circuit diagram based on the ATtiny85, (I know people can’t take more of my hand drawn schematics)

The biggest change this time around is in the hardware, the PID code in it’s basic form works well if the gains are of the right order, but that doesn’t mean the PID constants that worked for the Arduino UNO worked with the ATtiny85, it took a lot of trial and error before I arrived at the values for the new gains, again I feel like you are never completely happy so tweak the parameters as you please and choose the ones that work the best for you.

To give an idea of the performance here’s a picture of the PID controller set for a 1.7 Amp set point charging a  9.6 volt NiMh battery pack.

I know, I need to clean up my space

A significant improvement, the steady state error has been reduced to almost zero in this case, those who have been keeping up would remember that the earlier iterations faced an issue where the steady state error increased as we increased the set point, which has been completely eliminated this time around. Another important point to be careful of is that since I am working with two different circuits one of the PID controller and other one of the LM2576 based power part therefore the two grounds have to be tied together, always make sure the ground on the power part should be tapped from a point near to where the 0.1 ohm sense resistor connects to the ground this is crucial in getting the final result.

Moving Over To The 2.56 Volt Internal Reference

The prime reason why I switched over to the internal 2.56V reference can be understood once you look at this chart

Set points passed on to the ATtiny85 with 1.1 V and 2.56 V internal references

The ADC can never register decimal values so passing on set points with decimal values makes no sense and it will just compromise accuracy, so 2.56 Volt internal reference made perfect sense, right?….. Wrong! you see the internal reference of the ATtiny85 is pretty bad and according to the spec sheet can vary between 2.3V to 2.7V (if I remember the range correctly, for a confirmation you might want to refer to the data sheet), so to sum it up using the internal reference in precision applications like this is a pretty bad idea, so I had to resort to an external precision reference and for that I am using an LM336 shunt regulator which isn’t the best but gives a stable voltage. May be I can later on replace it with 2.56 precision external reference but so far it’s doing a pretty reasonable job.

However one important lesson learned here is that the internal reference should never be trusted especially for the ATtiny85, using the external error however does introduce one more problem, I am now utilizing the I2C data pin, I will just have to compensate for it in code at a later stage where I will initially use the pin for communication and receiving the set point and later one that pin will then be used for the internal reference, I am not sure if it will work though, great!

The Code

The code is largely the same, except for the inclusion of new gains specific for the ATtiny85, to further avoid integral windup I am adding another condition in the PID loop which completely disables the integral part if a zero current condition is detected, it prevent an integral windup in case the current drops to zero in the event the power circuit turns off while the controller is in operation.

Here it is very important to mention that I am using the internal 16 Mhz oscillator on the ATtiny85, the performance will not be the same or might degrade completely if any other clock is used.

Also make sure to upgrade your IDE to the latest version 1.6.12 and use the attiny core by David A. Mellis as the new cores support the ADC reference and saves a lot of hassle.

int ON = 3;
int FB = 1;
int Bias;
float Output;
float Actual, lastError = 0.0, Error = 0.0, Derivative = 0.0, Integral = 0.0;
float Amp = 0.0;
float Kp, Ki, Kd;
float setPOINT = 0.0;
void setup()
float num = 0.0;
pinMode(ON,OUTPUT); // ON/OFF signal for LM2576
pinMode(FB, OUTPUT); //PWM for LM2576 Feedback
digitalWrite(ON, HIGH);
Amp = 1.7;
setPOINT = Amp*1024; // with the amplification factor included
setPOINT = setPOINT/2.476;
Kp = 0.023;
Ki = 0.0005;
Kd = 0.0002;
if(Amp == 0.1)
Bias = 67;
Bias = 68;


void loop()
Actual = analogRead(A2);
Error = setPOINT – Actual;
Integral = Integral + Error;
if(Actual <= 15) //Forces the Integral to Zero when current below a certain value { Integral = 0; } if(Integral > 300000)//Limits the integral to prevent Integral windup
Integral = 300000;
if(Integral < -300000) { Integral = -300000; } Derivative = lastError – Error; Output = Bias – (Kp*Error + Ki*Integral + Kd*Derivative); if(Output > 255) //Limits the output to 5 volts maximum
Output = 255;
if(Output < 0)
Output = 10;
analogWrite(FB, Output);
lastError = Error;

Temperature Dependency Of The Achieved Current Value

As current passes through the ten 1 ohm parallel combination of sense resistors they tend to heat up increasing their resistance, which causes the achieved current to decrease from the desired set point by a few milli amps, also since the current sense resistors are installed quite near to the heat sink on the LM2576 therefore it’s possible that the resistors are absorbing some of the heat from the heat sink that is close by,

Current sense resistors installed near the heat sink

Introducing a 12 volt fan into the mix helps keep the resistors cool and for the controller to achieve the set point, well you solve one problem only to get into another. I wonder if there is anyway to eliminate the temperature dependency? Might work on it at a later stage, I think I might be better of with a precision shunt resistor made particularly for current sensing, components are hard to find here so it will be some time before I get a suitable replacement.

Final Words

Finally here’s a video of the PID controller programmed for a set point of 1.75 Amps, it wasn’t designed to regulate current up to the second decimal point but since it is working better than I had anticipated so I thought I’d try this just for the fun of it,

Some pictures of the final PID controller circuit  on a perf-board

ATtiny85 PID controller
Solder traces at the back of the PID board

I think I can finally give the PID chapter a rest now for a while and work on other aspects of my programmable charger, the PID has taken a lot of time but the results are finally at a stage where I wanted them, I might do a bit more testing as time goes on and might think up of some way to compensate for the temperature dependency of the design.

If you’ve found this article useful please share and like my blog post, it’d be great!


4 thoughts on “Improving and Porting the PID Controlled Current Source Design Over to an ATtiny85

    1. Thanks for your interest blogparassitaaldo, you are right I could have used a mosfet or a self made buck converter to do the job with tweaking the code a little and that would have been easier, the LM2576 is being fed an analog voltage (pwm through a low pass filter) at its feedback pin by the attiny85 in order to drive the current through the load, when you need more current the voltage at the feedback pin drops below 1.2 volts when the value is reached the lm2576 needs to tapped to hold that state by providing a voltage of 1.2 volts at the feedback, similarly if the current is high than whats required a voltage of greater than 1.2 volts is applied at the feedback and the current reduces and when the value is reached you have to tap it again really quickly, believe me it is a mess to control this chip, so much that at one point i wanted to move away to a simpler solution but the lm2576 wasn’t a calculated design decision to begin with it was more about working with what was available and developing a control scheme (in this case the PID) to achieve the desired result, so there has been some built up coming to this but I am always open to suggestions.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s