Lordanubis
Posts: 37
Joined: Mon Dec 23, 2013 8:13 pm

Internal temp sensor

Thu Jan 28, 2021 10:27 pm

Did start with the Pico 3 hours ago and am playing with the internal temperature sensor, but some questions comes up..

Why is there a 4-5º difference between reality ( 20,5ºC ) and the chip result? It's about 16ºC for almost 3 hours even with LED's turning on and off.

Where does that formula come from?

Code: Select all

conversion_factor = 3.3 / (65535)
temperature = 27 - ( ( sensor_temp.read_u16() * conversion_factor ) - 0.706) / 0.001772
Why isn't the chip warming up to room temperature? With a laser temp sensor the chip case is 18,8ºC, are the internal element cooling down??
Are the RP Pico chips compared to each other equal and stable in their internal temp sensor results? What error percentage should I expect?

The to test temperature will be between 18- 22ºC.
Because it will be battery powered, I don't want to use as less as possible external components.

hippy
Posts: 12485
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: Internal temp sensor

Fri Jan 29, 2021 12:27 pm

From the RP2040 datasheet - Page 575 -
4.9.4. Temperature Sensor

The temperature sensor measures the Vbe voltage of a biased bipolar diode, connected to the fifth ADC channel (AINSEL=4). Typically, Vbe = 0.706V at 27 degrees C, with a slope of -1.721mV per degree. Therefore the temperature can be approximated as follows:

T = 27 - (ADC_voltage - 0.706)/0.001721

As the Vbe and the Vbe slope can vary over the temperature range, and from device to device, some user calibration may be required if accurate measurements are required. The temperature sensor's bias source must be enabled before use, via CS.TS_EN. This increases current consumption on ADC_AVDD by approximately 40 μA.
Notionally the temperature is a straight line which passes through 706mV at 27C whose voltage falls as temperature rises.

So, to determine temperature; read the ADC, determine what voltage the 16-bit reading represents, map that on to the line, and see what temperature represents.

I don't know what the accuracy or linearity etc is of the temperature sensor in the RP2040 but it's quite common on other microcontrollers to have to calibrate them to get accurate temperature readings. Being some degrees out when using the 'typical conversion' algorithm is quite common in my experience.

jamesh
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 31340
Joined: Sat Jul 30, 2011 7:41 pm

Re: Internal temp sensor

Fri Jan 29, 2021 12:58 pm

Indeed, I suspect calibration will be necessary.
Principal Software Engineer at Raspberry Pi Ltd.
Working in the Applications Team.

hippy
Posts: 12485
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: Internal temp sensor

Fri Jan 29, 2021 2:23 pm

Lordanubis wrote:
Thu Jan 28, 2021 10:27 pm
temperature = 27 - ( ( sensor_temp.read_u16() * conversion_factor ) - 0.706) / 0.001772
hippy wrote:
Fri Jan 29, 2021 12:27 pm
From the RP2040 datasheet - Page 575 -

T = 27 - (ADC_voltage - 0.706) / 0.001721
However it doesn't cause much difference around normal room temperatures.

hippy
Posts: 12485
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: Internal temp sensor

Fri Jan 29, 2021 2:37 pm

jamesh wrote:
Fri Jan 29, 2021 12:58 pm
Indeed, I suspect calibration will be necessary.
Even then it probably won't be as accurate as some might be hoping for.

The temperature sensor only generates a small voltage and with a very small voltage change per whole degree of change.

A 20C change in temperature is a 34mV change in temperature sensor voltage, is a 43 change in 12-bit ADC value.

So at the very best the temperature sensor only has 0.5C resolution

With the ADC having effectively 9-bit reolution it's worse than that; 0.6C.

And it's probably even worse due to the inevitable noise in the ADC circuitry, minor variation with supply and reference voltages, actual temperature effects.

Not knocking the RP2040 - I spent ages calibrating a PICmicro device and came to the conclusion a DS18B20 is a much easier solution.

Lordanubis
Posts: 37
Joined: Mon Dec 23, 2013 8:13 pm

Re: Internal temp sensor

