ADC_INTERNAL_TEMP calculation in Example4 is off by a factor of 20-ish?

I’m having an issue with calculating a correct temperature for a reading from ADC_INTERNAL_TEMP on a Redboard Artemis. Example4_analogRead shows the same issue (as it should - that’s where I grabbed the code from!). I found one other thread on the board that discusses an issue with analogReads involving ADC_INTERNAL_TEMP, but it looks like the OP there got his issue fixed by updating to board library version 1.0.30 (viewtopic.php?f=169&t=52451&p=213396&hi … MP#p213396).

I’m using 1.0.30, and still having this issue - and honestly, I can’t see how the OP on the other thread wasn’t also having this issue with Example4, even after the board update. Here’s what I’m seeing:

Example4 returns a line like this:

A3: 16383 VCC/3: 9140 VCC: 3.35V internalTemp: 443.43 vss: 0

The chip is obviously not 443.43 degrees C, or my desk would be on fire! LOL. I added some code to try to ascertain how the math is getting to that point, so I have it print out internalTempVoltage (raw read off the ADC), and then I save aside internalTemp after the raw read is converted to voltage, but before converting voltage to degrees C. I get the following (note, for the same data line I posted above):

Internal temp voltage: 8248 internal temp voltage: 1.69

If the right conversion truly is 3.8mV per degree, something is really, really off in this value. It’s 72 degrees F in my office right now, which is 22.2C. That should be 84mV, not a value 20 times larger (give or take).

Reading the other thread, the OP there reported seeing values of 514 when reading with 10-bit resolution - if his calculations were based on using the 14-bit resolution, that’d yield 81 degrees F, but he says his office was 68F. If he used 1024 for the calculation, he ends up about where I am, at 435 degrees C.

It’s entirely possible that I’m missing something - so, please correct me, if so! Otherwise, can someone confirm this is a bug in the Example (my guess is the conversion from voltage to temp), and maybe provide the correction?

I get the same results as you from the example. I get changes with my finger on the Artemis chip, or hitting it with hot air, so the transfer function in the code is incorrect.

The first thing that’s almost certainly incorrect is using VCC (3.3V) in the calculation, when the Artemis ADC has a reference voltage of 2.0V.

The Apollo3 datasheet references the slope of 3.8mV/degC but it doesn’t specify an offset, so a variable is lacking to make a proper mV->degC transfer function. 0mV == 0degC seems unlikely, especially given the empirical evidence. Ie. 1.089V == 18degC. Using this, I’ve guessed my room temperature and used it decide on a subtraction of 247 from the final value. It’s +/-3degC accuracy so probably near enough is good enough.

Here’s the updated code:

  int internalTempVoltage = analogRead(ADC_INTERNAL_TEMP); //Read internal temp sensor. 3.8mV/C, +/-3C
  double internalTemp = internalTempVoltage * 2 / 16384.0; //Convert internal temp reading to voltage
  internalTemp /= 0.0038; //Convert voltage to degrees C
  internalTemp -= 247;
  Serial.print("\tinternalTemp: ");
  Serial.print(internalTemp, 2);

Thanks for your help, stephenf. That’s a lot closer, for sure. Based on current temp in my office (and maybe the calibration/tolerance of my sensor) it should be about 237 instead of 247 - but that’s a usable ballpark, I’m sure. +/- 3C is a 10-ish degrees Farenheit swing, so it’s not a precision value, either way. I’ll set up an issue on this via GitHub in a bit.

I looked at the numbers vs. 2V, too, but it didn’t occur to me that it might be a simple offset. Will be interesting to see if the SF guys have info to add. Maybe there was a hardware change after the Example was written, or something? I’ll file an issue via GitHub a bit later today, when I have a moment.

Actually, my math was off - my factor is 242… just magically forgot in my calculation that I was adjusting for Centigrade, not Farenheit… ha ha

Opened this issue: https://github.com/sparkfun/Arduino_Apollo3/issues/158

Also, found a note in the CPU datasheet that suggests calibration is needed for the sensor.

Looks like issue 158 is resolved, and will be in 1.0.31+. Nate got that one handled quick!

Hi,

I recently got notified of your post from another member. I’m the “OP” you referred to. Yes I did have the same problem with Example4 as you had. There are two things wrong with that example. The first one, already identified by “stephenf” in his reply, is the need to use 2.0V as the reference voltage multiplier for the ADC, not the VCC voltage of 3.35V. With a 14 bit resolution the analog divisor is 2^14 = 16384 (rather than the 16383 you show in your post). For your analog reading of 8248 the voltage is then 8248*2/16384 = 1.0068V, which is similar to my readings near 68 degF. The next problem with the example is how they use the 3.8 mV/degC specification for the internal temperature sensor (see Apollo3 datasheet for specifications). This specification only provides the slope of an assumed linear temperature response. Unfortunately, the specification does not give the associated reference temperature and voltage at which this slope applies. These additional values are needed to find an unknown temperature. It would be reasonable to assume the reference temperature to be 68 degF (20 degC) since this is the reference typically given for RTD’s. But you still need the associated reference voltage, which will vary from chip to chip, as will the slope. But all is not lost, because all you need are two voltage readings at two known temperatures (obtained with an independent accurate temperature measuring device) to create a chip specific calibration! For the most accuracy the temperatures should be fairly diverse, ideally the extremes of the intended temperature measuring range but at least say 40 degF apart.

For a linear temperature response (which is a reasonable assumption for a limited range of temperatures, on the order of -20 degF to 240 degF, the slope is equal to (V2 - V1)/(T2 - T1). To find a new temperature T3, given a voltage reading V3, you can use either V1, T1 or V2, T2 as your reference in the following equation:

(V3 - Vref)/(T3 - Tref) = slope (now known from previous measurements). After rearranging you get:

T3 = Tref + (V3 - Vref)/slope.

The above will give you the most accurate calibration for a given chip. However, some Apollo3 boards, such as the Redboard Artemis, have factory calibration data, stored in flash memory, that can be read. These values are referred to as “Trims”. See the Ambiq SDK example adv_vbatt.c, in the SDK\boards\apollo3_evb\examples folder, to see how these values can be retrieved. The trim values are based on a hypothetical linear response from 0 degK to any other temperature. No temperature sensor is going to be linear over such an extreme range but the resulting equation will work over a reasonable range centered around 68 degF. The slope, using trim values, is:

slope = (Vtrim - Voffset)/(Ttrim - 0)

In the above equation Voffset is the theoretical voltage at 0 degK that correlates to the actual measured slope. The temperature equation, based on trims, is the same as that derived above with the exception that the temperature values must be in degK. Using Voffset and 0 degK as the reference values, this gives:

T3 degK = 0 degK + (V3 - Voffset)/slope = Ttrim degK*(V3 - Voffset)/(Vtrim - Voffset)

For boards that don’t have calibration data, the following generic values are provided in the SDK:

Ttrim = 299.5 degK, Vtrim = 1.02809V, Voffset = -0.00428V

These generic values result in a slope of 3.447 mV/degC, which is similar to calibrated values for my two Redboard Artemis boards, which are:

Board1: Ttrim = 298.601 degK, Vtrim = 1.01355V, Voffset = 0.003235V, which gives a slope of 3.3835 mV/degC

Board2: Ttrim = 299.45 degK, Vtrim = 1.00525V, Voffset = -0.00055V, which gives a slope of 3.3588 mV/degC

The calibrated values for Board2 produce results very close to independent temperature measurements, but those for Board1 differ by up to 10 degF! Therefore, the best calibration values to use are those you obtain yourself from two independent temperature readings and associated voltage measurements.

Thanks - that’s good info! For my purposes, the getTemperature() function that Nathan put together gets it done. It does supply results on my board that are a little hotter than ambient, but that may make sense, given that the temp sensor is under the CPU shield. If I end up needing to get more accurate, your info above is a great starting point!