tinyAVR 2-series: read supply voltage

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

Hey all,

 

I'm currently migrating a project from series 0/1 to series 2 tinyAVRs. I'm now using the ATTINY1626. Migration worked fine, except for my code to read the VDD supply voltage (without external circuit), see AN2447. That's a crucial feature and I'm not sure if the series 2 AVRs can actually do it. The only information I found was that here:

 

https://github.com/SpenceKonde/megaTinyCore#internal-sources

 

Now I'm massively confused ;-) I can set VREF to 1.024V on the series 2 (1.1V on series 0/1), so that seems to be fine. But then what should I choose as internal voltage? Just ADC_VDDDIV10 instead of ADC_INTREF?! Will that work?

 

Best, Timm

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

As far as I read the data sheet, it seems that there is no problem.
If 1.024V is used for Vref and ADC_VDDDIV10 is measured with 10 bits without amplification, it is given by VDD = ADC_Result * 10 (mV).
You already have a working chip. Now let's write the test code and evaluate it.

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

kabasan wrote:

As far as I read the data sheet, it seems that there is no problem.
If 1.024V is used for Vref and ADC_VDDDIV10 is measured with 10 bits without amplification, it is given by VDD = ADC_Result * 10 (mV).
You already have a working chip. Now let's write the test code and evaluate it.

 

Thanks, kasaban! I will test asap, but don't have the chips yet. Will give code + feedback here, so that future series 2 users might benefit from it :-) Just thought that maybe someone already has some experience/code with that.

 

Best, Timm

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

Looks like you can now work it multiple ways, but can probably do as before-

 

ADC Vref = Vdd

MUXPOS = DACREF0 (AC VREF, why they name it DAC-anything without a dac in sight, who knows)

 

You can set AC0 VREF to 1.024 just like you did 1.1v in avr0/1, and is also the default value so don't need to touch.

 

Your formula just needs a little tweak.

 

edit- #2 sounds better/simpler, and leaving half the resolution unused will not matter, plus its an easy formula that stays in one place (resolution not moving around due to changing vref).

Last Edited: Thu. Jun 10, 2021 - 01:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm wrote:

Looks like you can now work it multiple ways, but can probably do as before-

 

ADC Vref = Vdd

MUXPOS = DACREF0 (AC VREF, why they name it DAC-anything without a dac in sight, who knows)

 

You can set AC0 VREF to 1.024 just like you did 1.1v in avr0/1, and is also the default value so don't need to touch.

 

Your formula just needs a little tweak.

 

edit- #2 sounds better/simpler, and leaving half the resolution unused will not matter, plus its an easy formula that stays in one place (resolution not moving around due to changing vref).

 

Hi curtvm,

 

sounds great! Thanks for your help. Didn't know that I could also use DACREF0. I will try out both methods and will post tested code soon.

 

Best, Timm

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

Hi all,

 

finally assembled an ATTINY1626 and did some tests. Wanted to share the results:

 

  • MUXPOS =  ADC_VDDDIV10 did not work at all, measurement value did not change with the supply voltage
  • MUXPOS = DACREF0 works, but with a "magic number conversion" ((4096UL * 1024UL) / res) that I don't understand, but is very accurate between Vcc = 2V and 4.2V, tested with F_CPU = 1 MHz

 

#define TIMEBASE_VALUE					(uint8_t)ceil(F_CPU*0.000001)

uint16_t readyVoltageSeries2() {
	uint32_t res;
	
	ADC0.CTRLA = ADC_ENABLE_bm;
	//ADC0.CTRLB = ADC_PRESC_DIV2_gc; // DEFAULT setting, no need to change
	ADC0.CTRLC = VREF_AC0REFSEL_1V024_gc | (TIMEBASE_VALUE << ADC_TIMEBASE0_bp); // Vref = 1.024V
	ADC0.CTRLE = 100; // sample duration ((100 * 2) / F_CPU seconds), 1 MHz = 0.2ms
	ADC0.MUXPOS = ADC_MUXPOS_DAC_gc; // using DAC as MUX voltage, ADC_MUXPOS_VDDDIV10_gc doesn't work
	ADC0.COMMAND = ADC_MODE_SINGLE_12BIT_gc; // single mode with 12 bit
	ADC0.COMMAND |= ADC_START_IMMEDIATE_gc; // start conversion

	while(true) {
		if(ADC0.INTFLAGS & ADC_RESRDY_bm) { // wait until measurement done
			res = (uint32_t) ADC0.RESULT; // get raw adc result
			if(res == 0) { res = 1; }
			res = (4096UL * 1024UL) / res; // convert result to mV
			break;
		}
	}
	ADC0.CTRLA = 0; // disable ADC
	return ((uint16_t) res);
}

 

Best, Timm

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

ADC0.CTRLC = VREF_AC0REFSEL_1V024_gc | (TIMEBASE_VALUE << ADC_TIMEBASE0_bp); // Vref = 1.024V

 

You are using the VREF value for AC0REFSEL 1.024v, which is 0 (VREF_AC0REFSEL_1V024_gc = 0), so you are getting Vdd as adc vref (also a value of 0) which is the method used on previous avr0/1 (you are getting 1.024v from dacref0 since that is default for VREF_AC0). Which is why your formula works. To be clear- the peripheral VREF and the adc vref are not the same thing, and the clue in the define or enum is VREF_anything is for VREF registers.

Last Edited: Tue. Jun 15, 2021 - 09:44 PM