ATtiny20 & measuring Vcc

Go To Last Post
79 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I found some posts about using the ADC to measure Vcc in battery operated projects rather than using an ADC input pin. I don't have a debugger so to check the code I use the read value as a delay and output a signal on a pin which I can measure the pulse width. I'm not getting a varying pulse width with this code so I've done something wrong and I can't seem to find out what's wrong.

 

Here's the routine to read Vcc:

uint8_t readVcc() {
	// Read 1.1V reference against AVcc
	// set the reference to Vcc and the measurement to the internal 1.1V reference
	ADMUX =  _BV(MUX3) | _BV(MUX0);

	// Set the prescaler to clock/128 & enable ADC
	ADCSRA |= (1 << ADPS1) | (1 << ADPS0) | (1 << ADEN);

	//delay(2); // Wait for Vref to settle
	ADCSRA |= _BV(ADSC); // Start conversion

	// Wait for it to finish - blocking
	while (ADCSRA & (1 << ADSC));

	uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
	uint8_t high = ADCH; // unlocks both

	uint16_t adc = (high<<8) | low;

	// Compute a fixed point with 1 decimal place (i.e. 5v= 50)
	//
	// Vcc   =  (1.1v * 1024) / ADC
	// Vcc10 = ((1.1v * 1024) / ADC ) * 10				->convert to 1 decimal fixed point
	// Vcc10 = ((11   * 1024) / ADC )
	uint8_t vccx10 = (uint8_t) (11 * 1024) / adc; // Calculate Vcc

	/*	
		Note that the ADC will not automatically be turned off when entering other sleep modes than Idle
		mode and ADC Noise Reduction mode. The user is advised to write zero to ADEN before entering such
		sleep modes to avoid excessive power consumption.
	*/
	
	ADCSRA &= ~_BV( ADEN );			// Disable ADC to save power

	return (vccx10); // Vcc times 10
}

and here's my while loop inside main:

while (1)
	{

		if (get_key_short( 1<<KEY1 )){
			LED_RED_SWAP;
		}

		if (get_key_long( 1<<KEY1 )){
			LED_GREEN_SWAP;
		}

		if (readVcc() >= 37)
		{
		LED_RED_OFF;
		LED_GREEN_ON;
		} 
		else
		{
		LED_GREEN_OFF;
		LED_RED_ON;
		}

		PORTA ^= 1<<PINA6; //test pin
		for (int i=1;  i < readVcc(); i++)
		{
			_delay_us(1);
		}
		PORTA ^= 1<<PINA6; //test pin
				
	}// End while

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Side note: Just to point out that most C compilers define a 16bit wide "ADC" so you don't have to read ADCL/ADCH separately and then combine.

 

Thus:

	uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
	uint8_t high = ADCH; // unlocks both

	uint16_t adc = (high<<8) | low;

	// Compute a fixed point with 1 decimal place (i.e. 5v= 50)
	//
	// Vcc   =  (1.1v * 1024) / ADC
	// Vcc10 = ((1.1v * 1024) / ADC ) * 10				->convert to 1 decimal fixed point
	// Vcc10 = ((11   * 1024) / ADC )
	uint8_t vccx10 = (uint8_t) (11 * 1024) / adc; // Calculate Vcc

could be:

	// Compute a fixed point with 1 decimal place (i.e. 5v= 50)
	//
	// Vcc   =  (1.1v * 1024) / ADC
	// Vcc10 = ((1.1v * 1024) / ADC ) * 10				->convert to 1 decimal fixed point
	// Vcc10 = ((11   * 1024) / ADC )
	uint8_t vccx10 = (uint8_t) (11 * 1024) / ADC; // Calculate Vcc

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PS I would have to look this up but what is the order of precedence on a type cast?:

uint8_t vccx10 = (uint8_t) (11 * 1024) / ADC;

Does that cast (11 * 1024) down to uint8_t and then do the division or is the cast applied to the result of the division? Also, as the left of the equals is uint8_t won't there be an implicit truncation of the whole expression result anyway?

 

EDIT: OK so I did look it up (can never remember!) and this:

 

http://en.cppreference.com/w/c/l...

 

suggests a typecast has a higher order of precedence than arithmetic operators (2 versus 3) so I guess you want:

uint8_t vccx10 = (uint8_t) ((11 * 1024) / ADC);

PPS oh and 11 * 1024 is 0x2C00, cast down to uint8_t that's going to be 0x00 I guess.

Last Edited: Mon. Jun 26, 2017 - 02:47 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

GeorgeIoak wrote:
uint8_t vccx10 = (uint8_t) (11 * 1024) / adc; // Calculate Vcc

Now you have to look at the generated code, or become a C expert, or add another set of parentheses.

 

11*1024 is 11264 and fits into 16-bit arithmetic.  Probably a signed value FWIW.

 

Now, does the cast apply >>before<< or >>after<< the /adc.  I'll guess "before" which turns 11264 into 44.  The subsequent divide will in all likelihood end up with a value of 0.  And that will have your for() loop terminate right away?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
which turns 11264 into 44
Is my copy of the Windows calculator telling me porkies? It tells me 11264 is 0x2C00. How does one get 44 from that after truncation?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lol -- I "simply" divided the 11264 by 256 and got 44 -- as you did.  But my head turned that quotient into the remainder.

 

In any case I think the cast applies to the result of the first term but I'm not sure.  Easy enough to add another ( ) and skip the research.

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well as you guys know by now "this isn't my day job" so I do appreciate a little hand holding as I try to figure this stuff out! Normally this is where I would use the debugger to step through the code and see what is actually happening. I had an old AVRISP clone that I was happy to find that it was able to program the ATtiny20 in TPI mode. Do I have to get an ICE in order to do any actual debugging?

 

