portable temperature measurement?

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

I'm looking for a portable way to read the internal temperature sensor on AVRs.
avr-libc doesn't define anything for the ADMUX settings for the internal temperature sensor. The t85, t84, and m328 all have different ADMUX settings for the temperature sensor.

Has anyone already written an open-source library that works with a number of different AVRs? My searching just finds libraries for things like the dallas temperature sensors.

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

Interesting idea.

I'd have to look at the datasheets but from my recollection aren't the calibration and reading mechanisms different (as well as picking the channel)?

I'm curious about the utility of said library. As you are measuring the temperature of the AVR itself, wouldn't self-heating effects be important except in the most quiescent of applications?

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:

I'm curious about the utility of said library. As you are measuring the temperature of the AVR itself, wouldn't self-heating effects be important except in the most quiescent of applications?

I've always wondered that myself.

The largest known prime number: 282589933-1

Without adult supervision.

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

An unscientific "poll" of my downloaded datasheets indicates that at least the AVR models below have internal temperature sensor:

MegannnRFxn family
Mega406
Mega32M1/C1 family
Mega48 family
Tiny48 family
Tiny1634
Tiny24 family
Tiny25 family
Tiny20, Tiny40
Tiny43U
Tiny87 family
Tiny261 family
Tiny441 family
Tiny828

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:
Interesting idea.

I'd have to look at the datasheets but from my recollection aren't the calibration and reading mechanisms different (as well as picking the channel)?

I'm curious about the utility of said library. As you are measuring the temperature of the AVR itself, wouldn't self-heating effects be important except in the most quiescent of applications?

There's lots of references online on the accuracy and calibration of the internal temperature sensor, starting with "AVR122: Calibration of the AVR's internal temperature reference"

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

What about the second question? ;)

While calibration procedures might be similar I saw at least three distinct transfer functions in my quick datasheet search for "Temperature Measurement".

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:
What about the second question? ;)

I could have answered quickly (like some of the old farts on this forum with egos bigger than their brains), but I have more respect for you than that since you seem to stay above that drama.

I did some digging around to find a reference I read about on HaD. It shows the self-heating effect is very stable, and from that I conclude that it can be ignored as a separate effect in offset calibration when the calibration is done after the AVR has been running for a minute or two.

http://www.narkidae.com/research...

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

Will turning down the clock prescaler when the chip is 'too hot' reduce the power and as a result the chip temp?

Imagecraft compiler user

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

bobgardner wrote:
Will turning down the clock prescaler when the chip is 'too hot' reduce the power and as a result the chip temp?

For a moment your post sounded like something from a PC overclocking forum, except for hotrodding an AVR. :)

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

You have to hot-rod the AVR Mega328P on your Arduino Uno if you run the main board and its daughterboards (or "shields") at 3.3V. Its on-board clock is 16MHz.

That's a little faster than the official spec. But I suspect that the spec is legalese, a cover-your-backside in case you make 100000 boards and run them at 10% overclock and a few percent fail, you can't sue Atmel.

Is the purpose of the AVR on-board temperature sensor to support shutting-down the AVR in 70 degree centigrade board temperatures, or is it an actual useful sensor that tells you what temperature is in the room?

Here's a chance to offer insight into the great centigrade vs. Fahrenheit debate. 0 to 100 degrees C is the range between water freezing and boiling. Formal but too few degrees to be useful for humans. Fahrenheit uses 0 to 100 to measure the range of temperatures that a man can do a day's work outside. Below 0, it's too cold no matter how many layers of clothes that you put on and above 100, it's too hot regardless of how much water that you drink. Much more reasonable on a human scale. It's why the smart countries haven't switched to the less useful centigrade scale.

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

Simonetta wrote:

Here's a chance to offer insight into the great centigrade vs. Fahrenheit debate. 0 to 100 degrees C is the range between water freezing and boiling. Formal but too few degrees to be useful for humans. Fahrenheit uses 0 to 100 to measure the range of temperatures that a man can do a day's work outside. Below 0, it's too cold no matter how many layers of clothes that you put on and above 100, it's too hot regardless of how much water that you drink. Much more reasonable on a human scale. It's why the smart countries haven't switched to the less useful centigrade scale.

"Any sufficiently advanced troll is indistinguishable from a genuine kook." - Alan Morgan

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