Fri Jan 29, 2021 4:29 pm

For the current project accuracy is not that important; if it is 0,8 degrees off its okay for the purpose, I will update the formula to get it comparable with the reality. Even the speed is not an issue. Current is the main issue.

If it gets lower or higher than the mentioned temperature, it will/has to do its job.

I know about the PIC and TI chips and their internal temp.

Thank you. I will read that mentioned page.

Lordanubis
Posts: 37
Joined: Mon Dec 23, 2013 8:13 pm

Re: Internal temp sensor

Fri Jan 29, 2021 6:40 pm

Okey, just adjust my formula to

T = 27 - (machine.ADC(4).read_u16() - 0.706)/0.001721

but that looks wrong. It gives a negative value.

So, my first question comes back, where are those formulas coming from and what is the right one?

pidd
Posts: 3658
Joined: Fri May 29, 2020 8:29 pm
Location: Wirral, UK

Re: Internal temp sensor

Fri Jan 29, 2021 6:58 pm

Some external temperature sensors have a standby current of less than 1uA, assuming you don't need really frequent readings they aren't going to make a lot of difference to battery life.

hippy
Posts: 12485
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: Internal temp sensor

Fri Jan 29, 2021 7:25 pm

Lordanubis wrote:
Fri Jan 29, 2021 6:40 pm
So, my first question comes back, where are those formulas coming from and what is the right one?
The temperature sensor provides a voltage to the ADC which will be ...
  • voltage = ( ( T - 27 ) * -0.001721 ) + 0.706
First step ...
  • voltage = ( ( T - 27 ) * -0.001721 ) + 0.706
  • voltage = ( ( 27 - T ) * 0.001721 ) + 0.706
Then, to determine T for a given voltage ...
  • voltage = ( ( 27 - T ) * 0.001721 ) + 0.706
  • voltage - 0.706 = ( 27 - T ) * 0.001721
  • ( voltage - 0.706 ) / 0.001721 = 27 - T
  • ( ( voltage - 0.706 ) / 0.001721 ) + T = 27
  • T = 27 - ( ( voltage - 0.706 ) / 0.001721 )
The division has precedence so no need for parenthesis, though I'd personally leave them in ...
  • T = 27 - ( voltage - 0.706 ) / 0.001721

hippy
Posts: 12485
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: Internal temp sensor

Fri Jan 29, 2021 7:31 pm

Lordanubis wrote:
Fri Jan 29, 2021 6:40 pm
Okey, just adjust my formula to

T = 27 - (machine.ADC(4).read_u16() - 0.706)/0.001721

but that looks wrong. It gives a negative value.
Because you missed a step out. "machine.ADC(4).read_u16()" returns the raw ADC reading which isn't a voltage. You need -

Code: Select all

voltage = machine.ADC(4).read_u16() * 3.3 / 65535
T = 27 - ( voltage - 0.706) / 0.001721
Or, if you really want it on one line -

Code: Select all

T = 27 - ( ( machine.ADC(4).read_u16() * 3.3 / 65535 ) - 0.706) / 0.001721

Lordanubis
Posts: 37
Joined: Mon Dec 23, 2013 8:13 pm

Re: Internal temp sensor

Fri Jan 29, 2021 8:42 pm

hippy wrote:
Lordanubis wrote:
Fri Jan 29, 2021 6:40 pm
Okey, just adjust my formula to

T = 27 - (machine.ADC(4).read_u16() - 0.706)/0.001721

but that looks wrong. It gives a negative value.
Because you missed a step out. "machine.ADC(4).read_u16()" returns the raw ADC reading which isn't a voltage.
Of course, you'r right about that. I should have read better.
hippy wrote: You need -

Code: Select all

T = 27 - ( ( machine.ADC(4).read_u16() * 3.3 / 65535 ) - 0.706) / 0.001721
I did do that in my first post. Still wrong, a bit.
even heating up tot 45ºC it stops at <27ºC with -

Code: Select all

T = 27 - ( ( machine.ADC(4).read_u16() * 3.3 / 65535 ) - 0.706) / 0.0022 
Of course this is not academic thinking, but just watching a movie and playing with a heatgun in my hands.