I did have a devil of a time getting this compile initially because I was experimenting with floats and different type casting.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can not debug a TPI chip. But since the ADC works just like any other AVR, why not use the same techniques?
e.g. set VREF to VCC and read the internal 1.1V Bandgap with the 10bit ADC
.
Develop and debug your programs on a JTAG or debugWIRE chip. Or even the Tiny817 UPDI chip e.g. XMINI-TINY817.
When debugged, rebuild and test for the Tiny20.
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

GeorgeIoak wrote:
Do I have to get an ICE in order to do any actual debugging?

Depends what you mean by "ICE" and "actual debugging".

 

For on-chip debug access, you do need a debug probe. These are commonly called "ICE" - as in "Atmel-ICE" - even though they are not truly ICE.

 

There is also the simulator - which requires no hardware at all.

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@clawson I kept reading that you had to read ADCL first, I guess that was before ADC was defined as 16-bit wide?

 

@theusch you were correct, I changed that line to 

uint8_t vccx10 = (uint8_t) ((11 * 1024) / adc); // Calculate Vcc

and I got the following results:

 

4.2V input yields a  151.4ms period

3.7V input yields a 133.7ms period

3.2V input yields a 116.2ms period

 

So the values are changing is a good step in the right direction but they don't seem to be Vcc x 10. I was expecting the periods to match Vcc or is my brain not working yet...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
For on-chip debug access, you do need a debug probe.
But as David says these "brain dead" chips don't have an OCD unit in the silicon (presumably part of the cost saving?). So you might buy yourself a shiny new Atmel-ICE but it's not going to do you much good if you choose to use these dreadful little chips.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

GeorgeIoak wrote:
but they don't seem to be Vcc x 10.
Just a quick reminder how for() loops work:

		for (int i=1;  i < readVcc(); i++)
		{
			_delay_us(1);
		}

Sure each iteration of this is going to call _delay_us(1) and give you something close to a 1us delay. But:

 

(a) the for loop stuff itself is going to take a finite time which, depending on the CPU clock speed could be in the realm of microseconds too.

 

(b) more importantly:

i < readVcc()

is going to be done on every iteration. I imagine readVcc() is going to be taking a LOT longer than the for() loop stuff or the _delay_us(1).

 

Might I suggest:

                int reading = readVcc();
		for (int i=1;  i < reading; i++)
		{
			_delay_us(1);
		}

The "<" comparison there is still going to "cost" but at least you won't be re-calling readVcc() on every iteration of the for() loop ;-)

 

(BTW why does "i" start at 1 not 0 ?)

 

Oh and if readVcc() really plans to return 0..50 to represent voltages up to 5.0V then why is it "int" (16 bit wide) when it only needs to be 8 bit wide? Remember this is a reduced resource micro - always use the thinnest types possible.

Last Edited: Mon. Jun 26, 2017 - 03:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

GeorgeIoak wrote:
So the values are changing is a good step in the right direction but they don't seem to be Vcc x 10. I was expecting the periods to match Vcc or is my brain not working yet...

I usually do the calculations from nominal on paper, and then have my "trip" points in ADC counts.

 

Note also that the internal bandgap has a tolerance, so I calibrate that.  I thought I gave you a link to a recent discussion on that.

https://www.avrfreaks.net/comment...

 