I used the Tiny1634 a while back and saw the Temp sensor as well. I thought it was used to measure the package temperature, and use the reading to calibrate the internal oscillator.

Re-reading the datasheet makes me re-think that thought as the error of both the oscillator, and the Temp sensor would not provide very favorable results.

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

But it seems like a simple experiment. Write a program to flash an led every sec, read the chip temp, reduce the clock as a fn of temp. Blow the hair dryer on it and see if the led flashes slower. Repeat with no clk reduction, see if led stops due to some failure/error related to overtemp.

Imagecraft compiler user

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

Uncle Bob said...

Quote:
I ain't nobody's uncle, so don't call me that.
Ummm... OK. :lol:

Ross McKenzie ValuSoft Melbourne Australia

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

Quote:
"Any sufficiently advanced troll is indistinguishable from a genuine kook." - Alan Morgan

Ralph, which one are you? Try to respond with something we can at least laugh at.

So what is the challenge? Read the temp in a portable way across chips or to read the temperature accurately?

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

Quote:

It shows the self-heating effect is very stable, ...

I looked at the link. I won't disagree that in a trivial/steady-state app the results are as reported.

But what about when the app goes from "idle" to sinking/sourcing a number of good-sized indicator LEDs? Engages PWM channels driving sensors? and the like.

Again, what is the end use for these gathered temperatures?

As your linked article mentioned, some might use the actual temperature to adjust internal oscillator. I've used it in a couple apps to note that the enclosure housing the AVR and other circuitry is getting "too darned hot" to run safely. In one app it was the reverse--when it was too darned cold, a heater was turned on for the LCD display. But that is about it.

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:
Quote:

It shows the self-heating effect is very stable, ...

Again, what is the end use for these gathered temperatures?

Why does it matter? So you can tell me I'm doing it wrong?
If it's simply to satisfy your curiosity, it's for wireless sensor nodes.

Although it only works with a few devices so far, I have some working code:

#include 
#include 
#include 

uint8_t temp_offset EEMEM;

static uint16_t doADC()
{
    // start conversion with ADC clock prescaler 16
    ADCSRA = (1<<ADSC) | (1<<ADPS2);
    while (ADCSRA && (1<<ADSC));        // wait to finish
    return ADCW;
}

#define ADC_GAIN 1.06
#define SAMPLE_COUNT ((256/ADC_GAIN)+0.5)
// returns signed byte for temperature in oC
char temperature()
{
    ADMUX = (0<<REFS0) | (1<<MUX3);     // ADC8
    uint16_t tempRaw = 0;
    // take multiple samples then average
    for (uint8_t count = SAMPLE_COUNT; --count;) {
        tempRaw += (doADC() - 273);
    }
    return ((tempRaw/256) - eeprom_read_byte(&temp_offset) ) ;
}

// temperature at programming time
#define AIR_TEMPERATURE 25
__attribute__ ((constructor)) void calibrate_temp (void)
{
    if ( eeprom_read_byte(&temp_offset) == 0xff)
    {
        // temperature uncalibrated
        char tempVal = temperature() + 1;
        eeprom_write_byte( &temp_offset, tempVal - AIR_TEMPERATURE );
    }
}

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

Presumably the ADEN is in the bit of the code we can't see?

Also a bit curious to set ADPS2 each time you make a reading.

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

Quote:

Why does it matter? So you can tell me I'm doing it wrong?

Sheesh. I don't care how you do it. My [repeated] query has to do with the utility of the whole endeavor. I suppose "just because I want to" is valid. As I posted, I'd think that as an add-on part of a full app, there will be a lot of variables such as self-heating.

Quote:

If it's simply to satisfy your curiosity, it's for wireless sensor nodes.

I can see, I guess, that if these nodes are in a more-or-less constant state that the AVR would tend to draw a more-or-less constant current and the effects would be as in your linked article. Will firing up the wireless to report change the current draw enough (as well as the nearby heating from the transmitter?) so it is no longer steady-state? I suppose with infrequent reports things would return to steady-state.

What have you found so far? When I did the datasheet search reported above, it appeared that most (maybe all?) of the modern Tiny models with the feature seemed to have a common interface.

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

clawson wrote:
Presumably the ADEN is in the bit of the code we can't see?

Good eye. I had hastily pasted in the untested version... It actually would turn off ADC since ADEN would get zero'd. Corrected:

    ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADPS2);