hippy
Posts: 12485
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: Internal temp sensor

Sun Jan 31, 2021 11:34 pm

Very odd. While I have also observed that the calculated temperature doesn't match the actual ambient, is quite a lot lower, I don't have any test equipment to check things out fully, determine where the issue may be.

If one works through it for 48C ...

Temperature sensor voltage as stated in RP2020 documentation -
  • voltage = ( ( T - 27 ) * -0.001721 ) + 0.706
  • voltage = ( ( 48 - 27 ) * -0.001721 ) + 0.706
  • voltage = 0.669859
Temperature sensor ADC reading with 3V3 Vref-
  • adc = voltage * 65535 / Vref
  • adc = 0.669859 * 65535 / 3.3
  • adc = 13303
Determining temperature from ADC reading -
  • T = 27 - ( ( machine.ADC(4).read_u16() * 3.3 / 65535 ) - 0.706) / 0.001721
  • T = 27 - ( ( 13303 * 3.3 / 65535 ) - 0.706) / 0.001721
  • T = 48
Of course this all depends on the very first equation being an accurate representation of the hardware. If that's not right then the reversing equation won't be right either.

What we really need is someone with test equipment to produce graphs of ADC readings against various calibrated temperatures so we can compare those to the stated straight-line function. And ideally over a range of RP2040 devices so we can determine what the variance is.

One thing which can affect readings is the Vref used. If Vref isn't exactly 3V3 then the reversing equation which assumes it is will show significant errors -

Code: Select all

3.20V Vref : 48C calculated to be 35.9C
3.25V Vref : 48C calculated to be 42.0C
3.30V Vref : 48C calculated to be 48.0C
3.35V Vref : 48C calculated to be 53.8C
3.40V Vref : 48C calculated to be 59.5C
In most cases a Vref which isn't an exact 3V3 won't have much of an impact on analogue inputs using equations which assume Vref is 3V3. It is only because the temperature sensor voltage is so low and changes so little over its range that discrepancies are magnified far greater than they normally would be.

cleverca22
Posts: 6274
Joined: Sat Aug 18, 2012 2:33 pm

Re: Internal temp sensor

Sun Jan 31, 2021 11:55 pm

hippy wrote:
Sun Jan 31, 2021 11:34 pm
adc = 0.669859 * 65535 / 3.3
i double-checked with a multi-meter, and found that my 3.3v rail was measuring 3.27v instead
i had to adjust the scaling code, and then i was getting better results, my example is in C though:

Code: Select all