/*

BG V	1.2	1.1	1.0

VCC		ADC COUNTS
5		246	225	205

VCC		ADC COUNTS		Rev. G adjust to 3.3V Vcc during cal
3.3		372	341	310

3.2		384	352	320
3.1		396	363	330
3		409	375	341
2.9		423	388	353
2.8		438	402	365
2.7		455	417	379
2.6		472	433	393
2.5		491	450	409
2.4		512	469	426
2.3		534	489	445
2.2		558	512	465
2.1		585	536	487
2		614	563	512

2.0V is 2x alkaline in series, used for Vcc, at 1.0V/cell.

The batteries are well on the highway to hell, but should be good
for another 100 hours at 5mA.

...

And part of that link shows where I do the calculations "on paper" to develop a trip value using as simple arithmetic as I can...

 

			// Rev. g  Adjust the above calculation for a 3.3V calibration voltage.
			//	Nominal is 341 counts.
			//		341 * 1.5 => 511.5; close enough. ;)
//			worknum *= 3;
//			worknum /= 2;			// x1.5 => 511.5; nominal 2.2V trip
// REvise again for 2.3V trip -- motor doesn't start...
//	...can that for now -- increase PWM duty proportional to adc_batt to get a
//	nominal ~2V PWM
//	Do both -- 2.3V is ~490 counts.  x1.436.  Find a ratio...
//	341 * 13 / 9 => 492; close enough
			worknum *= 13;
			worknum /= 9;			// x1.44 => 492.5; nominal 2.3V trip

			if (worknum > adc_batt)
				{
				OUTPUT_GREEN = OUTPUT_ON;
				}
			else
				{
				OUTPUT_RED = OUTPUT_ON;
				}
			}

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Mon. Jun 26, 2017 - 03:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@awneil, yes, I was referring to the Atmel-ICE but it sounds like from what @david.prentice said my next limitation would be that since the ATtiny20 has a TPI interface I could not debug even if I had the Atmel-ICE.

 

I have not used the simulator. When I did a quick search I could find some basic instructions on how to use it. If you happen to know of a link I would appreciate it if you could point me in the right direction

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Looks like I keep missing posts before I reply but you guys have been great, thanks again. That was dumb on my part to run the ADC on each loop as well as starting at 1. I'll change those and see if I can get closer to my expectations.

 

I had uint16 because I wasn't sure if I needed/wanted to go out 1 more decimal point. I need to get this working and then add in the PWM for the LED light string so even with that I'm hoping I'll have enough room without having to be too creative in my "coding"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

GeorgeIoak wrote:
@awneil, yes, I was referring to the Atmel-ICE but it sounds like from what @david.prentice said my next limitation would be that since the ATtiny20 has a TPI interface I could not debug even if I had the Atmel-ICE.

Yes; you need an "ICE" (sic) to access any debug hardware on the chip - of course, if the chip has no debug hardware, there is nothing to access!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@clawson I changed the loop to your recommendation

int reading = readVcc();
		PORTA ^= 1<<PINA6; //test pin
		for (int i=0;  i < reading; i++)
		{
			_delay_us(1);
		}
		PORTA ^= 1<<PINA6; //test pin

but now the period isn't changing with Vcc like it did before. Could it be because I'm only taking 1 ADC reading and "you're supposed" to throw the first reading away?

 

@theusch thanks for the link, I don't think you provided it to me before but I could be wrong. As soon as I get this part of the code working I'll look into the calibration and add that in before moving on

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But that whole for() loop is, itself, within a while(1) so it should be run over and over again - after the first time through you will already have effectively discarded the first reading.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Before the code change the signal had ~50% but now it much different so I missed that only 1/2 of the cycle was changing. The readings now are

 

4.2V:  637.2us low, 7.201ms high

3.7V:  562.1us low, 7.226ms high

3.2V:  486.5us low, 7.244ms high

 

So we're somewhat better but I don't see how these numbers equate to the actual voltage. I'm not expecting them to be spot on they're not even close. What's also odd to me is that I was expecting 10x Vcc so the values would be 42us, 37us, 32us yet we're an order of magnitude larger so perhaps my casting still isn't correct?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I suggest that you just measure the BandGap voltage.   Calculate VCC from this.   Compare with the actual VCC.

It is pretty accurate,  but obviously depends on the ultimate accuracy of the BandGap.

 

VCC = (1024 * 1.1) / ADCW

 

e.g. if VCC = 5V,  ADCW is about 225

e.g. if VCC = 3.3V, ADCW is about 341

 

There is little point in using 8-bit ADC.   But if you do,   you would have ADCH = 56 for 5V, ADCH = 85 for 3.3V

 

Having satisfied yourself that this method works,  you can use the results to adjust frequency, PWM,  choice of teabag, ....

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

David, sorry but what's ADCW, I don't find that in the ATtiny20 datasheet?

The ATtiny has a 10-bit ADC and from my understanding you can just read ADCH is you can accept an 8-bit calculation but if you combine ADCH and ADCL you'll be able to get a 10-bi reading.

 

I know that ADC = (Vin *1024)/Vref so I thought my method and calculations were correct. So sorry for not seeing the light but can you help a little more please.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Google "AVR ADCW" and I bet you will get the answer.
ADCW is the industry recognised name for the 10-bit ADC result. It shoould be accepted by GCC, CV, IAR, ICC, Rowley, ...
It saves you worrying about combining ADCH ADCL. The compiler will know what to do.
.
All the same, you can do the separate registers if you want.
Regarding the calculation.
ADCW = Vin * 1024 / Vref
ADCW = 1.1 * 1024 / VCC
VCC = 1.1 * 1024 / ADCW
VCC = 1.1 * 256 / ADCH if you want poor resolution
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, thanks, I had thought perhaps it was some register that the ATtiny20 didn't have.

 

So, it's good to know I can use it to simplify my readings but I'm not seeing why I'm not getting the "correct" results.

 

ACDW should be 268 for 4.2V and I'm getting 637 from my scope measurement

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
VCC = 1.1 * 1024 / ADCW

[side note] Always confusing to me, as the top value is 1023 counts -- but that represents a hair less than "full" value.  yeah, I know this has been bandied about over the years.  And makes no significant difference for "low battery" trip.

 

Remember that OP has a Tiny20.  Do you want to throw FP multiply into the mix?  IMO/IME, no.  But then to get decent resolution one must ensure that the multiply doesn't overflow a 16-bit intermediate result -- forcing to 32 bits (if no 32-bit multiplies and divides anywhere else in the app) may end up bigger than the FP mul and div?

 

As I opined earlier, if there is no display of the actual voltage there is no need IMO to convert to "voltage" at run time.  Do the calculations on paper to find the trip value in ADC counts.  If making a "meter" as OP is doing with the output pulse, then that can also be simply scaled to ADC counts.

 

Back to arithmetic:  OP showed 11 * 10 to get to tenths.  At a typical ADC count of say 1/3 of 1024 (that would be a nominal 3.3V Vcc and nominal 1.1V bandgap) that is about 341 counts as the divisor.  Just call *1024/341 as /3.  11*10 is about 100.  So you end up with only about 35 different values in the output.  Good enough for battery trip, but not real close on V, is it?  [thus I just keep to a magic number of counts...]

 

I'll usually jigger the multiplier to get an unsigned product as close to 16 bits as practical, and then scale the final result appropriately.  But suit yourself.

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The final product will not have a display so you're correct that a calculation to actual volts isn't important. I'm just still in the testing phase and trying to understand how the part works. I actually have a voltage divider connected to a pin and scaled for using the 1.1V reference voltage. I just read about being able to sense the actual Vcc and then also the imprecise nature of the 1.1V reference so I thought I would experiment. If I can save not having to mount 2 resistors and a cap as well as saving 2 processor pins (I tied the voltage divider ground to a processor pin so I could disconnect the divider and save some precious power) then that's a win.

 

So it sounds like perhaps the best bet is to use your calibration routine to tighten up the 1.1V reference and then just read ADCW value. I could then use my routine to see what the ADCW value is by measuring the pulse width on the scope. I do have 1 freen pin on the process which I guess I could use for a UART Tx pin but that might be going a little far to debug this sucker.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In apps like yours, I usually use the EEPROM to gather "debug" information.  Then use ISP to suck out the EEPROM contents, and decode.

 

But you have picked (the only?  one of the few?) model of AVR8 that has no EEPROM?

 

I can't see in the thread where you mentioned the app's power source and supplyV level.  IMO/IME, while there is a seminal thread on "AVRs can measure their own supply, but do it badly" it can be done satisfactorily without external components.  Already explored is the general approach.  If +/-10% on bandgap is too big, we run the "calibration" routine after ISP, and do ISP with a known supplyV.  The result of that (ADC counts) is stored as the actual value of the 1.1V with respect to the known voltage (say, 3.3V or 5V or whatever).  That is then used to adjust the supplyV reading accordingly.

 

Note that if using say 2x AA as supplyV, then be sure to check the battery level >>WHEN THE APP IS UNDER LOAD<<.  When idle and the AVR is drawing only a bit of current, even nearly-depleted batteries will read as near "fresh".

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Mon. Jun 26, 2017 - 08:50 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The power source will be a Li Ion single cell so starting voltage of 4.2V going down to maybe 3.2V. That's the beauty of the AVRs; AFAIK they are the only one's able to handle above 3.6V. I had to poke at TI because I said that they brag about low power but I said that you need a regulator because they can't handle 4.2V so there goes your power savings. Now I do run circuits fairly efficient but not having a regulator also saves on cost.

 

So, is it a pain to try and add a UART for debug info?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

From memory, the Tiny20 has got a USART. For debugging purposes, just add a UART-USB dongls.

I still reckon that it is easier to develop on a big chip. Then rebuild and test on the Tiny20.
I would just use Uno hardware. But actually I have a tiny1634 that is easy to use.
.
I own a Tiny20 and a Tiny40. It is painful to dig them out and find a TPI programmer.
.
Oh, Lee was critical of scaling with a f-p constant. 1.1 * 1024 = 1126. No need for any runtime f-p. You can calculate in mV if you want. Just use int32_t maths.
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You need a way to display the result directly. I flash an LED for each digit, e.g. 3 flashes...pause...5 flashes...pause...6 flashes. Modulate it at 40 kHz and parallel with an infrared diode and you can capture the value through a standard IR receiver-AVR-USB chain for logging.  My battery monitor logs the reading of 12 ATTinys every 10 seconds using this technique, a battery box being a fine dark and private place :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Unfortunately my coding skilla aren't that good to just whip out something clever like that. I'm more comfortable around a scope and soldering iron than for loops and unint!

 

I checked and the ATtiny does not have a USART. We left yesterday for vacation and I didn't think to grab an Arduino so I'll have to work with what I've got with me. It still bothers me that the counts aren't even close to what I calculate for the applied Vcc. I may try to modify the code to use Vref and check the voltage divider's input to see if that gives me any different results.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

GeorgeIoak wrote:
It still bothers me that the counts aren't even close to what I calculate for the applied Vcc.
As you seem to be talking in the realms of microseconds and, for example, a 1MHz AVR has a 1us cycle time then every opcode cycle is going to be significant in the length of the pulses you are trying to generate/measure. So if I were you I would persuade you C compiler to show you the Asm it is generating then get out your copy of the AVR Opcode manual and start counting those cycles then base your maths on accurate cycle counts.

 

Of course the "simpler" version of this is to move your pulses out of the realms of opcode cycle times. Work in ms not us so the odd us one way or another will have an insignificant effect. It doesn't really matter whether you use:

		for (int i=0;  i < reading; i++)
		{
			_delay_us(1);
		}

or

		for (int i=0;  i < reading; i++)
		{
			_delay_ms(1);
		}

 

BTW it is very sad you picked a chip that doesn't even have a USI let alone a UART. Most folks running "prototype experiment" would expect to use a UART as a minimum interaction device to allow you to control and see results in the micro. I suppose you could put a bit-banged "soft UART" into it? For interaction with humans (slow!) it doesn't need to be able to work at lightning speed - just 1200 or 2400 baud or something like that would be fine.

 

But personally I'd start with a decent sized micro for prototyping (like the 328 on an Arduino) then port and shoehorn the code into the brain-dead device later.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks @clawson, good idea to just switch to ms, dumb choice on my part on hindsight. To be honest I wasn't anticipating not being able to debug the chip. I'm glad I didn't buy the Atmel-ICE expecting that to be better than the AVRISP clone I have. I'm kind of stuck with what I've got with me this week unless I find something online that could be delivered to me in a day. Since I'm not the most proficient programmer I usually use debugging as a learning tool until I can better understand what's going on.

 

I'll switch to ms and see what my portable little scope shows me.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here's the results after changing the delay to ms instead of us:

 

 

ADC Count vs Vcc

Vcc (V) + Width (ms) -Width (ms) Delta
4.2 7.3 341.4 --
4.1 7.2 333.6 7.8
4.0 7.2 325.8 7.8
3.9 7.2 317.5 8.3
3.8 7.2 309.1 8.4
3.7 7.2 300.9 8.2
3.6 7.3 292.9 8.0
3.5 7.3 284.8 8.1
3.4 7.3 276.6 8.2
3.3 7.2 268.4 8.2
3.2 7.3 260.3 8.1

 

Vcc (V) +Width (ms) -Width (ms) Delta ADCW
4.2 7.3 341.4   268
4.1 7.2 333.6 7.8 275
4.0 7.2 325.8 7.8 282
3.9 7.2 317.5 8.3 289
3.8 7.2 309.1 8.4 296
3.7 7.2 300.9 8.2 304
3.6 7.3 292.9 8.0 313
3.5 7.3 284.8 8.1 322
3.4 7.3 276.6 8.2 331
3.3 7.2 268.4 8.2 341
3.2 7.3 260.3 8.1 352

 

So at least the count change is fairly consistent between Vcc changes of 0.1V but I'm not sure if I should be expecting the values to be a little tighter than this. I wonder if I have to run the calibration routine to shift the readings to match with Vcc. If I add ~60 to each count I get closer to actual Vcc

 

I edited this post to add the calculated ADCW counts. Couldn't figure out how to edit the existing table and the pasted table format isn't great, sorry

Last Edited: Tue. Jun 27, 2017 - 03:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oops.  My memories are obviously wrong.  Neither Tiny20 nor Tiny40 has an USART.

 

However, it is very easy to write a bit-banged USART TX.   i.e. you can send human readable messages to a Terminal.

Creating an USART RX is very difficult.  Not worth the bother.

 

Seriously.   Developing on a Uno is a breeze.   You would understand all the features of an AVR.    Easy to report messages on a Terminal.

 

Then rebuild for the brain-dead Tiny20.

 

David.

 

p.s.  I must confess that I have not read all of this thread.   I probably would have actually built and run code (if it was a mega328 or any other AVR)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Believe me, I hear you and I have a bunch of different Arduino boards at home and just plain forgot to grab a couple to test with. My board has a USB connector on it (not for USB communication but mainly for battery charging). Instead of leaving the data lines and OTG pin unused I brought out the TPIDATA, TPICLOCK, and RESET. I've got a programming header but I thought I'd make a custom cable that plugs into the USB port which allows reprogramming. The reason I mention this is that I could hack a USB cable here and connect it to my USB-to-Serial port dongle and use some bit-banged code to generate messages on one of these wires. That's something I could probably do today rather than trying to find a way to have an Arduino board delivered to me tomorrow.

 

Got any links handy for the bit-banged Tx?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

GeorgeIoak wrote:
Got any links handy for the bit-banged Tx?
Check the project section here. In particular anything written by "danni" is likely to be very good.

 

(which reminds me - we haven't seen Peter Danegger in a while??)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@theusch In your linked post you call

 

init_adc_cal();	// set up ADC for assumed 3.3V Vcc and start dummy conversion
		// (modified from assumed 5.0V rev. g

 

but I don't see what you actually do there. When I check my ADCW values and calculate a ratio against measured and theoretical it changes for each voltage applied. It varies from 0.8 to 1.4 (-Width/ADCW) so I'm not seeing how I can calibrate Vref if the fudge factor is different for each applied Vcc voltage.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'll have to dig back in versions to see if there is any difference between the 3.3V version and the 5V version...I can't think of anything.  Indeed, the "5V" version has no changes to that routine.

 

Nothing magic; an ADC setup with the selected reference as produced by the Wizard.  At least more-or-less. REMEMBER:  YMMV -- I wasn't using Tiny20; that app uses Tiny24.

//
// **************************************************************************
// *
// *		I N I T _ A D C _ C A L
// *
// **************************************************************************
//
//
//	Start up the ADC to be used for a series of conversions
//	of the internal bandgap "channel", using AVcc as reference.
//
//	The procedure assumes that Vcc is from the ISP programmer, and is 5.0V.
//
//	The results of this are then used in calculations during normal operation
//	on signals scaled to use the BG as reference.
//
void	init_adc_cal					(void)
{
	PRR &= 	~(1 << PRADC);

// ADC initialization
// ADC Clock frequency: 125.000 kHz
// ADC Voltage Reference: AVCC pin
// ADC Bipolar Input Mode: Off
// ADC Auto Trigger Source: ADC Stopped
// Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
// ADC4: On, ADC5: On, ADC6: On, ADC7: On
DIDR0=(0<<ADC7D) | (0<<ADC6D) | (0<<ADC5D) | (0<<ADC4D) | (0<<ADC3D) | (0<<ADC2D) | (0<<ADC1D) | (0<<ADC0D);
//ADMUX=ADC_VREF_TYPE;
//ADCSRA=(1<<ADEN) | (0<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (0<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
//ADCSRB=(0<<BIN) | (0<<ADLAR) | (0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);

// Start a dummy conversion on the internal Gnd channel to get things rolling
ADMUX=ADC_VREF_VCC | ADC_GND;
ADCSRA=(1<<ADEN) | (1<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (0<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);

ADCSRB=(0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);

}

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Tue. Jun 27, 2017 - 06:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

GeorgeIoak wrote:
When I check my ADCW values and calculate a ratio against measured and theoretical it changes for each voltage applied. It varies from 0.8 to 1.4 (-Width/ADCW) so I'm not seeing how I can calibrate Vref if the fudge factor is different for each applied Vcc voltage.

I don't understand what you are trying to say.  As demonstrated (IIRC) in that link, I set up for calibration and do 16 conversions, once each pass through the program.  The last result is stored in EEPROM, and is used to adjust run-time supplyV readings as demonstrated in another section.

 

BUT YOU HAVE NO EEPROM TO SAVE TO!  So you will indeed need to go to some other Plan B.  In the good old days when men were men and micros didn't have sissy toyz like EEPROM (or ADC or watchdog or ...), then it wasn't unusual to have a double-build sequence.  Build once; load to the device and e.g. calculate such things as the bandgapV or checksum or DAC level or similar.  Then plug these back into a source module, rebuild with those values, and reload the device.

 

You module is quite limited on tools such as EEPROM and comms.

 

		case	STATE_CAL:
			// Do one ADC read each pass.
			//	After 16 reads, take the last reading of the BG channel, store in EEPROM, and move on

			// Read ADC.  ADMUX already set
			ADCSRA |= (1 << ADSC);

			// Wait for conversion to complete
			while (ADCSRA & (1<<ADSC)) ;

            if (++conversion_count > 16)
            	{
            	// Take the last result; do a sanity check [future]; and store in EEPROM
            	worknum = ADCW;

            	// Nominal would be about 225 counts (1.1V/5.0V)

            	ee_bg_cal = worknum;
#if 0
//test -- 32-bit mul and div takes about 10% of flash (100 words?)
				// ADJ = ADC * CAL / NOM
				if ((ee_bg_cal > 100) && (ee_bg_cal < 500))
					{
					// Sanity check passed.  Adjust the ADC reading
					worknum = (unsigned long)worknum * (unsigned long) ee_bg_cal / BG_NOM;
					}
#endif
            	// Shut down the ADC
				ADCSRA = 0;	// Shut down ADC before invoking the PRR bit for it
				PRR |= 	(1 << PRADC);		// Shut Down ADC

            	// Move on to next state
            	state = STATE_CAL_DONE;
            	}
			break;

The ee_bg_cal value is then used to adjust the readings.

 

I don't know what you mean by the fudge factor.  Your readings are no good?  I'd have to study the table, and the output pulse code. 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'll have to study this after I grab some lunch but thanks for adding some details for me. 

 

What I meant by the fudge factor was that when I apply say 4.2V the pulse width is 341.4ms and if you calculate ADCW your theoretical pulse width should a count of 268. At Vcc=3.7 I measured 300.9ms and the calculated ADCW is 304

 

Vcc = (1024 * 1.1) / ADCW and if I try to calibrate I'm looking to find the actual bandgap voltage rather than assuming it is 1.1V so

 

Vref = (Vcc * ADCW) / 1024

 

With Vcc=4.2V and a pulse width of 341.4 (ADCW) you get a Vref of 1.40V

With Vcc=3.7V and a pulse width of 300.9 (ADCW) you get a Vref of 1.09V

 

So clearly my brain is not working right...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As the calculation is an inverse calculation, I think you need to work differently.  Let's use the table I posted in #13 above. 

 

If I have a perfect 1.1V bandgap, and a Vcc level of 2.75V I get 409 counts.

If I have a 1.0V bandgap and get 409 counts, then my Vcc is 3.0V.

If I have a 1.2V bandgap and get 409 counts, then my Vcc is 2.5V.

 

What is the purpose of your experiment and the resulting table above?  To determine bandgapV on this particular chip?

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is a fair amount of discussion above about the pulse generation.  I think in the other thread you determined what your AVR's clock speed is.  And you have a 'scope.  And your chip has a 16-bit timer.  (and an 8-bit which would be good enough for the purposes described below, using ADCH instead of ADCW)

 

-- Set up a 16-bit timer for Fast PWM.  For simplest operation, if you are running the timer at /1 and your ~1MHz, that would be 1us per timer count.  (if really needed at the end you can adjust by 2% for your 0.98MHz actual clock)

-- Conveniently, you have a 10-bit ADC, and your timer has a 10-bit Fast PWM mode...

 

-- Use either channel A (OC1A on PB1) or channel B (OC1B on PB2) as is convenient for the output.  A sample configuration is below.

-- So now you have a 1024us period.  [If you want to slow things down use a prescaler]  The nature of the timer is that 0 won't be full-off but who cares...

 

-- Do a series of ADC conversions on the bandgap channel, using a known fixed Vcc level.  I'd suggest at least 8 or 10.  Take the ADCW from the last one, and ...

 

-- [assuming channel A] ...put the value into OCR1A.  The 'scope trace will now be 1us per ADC count.  No worry about loop timing and such, and it runs forever.  Might get a runt when you change value but who cares, there will be a new period 1ms later.

 

-- If you care to, adjust for your clock being 2% below nominal.

 

After the above, with a known Vcc level and known AVR clock speed (NOTE:  For any particular run, you can measure the period on your waveform and it will be 1024 CPU clocks at /1, as the timer counts 0 through 1023) and proper use of the ADC (isn't clk/128 slower than the recommended ADC clock for best results?), then you can calculate the bandgapV.

 

Repeat for a few known Vcc levels and post those numbers.  Or if you want to challenge me, post the "known" voltage number and a couple other supplyV values you test with, and I'll predict what the ADC counts are.  (or post the counts and I'll tell you the supplyV)

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Using channel A, OC1A, PB1 output (be sure to make it an output), and a nominal starting value for OCR1A of 10%:

// Main Clock source: Calibrated Internal 8 MHz Osc.
CCP=0xd8;
CLKMSR=(0<<CLKMS1) | (0<<CLKMS0);
// Clock Prescaler division factor: 8
CCP=0xd8;
CLKPSR=(0<<CLKPS3) | (0<<CLKPS2) | (1<<CLKPS1) | (1<<CLKPS0);

// Input/Output Ports initialization
...

// Port B initialization
// Pull-up initialization:
// Bit3=Off Bit2=Off Bit1=Off Bit0=Off 
PUEB=(0<<PUEB3) | (0<<PUEB2) | (0<<PUEB1) | (0<<PUEB0);
// Function: Bit3=In Bit2=In Bit1=Out Bit0=In 
DDRB=(0<<DDB3) | (0<<DDB2) | (1<<DDB1) | (0<<DDB0);
// State: Bit3=T Bit2=T Bit1=0 Bit0=T 
PORTB=(0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);

// Break Before Make Mode PORTA: Off
// Break Before Make Mode PORTB: Off
PORTCR=(0<<BBMB) | (0<<BBMA);

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 1000.000 kHz
// Mode: Fast PWM top=0x03FF
// OC1A output: Non-Inverted PWM
// OC1B output: Disconnected
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer Period: 1.024 ms
// Output Pulse(s):
// OC1A Period: 1.024 ms Width: 0.1021 ms
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=(1<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (1<<WGM11) | (1<<WGM10);
TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (1<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10);
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x66;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=(0<<ICIE1) | (0<<OCIE1B) | (0<<OCIE1A) | (0<<TOIE1) | (0<<OCIE1B) | (0<<OCIE0A) | (0<<TOIE0);

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

GeorgeIoak wrote:
The power source will be a Li Ion single cell so starting voltage of 4.2V going down to maybe 3.2V.

I see that for that model the bandgap varies by a few percent at higher voltages.

At room temperature, thogh, fairly flat from 3.5V down to about 2V so shuld be pretty good to monitor your batteryV.  At your "full" 4.2V the chart indicates about 0.5% lower.  Not perfect but not too bad either.

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

From the formula in #22, you can measure the Bandgap if you know VCC.
Or you can measure VCC if you know the Bandgap.
.
The OP has got a Saleae Logic Analyser. So he could write diagnostics to SPI or a software UART. And read the decoded data.
But life is so much simpler if you just use printf to a Terminal.
.
Mind you, having read ADCW, he can use the value for duty cycle in PWM. Read the frequency, duty cycle via Saleae.
.
In practice, you might want to monitor Battery voltage. The absolute accuracy is not important. You just want an indication that the battery needs changing. e.g. a flashing LED.
.
I repeat. It is easier to develop on a big AVR. The Tiny20 posseses a TWIS and SPI slave. I do not see anything 'better' than a regular Mega. Ok, the TWIS works quite nicely. Everything else is brain dead.
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm a little confused about your "starting voltage of 4.2V".  Are you recharging in-system?  If not, it seems that nominal voltage is about 3.7V give-or-take.

 

Li-ion or "LiPo"?

 

Discussion at https://electronics.stackexchang...

 

8 down vote accepted

1] VOLTAGE: 3.6V or 3.7V - 18650 Li Ion Batteries

All single cell lithium ion batteries are going to be 3.6-3.7v. There are applications where multiple cells will be tied together in series. This will result in voltages that are multiples of 3.6-3.7v. So as long as you match the number of cells and approximate mAH you should be fine.

  1. LiIon batteries have lots of variants of chimestry - all are LiIon, but different voltages, prices, reliability.
LiCoO2    3.7 V   140 mA·h/g  0.518 kW·h/kg
LiMn2O4   4.0 V   100 mA·h/g  0.400 kW·h/kg
LiNiO2    3.5 V   180 mA·h/g  0.630 kW·h/kg
LiFePO4   3.3 V   150 mA·h/g  0.495 kW·h/kg
Li2FePO4F     3.6 V   115 mA·h/g  0.414 kW·h/kg
LiCo1/3Ni1/3Mn1/3O2   3.6 V   160 mA·h/g  0.576 kW·h/kg
Li(LiaNixMnyCoz)O2    4.2 V   220 mA·h/g  0.920 kW·h/kg
LiCoO2    3.7 V   140 mA·h/g  0.518 kW·h/kg
LiMn2O4   4.0 V   100 mA·h/g  0.400 kW·h/kg
LiNiO2    3.5 V   180 mA·h/g  0.630 kW·h/kg
LiFePO4   3.3 V   150 mA·h/g  0.495 kW·h/kg
Li2FePO4F     3.6 V   115 mA·h/g  0.414 kW·h/kg
LiCo1/3Ni1/3Mn1/3O2   3.6 V   160 mA·h/g  0.576 kW·h/kg
Li(LiaNixMnyCoz)O2    4.2 V   220 mA·h/g  0.920 kW·h/kg

 [...where one chemistry in the table indeed shows 4.2V...]

LiCoO2    3.7 V   140 mA·h/g  0.518 kW·h/kg
LiMn2O4   4.0 V   100 mA·h/g  0.400 kW·h/kg
LiNiO2    3.5 V   180 mA·h/g  0.630 kW·h/kg
LiFePO4   3.3 V   150 mA·h/g  0.495 kW·h/kg
Li2FePO4F     3.6 V   115 mA·h/g  0.414 kW·h/kg
LiCo1/3Ni1/3Mn1/3O2   3.6 V   160 mA·h/g  0.576 kW·h/kg
Li(LiaNixMnyCoz)O2    4.2 V   220 mA·h/g  0.920 kW·h/kg

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
Mind you, having read ADCW, he can use the value for duty cycle in PWM.

;)  I wish I had thought of that.

 

david.prentice wrote:
I repeat. It is easier to develop on a big AVR.

I guess.  But still, IME I like to develop using the target processor.  On a small app especially, there aren't going to be that many lines of code so the "porting" is working with the idiosyncrasies of the particular target, as we have found here.  Will OP's Tiny20 bandgap and ADC and associated work the same as on my Tiny24 app I'm holding up as an example?  The stuff we are discussing in this thread still needs to be addressed on the final target.

 

In another sence, OP has never said how many of these are going to be made and what the criteria are for choosing this model in the first place.  Sometimes with a "quick" app and low/moderate volume we'll pick a model with a reasonable pricing but perhaps overkill on paper.  Lessee--if I can save 40 hours at $100/hour, that pays for $0.20 extra on 20000 units if I did that in my head correctly.  If we only plan to do 100/year...

 

 

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Everything in life has a price.
Any high volume product is going to depend more on parts cost than development time.
For small volumes the balance changes.
.
Obviously any product has to be tested on the target device. I can't see much problem with the Tiny20. It just is a little painful to develop with. But for this particular project, you would probably do it in the Simulator.
.
Other Tinys have some unique hardware features.
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK you guys are great and I do appreciate all the help! I am using a Li Ion and there is a charger built on board so after charging the battery will start at 4.2V. I have another project that is also operated by Li Ion but uses a much smaller battery (110mAh) and has Bluetooth, an accelerometer, and a vibration motor. I'm doing some lifetime tests and to give you some data:

 

started on 4/19 with a battery voltage of 4.17V

on 5/17 the battery voltage was 3.90V

on 6/17 the battery voltage was 3.77V

 

I would measure and activate the vibration every day. So not as much drain as a string of LEDs but you can see that there is plenty of life in the battery between 4.2V and 3.7V

 

When I get back I'll try to run these experiments as well as searching to see if there's any place in South Lake Tahoe that has Arduinos!

 

BTW, I don't have a Saleae Logic Analyser with me but I do have a Digilent Analog Discovery 2. It's a great little box to have on the road since it gives you a scope, a logic analyzer, voltmeter, blah, blah blah. Not the best but at least you multiple tools in 1 little portable box. The logic analyzer isn't as good as the Saleae but the scripting tools are nice

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
I can't see much problem with the Tiny20.

Someone smart said:

david.prentice wrote:
Everything else is brain dead.

;)  I'd find it difficult, as with OP's situation here, to work without any EEPROM (ignoring no comms, brain-dead, small SRAM, etc.).

 

Compare resources of Tiny20 and e.g. Tiny1634 that costs about the same in -Mx packages.  (bigger packages -Sx seem to be about $0.50 more/qty. 100)

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
Compare resources of Tiny20 and e.g. Tiny1634 that costs about the same in -Mx packages.

 

No way, the Tiny20 is sub $.40, I don't see the Tiny1634 anywhere near that. Although you guys are making me 2nd guess my choice!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just a cautionary interjection here; the attiny20 needs 5V applied while programming. Caught me off-guard just last week. I opted to switch to the attiny24A for an extra 10 cents rather than adding an extra power header and diode to protect the rest of the circuit.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

GeorgeIoak wrote:
No way, the Tiny20 is sub $.40,

Yet again, you haven't answered previously asked question (unless I missed it) about quantity and other important design criteria.

 

Octopart shows qty. 100 prices from US distributors at about $0.75 for Tiny20, and about that for Tiny1634 in -Mx packages.

 

But scrolling down to more flavours, I indeed see sub-$0.50:

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, I ran your code but I think something is wrong because I don't see a change in the period with different Vcc levels. 

3.14V Measured across decoupling Cap

4.16V Measured across decoupling Cap

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

GeorgeIoak wrote:
OK, I ran your code but I think something is wrong because I don't see a change in the period with different Vcc levels.

What do you mean "ran my code"?  You are indeed getting the 10% default duty cycle.  You have to do the steps I outlined earlier, not just the PWM setup:

-- Do a series of ADC conversions on the bandgap channel, using a known fixed Vcc level.  I'd suggest at least 8 or 10.  Take the ADCW from the last one, and ...

 

-- [assuming channel A] ...put the value into OCR1A.  The 'scope trace will now be 1us per ADC count.  No worry about loop timing and such, and it runs forever.  Might get a runt when you change value but who cares, there will be a new period 1ms later.

 

-- If you care to, adjust for your clock being 2% below nominal.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Did you adjust your ADC clock prescaler?

15.5 Prescaling and Conversion Timing
By default, the successive approximation circuitry requires an input clock frequency between 50 kHz and 200 kHz to get
maximum resolution.
 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

balisong42 wrote:

Just a cautionary interjection here; the attiny20 needs 5V applied while programming. Caught me off-guard just last week. I opted to switch to the attiny24A for an extra 10 cents rather than adding an extra power header and diode to protect the rest of the circuit.

Yes, I found that out while programming. It can actually program at ~4.6V and it looks like the battery charging IC (BQ24040) and LED string driver (AP5724) can handle so I should be OK

 

As far as volumes go it's large enough that internet pricing doesn't hold valid. It's a good comparison but not what the actual purchase price is. Oddly, the ATtiny20 is cheapest in the SOIC-14 in tubes. 1000 piece retail price direct from Microchip is $0.41 but I'll be doing more than 1k but less than 1 million

  • 1
  • 2
  • 3