BabyO, single LiPo cell, fuse settings revisited

I have seen posts in the past about using a single LiPo battery to power a BabyO based bot and have myself made one awhile back but it has been a while and I have a few questions.

First I am using a first generation BabyO board with the old motor driver.

I have seen comments on the forum of changing the clock frequency from 20mhz to say 10 by changing the declaration in the code which in turn might save battery power. I also read a post and was told to change to an internal clock setting - specifically the internal default fuse setting i am driving two planetary geared pager motors to control a small chassis that is using o-rings as the tread between the wheels to act like a tank tread.

Are there benefits to changing to an internal clock over external declaration changes? risks? Is it better to define the external frequency to be slower. I don’t need a lot of processing - just trying to get the most out of a single 3.7V LiPo as I know it can be done.

Any thoughts on other settings or if that is the best fuse setting are appreciated. I don’t want to risk locking up the board and I am sure there are trade offs - just looking for some recommendations.

Thanks,
Mike

If you want to follow the datasheet specification (never a bad idea), if your ATMega168 is going to be powered by less than 4.5V, it should be running off of a 10MHz or slower clock at startup, before your code even starts running. The clock source will need to be selected and scaled with fuses.

If you don’t want to replace the external 20MHz resonator on your Baby O, you can set the “divide clock by 8 internally” fuse to run at 2.5MHz, or switch over to the internal 8MHz oscillator (or do both, to run at 1MHz).

-Adam

Hello.

First, you can’t change the frequency of the external clock without physically replacing it. It runs at 20 MHz, and that’s all it will run at. The problem with 20MHz at a lower supply voltage isn’t power; rather, the chip isn’t guaranteed to work correctly at that voltage and speed. (You can check the datasheet to see which speeds work at which voltages.) So, given that you need to lower the frequency, the easiest thing (I think) is to switch to the internal oscillator, which runs at 8 MHz. You’ll have to do that with the fuse bits, and if you do it out of AVR studio, I think it’s not that risky (I think there’s just one option for internal oscillator).

As for the changing the clock speed in software at run time, I don’t have any experience with that, but I suspect that it’s not necessarily legit since the processor would try to run at the higher frequency until your code got executed, and that higher-frequency operation is what might fail. I don’t think it’s risky in the sense that you could brick your microcontroller, but it’s annoying trying to debug code if you can’t trust that it’s being executed correctly. But, if that code happens right at the beginning of your program, I guess you would know right away if that part succeeded, and after that, you should be okay.

- Jan

OK thanks - I changed any reference to the frequency in the code and selected the internal fuse setting that was labeled (default) for 8mhz. One additional thought would be to use a boost circuit that would increase the battery output to 5V. I have built a few of these circuits, but I am not sure what the drain would be and how fast the battery output might decrease. Is there any sample code of reading the battery level - I know it involves reading the internal voltage and comparing. If there are any code examples - that would be really helpful.

Thanks,
Mike

It’s probably a waste to boost everything (including the motor supply); is the 8MHz turning out to be too slow? For reading the battery voltage, you’ll need some kind of reference. Usually, it’s the regulated 5V, but now, you’ll be running on less than that, so that makes things difficult. You could connect some reference to one of the analog inputs, and it should be fairly straightforward to figure out the relationship between the reading you get there and the supply voltage.

- Jan

Ok - good to know. I think it is performing fine - just wanted to cover all my bases. I got the following tip related to monitoring voltage from a forum member, but would really appreciate any examples of how to turn this into code - I have never really written anything from scratch and I am not sure where to start. Are there any examples of battery monitoring code out there?

Here is his recommendation on a project he had:

If I remember right, I used the internal 1.1V reference to determine the battery voltage. It works like this:
• Connect the battery (main input supply) to V_ref
• In 8 bit mode the calculation for reading a voltage is (V_in/V_ref)*256=(A2D_Reading)
• When you read a known voltage, like the internal 1.1V reference, you can rearrange the equation to solve for V_ref which is your battery voltage. V_ref=281/A2D_Reading
• As long as you use ratiometric analog sensors (which always give you the same ratio of input to output voltage for a given sensed value, like a CDS cell voltage divider) it won’t matter that V_ref changes

I just am not sure how to convert what he said into actual code to test… any examples are hugely appreciated and I can go from there - hopefully!

Thanks,

Mike

That’s basically what I said. What part don’t you know how to do? There are plenty of examples of reading an A/D input, and that’s all you need to do.

- Jan