Quote:

Also a bit curious to set ADPS2 each time you make a reading.

ADCSRA is outside of the I/O address space, so assigment takes less code than read, or, write.
If it were in the sbi/cbi range I'd have set ADEN & PS2 outside doADC, and just set ADSC in doAdc() since it would compile to a single sbi.

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

Quote:

while (ADCSRA && (1<<ADSC));

One too many & ;)

If there is other ADC work in the app, then the switch to the needed internal reference may well take some time and/or some number of conversions before you'll get any useful temperature channel readings. I can try to hunt out past threads on that if you like.

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:
Quote:

Why does it matter? So you can tell me I'm doing it wrong?

Sheesh. I don't care how you do it. My [repeated] query has to do with the utility of the whole endeavor.
Quote:


So it really shouldn't matter if there's a method to my madness. :-)

Quote:

If it's simply to satisfy your curiosity, it's for wireless sensor nodes.

I can see, I guess, that if these nodes are in a more-or-less constant state that the AVR would tend to draw a more-or-less constant current and the effects would be as in your linked article. Will firing up the wireless to report change the current draw enough (as well as the nearby heating from the transmitter?) so it is no longer steady-state? I suppose with infrequent reports things would return to steady-state.

I'm using nRF24l01+ modules. At 0dB transmit power they consume 11-12mA. The transmit time is ~500uS. Then they go back to power-down mode (~1 uA) until the next transmission...

Quote:

What have you found so far? When I did the datasheet search reported above, it appeared that most (maybe all?) of the modern Tiny models with the feature seemed to have a common interface.

Well, the t84a and t85 are definitely different.

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

Quote:

ADMUX = (0<<REFS0) | (1<<MUX3); // ADC8

Isn't internal/bandgap/1.1V reference needed for temperature channel? On Mega48 family that would be 1-1 in the reference bits.

=====
The 1.1V reference varies some percent from nominal, and IME from chip-to-chip even from the same model and batch. The calibration may well cancel that out?

=====
I pulled the datasheets back up from the search yesterday. Concentrating on the Tinys and Mega48 family, there isn't much commonality in temperature channel selection, nor for reference selection. You have set yourself to a daunting task. :)

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

Wow--setup bits are all over the place, at least on Tinys.

Model		1.1V REF	Channel 	Notes
(Family)	REFS1/REFS0	(binary)	     
========	========	========	=====
Mega48		11		1000
Tiny441		01		1100		Also REFS2; shifted REFS1/0
Tiny24		10		10 0010
Tiny167		01		1011
Tiny43		01		111		Single REFS bit
Tiny261		01		111111		Also REFS2; shifted REFS1/0
Tiny828		001		011110		Separate ADMUXB

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:
Quote:

ADMUX = (0<<REFS0) | (1<<MUX3); // ADC8

Isn't internal/bandgap/1.1V reference needed for temperature channel? On Mega48 family that would be 1-1 in the reference bits.

Ugh. The above code is for the t88, which on first inspection looked the same as the mxx8. As you pointed out the reference voltage selection is different.
I hate writing blocks of #ifdef __avr...

Quote:

The 1.1V reference varies some percent from nominal, and IME from chip-to-chip even from the same model and batch. The calibration may well cancel that out?

I looked back at a thread I started about the t85's internal temperature sensor where you mentioned the bandgap variability. The calibration will cancel that out well enough for my purposes.

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

theusch wrote:
Wow--setup bits are all over the place, at least on Tinys.

Model		1.1V REF	Channel 	Notes
(Family)	REFS1/REFS0	(binary)	     
========	========	========	=====
Mega48		11		1000
Tiny441		01		1100		Also REFS2; shifted REFS1/0
Tiny24		10		10 0010
Tiny167		01		1011
Tiny43		01		111		Single REFS bit
Tiny261		01		111111		Also REFS2; shifted REFS1/0
Tiny828		001		011110		Separate ADMUXB

Any idea if there are common defines for parts with the same configuration; i.e. m48/88/168/328?
I don't want to have a bit list of #ifdefs
__AVR_ATmega88__, __AVR_ATmega168__, __AVR_ATmega328__

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

ralphd wrote:
Ugh. The above code is for the t88, which on first inspection looked the same as the mxx8. As you pointed out the reference voltage selection is different.
I hate writing blocks of #ifdef __avr...
Then don't. Use a host-based program to generate them for you. All you need to do is maintain a spreadsheet (or database, or XML, or CSV) of the particulars.

