I have a bare-metal application where I am getting a strange set of die temperature readings. They are strange in that they are 7 or 8 C below the ambient air temperature (and thus, at least 15C below the expected die temp). I've looked at all of the possible culprits I can think of and have had no success in determining why the calculated values are so far off.
I am sampling an analog input (PE3) and the die temperature in the same sequencer (SS2). I have trimmed the software calculations (manually) to include the measured Vdda value and the analog voltage calculation is in very good agreement with the measured voltage at PE3. With this result, I would expect all external issues (variations in Vdda, power supply noise, etc...) to be common to the two measurements.
I have read the errata (ADC#09 from "SPMZ849D–August 2013–Revised August 2014") for the GH6PM and have tried placing the temp sensor in all 4 SS slots with no change in the result. In fact, this part does not seem to express the errata because the first FIFO reading is usually within 1 LSB of the last. I also have hardware averaging turned on (64 samples), but this does not affect the issue, it just smooths out the readings. With no HW averaging, the raw ADC values vary by something like +/-20 LSBs (not nearly enough to account for the observed offset).
The part being used was salvaged from a TM4C1294 launchpad (it was the JTAG interface processor). Is it possible that the parts used for the launchpads to have relaxed acceptance specifications on the peripheral modules that are not needed for the JTAG application? I am not confident in this possibility since a TM4C123GH6PM launchpad that I have gives even lower readings for Tj (see below).
I am confident that the sensor is being accessed since I can blast the MCU with cold spray and get a significant drop in calculated temperature followed by a slow return to the original value.
Below are code snippets in case they are of assistance. As pictured, SS2 is configured to gather 4 temperature readings. The commented line above that is what I use to gather the AIN0 and TS readings. As mentioned above, when this line is included (and the next commented out) the AIN0 readings appear correct. This is output from the SW showing the captured ADC readings and calculated values (shown for the all-TS SS configuration):
#samps: 4, R0: 2163, R3: 2162
eng: V0: 1.74 V, Tj: 17.26 C
stats: s0: 1000, s3: 0003
These are some readings from the GH6PM launchpad (un-modified) -- Vdda is within 0.01V of the application MCU:
#samps: 4, R0: 2269, R3: 2270
eng: V0: 1.82 V, Tj: 10.75 C
stats: s0: 1000, s3: 0003
Note: The status words are captured before the ADC values are read from the FIFO, so that is why the last status indicates that the FIFO is not empty.
Ambient air temp for both targets was 26C, and this was in a controlled environment with both die sets fully acclimated to the ambient temp (in other words, I didn't just drag either board in from arctic storage and start testing them).
ADC INIT (not shown is the GPIO init which happens elsewhere. Since ANIN0 is working as expected, I don't consider it relevant here):
U16 adc_init(void) { volatile uint32_t ui32Loop; // ADC init SYSCTL_RCGCADC_R |= SYSCTL_RCGCADC_R0; // enable ADC clock ui32Loop = SYSCTL_RCGCADC_R; SYSCTL_RCGC0_R |= SYSCTL_RCGC0_ADC0; // activate ADC0 (legacy code) ui32Loop = SYSCTL_RCGC0_R; GPIO_PORTE_AFSEL_R |= SPARE5; // enable alt fn, PE3 GPIO_PORTE_AMSEL_R |= (SPARE5); ADC0_CC_R = ADC_CC_CS_PIOSC; // use PIOSC ADC0_PC_R = ADC_PC_SR_125K; // 125KHz samp rate // ADC sequencer init ADC0_SSPRI_R = 0x1023; // Sequencer 2 is highest priority ADC0_ACTSS_R &= ~ADC_ACTSS_ASEN2; // disable sample sequencer 2 ADC0_EMUX_R &= ~ADC_EMUX_EM2_M; // seq2 is software trigger ADC0_SSMUX2_R = 0x0000; // set channels, PE3 = ain0 // ADC0_SSCTL2_R = (ADC_SSCTL0_TS1|ADC_SSCTL0_IE1|ADC_SSCTL0_END1); // // TS0 is 2nd sample, IE0 enabled after 2nd samp ADC0_SSCTL2_R = (ADC_SSCTL0_TS3|ADC_SSCTL0_TS2|ADC_SSCTL0_TS1|ADC_SSCTL0_TS0|ADC_SSCTL0_IE3|ADC_SSCTL0_END3); // do 3 samples of Tj per eratta ADC#09 // TS is 4th sample, IE enabled after 4th samp // ignore 1st 2 TS samples, only use TS3 reading ADC0_SAC_R = ADC_SAC_AVG_64X; // set 64x HW averaging ADC0_IM_R &= ~ADC_IM_MASK2; // disable SS2 interrupts ADC0_ACTSS_R |= ADC_ACTSS_ASEN2; // enable sample sequencer 2 return 0; }
This function reads the fifo into an array (data and status are captured as sequential words in the array):
U8 adc_in(U16* p) { #define NUM_SAMPS 4 // number of samples in sequence U8 i; ADC0_PSSI_R = ADC_PSSI_SS2; // initiate SS2 while((ADC0_RIS_R & ADC_RIS_INR2) == 0); // wait for conversion done for(i=0; i<NUM_SAMPS; i++){ *p++ = ADC0_SSFSTAT2_R & 0xffff; // get fifo status in 1st buffer word *p++ = ADC0_SSFIFO2_R & 0x0fff; // read result in 2nd buffer word } ADC0_ISC_R = ADC_ISC_IN2; // acknowledge completion (clr flag) return i; }
Finally, this is where I calculate the voltage/temperature for display (3.29V is what is measured at pin 2 of the MCU) (adc_in() is called prior to this snippet):
// TJ = 147.5 - (75 * (rawADC * 3.29 / 4096)) fa = 147.5 - ((float)adc_buf[7] * 60.242E-3); // fa is the die temp from sample 4 fb = (float)adc_buf[1] * 803.223E-6; // fb is the voltage for sample 0 sprintf(obuf,"eng: V0: %.2f V, Tj: %.2f C",fb,fa); puts0(obuf);
Thanks for taking a look.