Ok - well then I am on the same page, but what I guess I was asking for from anyone is a sample of any code with the correct syntax that might be used as a test bed and then incorporated into my main program. Something like read the battery voltage and at some point - blink an LED to indicate that it is low then I could replace the LED function with another action later. I have used other code in the past, but never from scratch and only tweaked existing code. So I will certainly search for code that reads A/D, but if it would be possible to get a section of code to read the voltage and compare to that internal number, I would be very greatful. I realize that might be a lot to ask, but I am hoping someone might have some code already that could be shared.

Thanks in advance,
Mike

Hello.

This forum has a number of ATmega168 ADC code examples, and many of our ATmega168-based products have such code examples under their resources tabs. Using the internal 1.1V as a voltage reference is a very minor tweak to such code, and the ADC section of the ATmega168 datasheet should make the required changes clear. If you have specific questions about what the datasheet says, I’d be happy to answer them.

- Ben

Thanks - I will search again and see what I can find.

I have been researching various code choices and was communicating with Jim Remington who pointed out this issue, which I had not noticed:

Upon a closer look at the atmega168 documentation (page 249), you can’t use the internal analog reference if the AREF pin is connected to Vcc. According to the Baby-O schematic, that is the case. So, you will have to cut a trace on the circuit board and may also have to add a capacitor to the AREF pin.

Can you recommend the best way to achieve this modification to the board or if it is possible?

As a recap - I am using a 3.7V LiPO and want to measure the voltage and when below a certain value, the LED would blink. I have the settings to change the ADMUX, but now I am not sure about this issue.

I assume I can use ADC6 to connect the voltage divider?

Thanks,
Mike

I haven’t tried this myself yet (hectic at work right now, as evidenced by the fact that I’m still at work), but I don’t think you need to cut anything on your Baby O.

My understanding is that you can leave Vcc (your LiPo voltage) connected to AREF, and set the ADC to measure the 1.1V internal reference voltage by setting ADMUX=0b00001110 (from table 21-3 on page 255 of the datasheet). It’s a little backwards from the normal way you use an ADC, in that your reference voltage is unknown but the voltage you’re measuring is set.

The reading would the ratio of 1.1V over your battery voltage expressed as a ten-bit number:

Reading=10241.1V/Vbatt
so
Vbatt=1024
1.1V/Reading

Does that do it? I’ll give it a try when I get a chance. If it does, you don’t even need a voltage-divider!

-Adam

Adam,

Thanks for responding, That sounds like a better plan. I will take a look at what you suggested and would be very interested in your testing.

When looking at page 254 in the ATmega168 doc, would I not need to set REFS1 and REFS0 equal to 1
thus ADMUX=0b11001110? if I do not need a voltage divider then I guess I would not need anything connected to ADC6? Would you mind sharing any test code you come up with?

Thanks,
Mike

If you’re not making any hardware modifications to your Baby O you definitely want to leave AREF as the ADC Voltage reference (REFS1=0, REFS0=0). From section 21.5.2 on page 249:

It is a little concerning that they phrase the AREF option as having “Internal Vref turned off”. I hope what they actually mean is internal Vref disconnected. I’m hopeful that what hey actually mean is internal Vref disconnected, but still on, since they let you measure the internal Vref with the ADC. It would be sort of pointless if you could only measure it if it was also your reference voltage, since that would always get you a reading of 1024!

Anyway, the best way to figure it out is to try, I should get around to it one of these days.

-Adam

Thanks - that does make sense. I will try to test it out as well. When you are not burning the midnight oil, I would be interested in your results as well.

Mike

I had a little down time while making a drive image, and it turns out this technique works:

#include <avr/io.h>

int main(){
	int ADCGrab,VBatt;

	ADCSRA|=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
	//Enable ADC, system clock/128

	ADMUX=0b00001110;//AREF as reference, Internal 1.1V as sample

	unsigned char i;//general counter

	while(1){
		ADCGrab=0;
		for(i=0;i<8;i++){
			ADCSRA|=(1<<ADSC);//start conversion
			while(!(ADCSRA&(1<<ADIF)));//wait for conversion to finish
			ADCGrab+=ADC;//add the conversion result, clears the ADIF flag
		}

		ADCGrab>>=3;//divide by 8 for average reading
		VBatt=((long int)1024*(long int)1100)/ADCGrab;//calculate VBatt in millivolts
	}

	return 0;
}

On my original Orangutan Mega168 (running at 20MHz, just like your Baby O) I get an output of VBatt=5143 for the regulated 5V. Not spot-on, but darn close.

-Adam

That is exactly what I was looking for. Now I can add the code to control the LED or other behavior.

Thanks, Mike