/**
 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <stdio.h>
#include "pico/stdlib.h"
#include "tusb.h"
#include "hardware/adc.h"
#include "hardware/gpio.h"

int main() {
    stdio_init_all();
    adc_init();
    printf("waiting for usb host");
    while (!tud_cdc_connected()) {
      printf(".");
      sleep_ms(500);
    }
    printf("\nusb host detected!\n");
    for (int pin=26; pin<30; pin++) {
      printf("init pin %d\n", pin);
      adc_gpio_init(pin);
    }
    adc_set_temp_sensor_enabled(true);
    while (true) {
      printf("Hello, world!");
        for (int channel=0; channel<5; channel++) {
          adc_select_input(channel);
          // 12-bit conversion, assume max value == ADC_VREF == 3.3 V
          const float conversion_factor = 3.27f / (1 << 12);
          uint16_t raw = adc_read();
          float result = raw * conversion_factor;
          printf(" ADC%d: %f (%d)", channel, result, raw);
          if (channel == 3) {
            float voltage = result * 3;
            printf(" VSYS = %f volts", voltage);
          } else if (channel == 4) {
            float temp = 27 - (result - 0.706)/0.001721;
            printf(" temp = %f C", temp);
          }
        }
        puts("");

        sleep_ms(1000);
    }
    return 0;
}
and the output:

Code: Select all

Hello, world! ADC0: 0.645059 (808) ADC1: 0.692959 (868) ADC2: 0.716111 (897) ADC3: 1.566343 (1962) VSYS = 4.699028 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.658630 (825) ADC1: 0.696152 (872) ADC2: 0.715312 (896) ADC3: 1.579116 (1978) VSYS = 4.737349 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.624302 (782) ADC1: 0.654639 (820) ADC2: 0.685774 (859) ADC3: 1.567141 (1963) VSYS = 4.701423 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.570015 (714) ADC1: 0.594763 (745) ADC2: 0.633882 (794) ADC3: 1.564746 (1960) VSYS = 4.694239 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.544468 (682) ADC1: 0.566821 (710) ADC2: 0.607537 (761) ADC3: 1.568738 (1965) VSYS = 4.706213 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.544468 (682) ADC1: 0.572410 (717) ADC2: 0.621108 (778) ADC3: 1.563948 (1959) VSYS = 4.691844 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.592368 (742) ADC1: 0.625898 (784) ADC2: 0.672202 (842) ADC3: 1.561553 (1956) VSYS = 4.684658 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.645059 (808) ADC1: 0.690564 (865) ADC2: 0.711321 (891) ADC3: 1.562351 (1957) VSYS = 4.687053 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.653042 (818) ADC1: 0.703337 (881) ADC2: 0.717708 (899) ADC3: 1.558359 (1952) VSYS = 4.675078 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.635478 (796) ADC1: 0.660227 (827) ADC2: 0.689766 (864) ADC3: 1.561553 (1956) VSYS = 4.684658 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.566821 (710) ADC1: 0.590771 (740) ADC2: 0.634680 (795) ADC3: 1.571931 (1969) VSYS = 4.715794 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.529299 (663) ADC1: 0.558838 (700) ADC2: 0.614722 (770) ADC3: 1.561553 (1956) VSYS = 4.684658 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.532493 (667) ADC1: 0.565225 (708) ADC2: 0.625898 (784) ADC3: 1.565544 (1961) VSYS = 4.696633 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.579595 (726) ADC1: 0.610730 (765) ADC2: 0.653840 (819) ADC3: 1.572729 (1970) VSYS = 4.718188 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.635478 (796) ADC1: 0.678589 (850) ADC2: 0.708926 (888) ADC3: 1.564746 (1960) VSYS = 4.694239 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.649849 (814) ADC1: 0.696951 (873) ADC2: 0.726489 (910) ADC3: 1.565544 (1961) VSYS = 4.696633 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.637075 (798) ADC1: 0.673799 (844) ADC2: 0.693757 (869) ADC3: 1.561553 (1956) VSYS = 4.684658 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.593167 (743) ADC1: 0.617117 (773) ADC2: 0.649849 (814) ADC3: 1.563149 (1958) VSYS = 4.689448 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.546863 (685) ADC1: 0.563628 (706) ADC2: 0.616318 (772) ADC3: 1.564746 (1960) VSYS = 4.694239 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.526904 (660) ADC1: 0.565225 (708) ADC2: 0.609133 (763) ADC3: 1.565544 (1961) VSYS = 4.696633 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.562830 (705) ADC1: 0.603545 (756) ADC2: 0.652244 (817) ADC3: 1.567141 (1963) VSYS = 4.701423 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.617117 (773) ADC1: 0.664219 (832) ADC2: 0.700144 (877) ADC3: 1.564746 (1960) VSYS = 4.694239 volts ADC4: 0.706531 (885) temp = 26.691605 C
Hello, world! ADC0: 0.654639 (820) ADC1: 0.698547 (875) ADC2: 0.722498 (905) ADC3: 1.566343 (1962) VSYS = 4.699028 volts ADC4: 0.706531 (885) temp = 26.691605 C
and a DS18B20 elsewhere in the room claims it is 21.94c, the pico is also under a bright LED lamp, so reading a few degrees off seems within reason

hippy
Posts: 12485
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: Internal temp sensor

Mon Feb 01, 2021 1:55 am

cleverca22 wrote:
Sun Jan 31, 2021 11:55 pm
i double-checked with a multi-meter, and found that my 3.3v rail was measuring 3.27v instead
i had to adjust the scaling code, and then i was getting better results
Many microcontrollers will have some kind of internal fixed voltage reference which can be ADC read and the actual ADC's Vref can be determined in code. The RP2040 doesn't have that but it could be added off-chip and read by one of the other 3 ADC channels.

cleverca22
Posts: 6274
Joined: Sat Aug 18, 2012 2:33 pm

Re: Internal temp sensor

Mon Feb 01, 2021 10:40 am

hippy wrote:
Mon Feb 01, 2021 1:55 am
Many microcontrollers will have some kind of internal fixed voltage reference which can be ADC read and the actual ADC's Vref can be determined in code. The RP2040 doesn't have that but it could be added off-chip and read by one of the other 3 ADC channels.
Screenshot_2021-01-30_08-06-43.png
Screenshot_2021-01-30_08-06-43.png (35.7 KiB) Viewed 4202 times
it already has an off-chip voltage refernence, and i think adding a 3v shunt diode will clamp the upper limit to exactly 3v, giving you a cleaner reference

hippy
Posts: 12485
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: Internal temp sensor

Mon Feb 01, 2021 12:10 pm

cleverca22 wrote:
Mon Feb 01, 2021 10:40 am
it already has an off-chip voltage refernence
That's not a fixed reference voltage, it will vary with 3V3. You need a stable fixed voltage to read via ADC to be able to determine what ADC_AVDD Vref or that '3V3' is in code.

cleverca22
Posts: 6274
Joined: Sat Aug 18, 2012 2:33 pm

Re: Internal temp sensor

Mon Feb 01, 2021 12:17 pm

hippy wrote:
Mon Feb 01, 2021 12:10 pm
cleverca22 wrote:
Mon Feb 01, 2021 10:40 am
it already has an off-chip voltage refernence
That's not a fixed reference voltage, it will vary with 3V3. You need a stable fixed voltage to read via ADC to be able to determine what ADC_AVDD Vref or that '3V3' is in code.
yep, thats why i had to measure it with a multi-meter, and adjust the code to use 3.27 instead

but if you follow the guide in the text on the schematic, i think it will clamp the reference to 3v, and that would then be more stable

Blimp10
Posts: 6
Joined: Fri Jan 24, 2014 3:12 pm

Re: Internal temp sensor

Sat Feb 20, 2021 5:42 pm

Hi guys,

so the formula for the data sheet requires you to have the voltage!

T = 27 - (ADC_voltage - 0.706)/0.001721

However, when you use read adc_read() it returns the ADC value. This number is calculated via:

adc_read() = (ADC_voltage / reference_voltage) * (adc_resolution)

adc_resolution = 4096 (12bit)
reference_voltage = 3.3

therefore rearranging the equation for the voltage measured gives you!

ADC_voltage = ( adc_read() / 4096) * 3.3
i.e case
0.71V ~ (888/4096) * 3.3

then you can use the formula given to calculate temperature!

T = 27 - (ADC_voltage - 0.706)/0.001721
i.e case
24.5 ~ 27 - (0.71 - 0.706)/0.001721

these are not very accurate and have some downside verus external temperature sensors. See RP2040 Datasheet for more!

cleverca22
Posts: 6274
Joined: Sat Aug 18, 2012 2:33 pm

Re: Internal temp sensor

Sat Feb 20, 2021 5:44 pm

Blimp10 wrote:
Sat Feb 20, 2021 5:42 pm
ADC_voltage = ( adc_read() / 4096) * 3.3
also, i checked with my multi-meter, and found that the 3.3v rail, was actually 3.27v

if you want any kind of accuracy, you must measure your 3.3v rail, and adjust the code to use the real voltage, or use a shunt diode like the schematic for the pico says to

User avatar
pettefar
Posts: 46
Joined: Thu Jul 12, 2012 9:53 pm

Re: Internal temp sensor

Sun May 23, 2021 5:37 pm

My 3V3 was 3V27 too. But I adjusted my conversion_factor to 3.2368/65535 to match the readings of a more accurate temperature sensor. The internal temperature sensor was -8'C off with the standard value!
Nick
Dublin

Return to “General”