ralphd wrote:
I looked back at a thread I started about the t85's internal temperature sensor where you mentioned the bandgap variability. The calibration will cancel that out well enough for my purposes.
Be wary of the ADC in general on the t85. I have found it to be quite cranky. Not only does the band gap reference suffer the same issues with drift over Vcc and temperature as do other AVR, but the ADC will give very different results depending on whether you sample in active mode, idle mode, or ADC noise reduction mode.

By 'very' I don't mean just a few LSB. More like a 20 LSB spread.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Quote:
ADCSRA is outside of the I/O address space, so assigment takes less code than read, or, write.
When it's going to take 65us to make a reading anyway what does the 1 or 2 cycles difference in setting a bit or making a complete register write really matter? If you were really concerned about the ADC conversion time you wouldn't be doing it synchronously in the first place (at which point I guess I could see the issue with how long the original "trigger" takes).

EDIT: yoiks, there was a whole page 2 I missed!

Quote:
I don't want to have a bit list of #ifdefs

If you look at other people's multi-CPU code - even the AVR-LibC headers you'll find that this is principally how everyone does it. There is no magic to group 48/88/168/328 or whatever you really do need:

#if defined (48) || defined (88) || define (168) || defined (328) etc.
...

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

clawson wrote:
Quote:
ADCSRA is outside of the I/O address space, so assigment takes less code than read, or, write.
When it's going to take 65us to make a reading anyway what does the 1 or 2 cycles difference in setting a bit or making a complete register write really matter?

Are you suggesting I should try to get out of the habit of writing efficient code? :-)

By writing tight code the first time around, I rarely have to go back and tweak/optimize code in the situations where it's required.

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

ralphd wrote:
By writing tight code the first time around, I rarely have to go back and tweak/optimize code in the situations where it's required.
Agreed. However 'tight' often means 'machine specific'. IMO it's better to concentrate on portable code. Seems you agree, based on the title of this thread ;)

You can have both:

  if ((&ADCSRA - __SFR_OFFSET) < 0x20) {
    ADCSRA |= (1<<ADSC);
  }
  else {
    ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADPS2); 
  }

Since the expression in the if is constant, the compiler will optimise it away and leave only the relevant access to ADCSRA.

It would be nice if this could be done with #if instead, but ADCSRA expands to _SFR_MEM8(0x7A) which expands to _MMIO_BYTE(0x7A) which expands to (*(volatile uint8_t *)(0x7A)) which is meaningless to the preprocessor.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

clawson wrote:

Quote:
I don't want to have a bit list of #ifdefs

If you look at other people's multi-CPU code - even the AVR-LibC headers you'll find that this is principally how everyone does it. There is no magic to group 48/88/168/328 or whatever you really do need:

#if defined (48) || defined (88) || define (168) || defined (328) etc.
...

Which I find messy and hard to maintain.
I think I came up with a better way:

#if defined (REFS1) && !defined(REFS2) && !defined(MUX4)
    // m48 family
    #define ADCINPUT (1<<REFS0) | (1<<REFS1) | (1<<MUX3)
#elif !defined(REFS1) && !defined(MUX4)
    // tinyx8
    #define ADCINPUT (0<<REFS0) | (1<<MUX3)
#elif defined(REFS2)
    // tinyx5 0x0f = MUX0-3
    #define ADCINPUT (0<<REFS0) | (1<<REFS1) | (0x0f)
#else
    #error unsupported MCU
#endif

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

I tested it out on a m328p pro mini and it's working great. The temperature readings are *very* stable; I had over 100 readings in a row at 23C.
I put a large cotter pin in the freezer, then held the end of it on the m328, and the temperatures dropped down to 0C within a few seconds.

Experimenting with ice is a bit more problematic if you don't put it in a plastic bag. I got readings in the -80's when some ice melted and dripped down onto the leads.

I've posted the updated code on nerdralph.googlecode.com.

The first time I tested it I used optiboot on a pro mini to flash it. Optiboot doesn't clear the eeprom. I switched to a usbasp, which also made it easy to read back the temperature calibration offset value from eeprom.

Attachment(s): 

I have no special talents.  I am only passionately curious. - Albert Einstein