Search by Tags

SoC Temperature Readout (WinCE)

 

Article updated at 02 Feb 2018
Compare with Revision




This article demonstrates how to read Colibri/Apalis internal Soc temperature.

Colibri PXAxxx

PXAxxx processors do not have internal temperature sensors. External temperature sensor must be added to the carrier board if temperature measurements are required.

Colibri/Apalis Txx

To measure Temperature of Soc on Colibri T20, T30 and Apalis T30 module use following C code:

#include <windows.h>
 
/// Temperature zone
typedef enum
{
    NvRmTmonZoneId_Module = 1,  ///< specifies the temperature sensor located on the module, away from the CPU.
    NvRmTmonZoneId_Core   = 2,  ///< specifies the temperature sensor measuring the CPU core voltage
} NvRmTmonZoneId;
 
/// NvError NvRmDiagGetTemperature(NvRmDeviceHandle pHandle, NvRmTmonZoneId ZoneId, DWORD* pTemperatureC);
///
/// Read a temperature from the on-module temperature sensor
/// @param[in]  pHandle         not required. Always set to 0
/// @param[in]  ZoneId          specifies which temperature sensor to read
/// @param[out] pTemperatureC   measured temperature in degree C
/// @return                     0 indicates success, any other value indicates an error
typedef DWORD (*PFNNvRmDiagGetTemperature)(DWORD, NvRmTmonZoneId, DWORD*);
PFNNvRmDiagGetTemperature NvRmDiagGetTemperature;
 
/// Demo function to read the temperatures on Tegra modules
/// To keep the code simple, there is no error handling implemented.
int _tmain(int argc, _TCHAR* argv[])
{
    HMODULE hMod;
    DWORD   moduleTemperature;
    DWORD   cpuTemperature;
 
    // evaluate function pointers
    hMod=LoadLibrary(L"libnvrm.dll");
    NvRmDiagGetTemperature  = (PFNNvRmDiagGetTemperature)GetProcAddress(hMod, L"NvRmDiagGetTemperature");
 
    // read temperatures
    NvRmDiagGetTemperature(0, NvRmTmonZoneId_Module, &moduleTemperature);
    NvRmDiagGetTemperature(0, NvRmTmonZoneId_Core,   &cpuTemperature);
    return 0;
}

In C# the following code can be used:

// definition of the native code call
[DllImport("libnvrm.dll")]
public static extern UInt32 NvRmDiagGetTemperature(UInt32 pHandle, UInt32 ZoneId, out UInt32 TemperatureC);
 
// To actually read the temperature:
{    
    UInt32 retVal;
    UInt32 tempModule;
    UInt32 tempCpu;
 
    retVal = NvRmDiagGetTemperature(0, 1, tempModule);    
    retVal = NvRmDiagGetTemperature(0, 2, tempCpu);
}

Colibri VFxx

To measure temperature of Soc on Colibri VF50, VF61 module use following code:

#include <windows.h>
#include "winioctl.h"
 
#define ADC_AVG_32      3
#define ADC_MODE_10BIT  1 
#define IOCTL_ADC_READ CTL_CODE(32768,2048,METHOD_BUFFERED,FILE_ANY_ACCESS)
 
typedef struct
{
    BYTE        channel;                                // ADC channel used
    BOOL        useaverage;
    BOOL        avgsamples;                             // Number of samples to be averaged to get value
    BOOL        mode;                                   // ADC mode 8, 10, 12 bit mode
} ADC_READ;
 
typedef struct
{
    DWORD       vTemp25;                                // V_Temp value at 25 'C at VDD 3.3V see ADC electrical characteristic in datasheet
    float       slopeCoefficient;                       // temperature slope value used to calculate temperature see datasheet
    BYTE        channel;                                // temperature sensor connected to 26 channel of adc
}TEMPERATURE_SENSOR;
 
int wmain()
{
    HANDLE      adc0            =   NULL;               // handle to adc device
    ADC_READ    adcRead;                                // ADC configuration 
    TEMPERATURE_SENSOR tempSensor;                      // Internal temperature sensor configuration
    DWORD       adcValue        =   0;                  // variable to get adc value
    DWORD       returned        =   0;                  // variable holds number of bytes returned by DeviceIoControll      
    float       temperature     =   0;                  // variable to hold temperature reading
    DWORD       error           =   0;                  // error value used by Getlasterror to return error 
    tempSensor.channel          =   26;                 // Temperature sensor channel
    tempSensor.slopeCoefficient =   1.8;                // temp slope to calculate value
    tempSensor.vTemp25          =   721;                // VTemp at 25 'C
    adcRead.useaverage          =   TRUE;   
    adcRead.avgsamples          =   ADC_AVG_32;         // 32 samples averaged                                      
    adcRead.mode                =   ADC_MODE_10BIT;     // ADC used in 10 bit mode
    adcRead.channel             =   tempSensor.channel; // adc_channel 26 connected to internal temperature sensor
    // provide handle to adc0
    adc0 = CreateFile(TEXT("ADC1:"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
    if(!adc0)
    {
        printf("GetLastError %x\r\n", GetLastError());
        printf("ERROR - opening ADC0\r\n");
        return -1;
    }
    // get adc value at channel 26(temperature sensor)
    if(!DeviceIoControl(adc0, IOCTL_ADC_READ, &adcRead, sizeof(ADC_READ), &adcValue, sizeof(DWORD), &returned, NULL))
    {
        printf("GetLastError %x\r\n", GetLastError());
        printf("ERROR - Reading ADC value at channel %d\r\n", adcRead.channel);
        return -1;
    }
    temperature = 25 - ((adcValue*3.22 - tempSensor.vTemp25)/tempSensor.slopeCoefficient);// calculation to obtain temperature
    printf("Temperature is %2.2f 'C\r\n", temperature);
    CloseHandle(adc0);
    printf("Press Enter to exit \r\n");
    getchar();
    return 0;
}

Colibri/Apalis iMX6

This code can be used to read SOC temperature on iMX6-based modules

#include "windows.h"
#include "mapmem.h"
 
int _tmain(int argc, _TCHAR* argv[])
{
	// Init map mem lib
	HANDLE maphandle=Map_Init();
 
	// we need to map the OCOTPANA1 fuse to read calibration values
	volatile DWORD* ocotpana1;
 
	ocotpana1=(DWORD*)Map_MapMemory(0x021BC4E0,sizeof(DWORD));
 
	// split the value into room temperature (25C) value, hot value and hot reference temp
	DWORD roomcount,hotcount,hottemp;
 
	roomcount=*ocotpana1>>20;
	hotcount=(*ocotpana1>>8)&0x00000FFF;
	hottemp=*ocotpana1&0x000000FF;
 
	// map the TEMPMON registers (TEMPSENSE0 and TEMPSENSE1, both have separate registers to set,clear and toggle bits)
	volatile DWORD *tempsense0,*tempsense1;
	volatile DWORD *tempsense0set,*tempsense0clr,*tempsense0tog;
	volatile DWORD *tempsense1set,*tempsense1clr,*tempsense1tog;
 
	tempsense0=(DWORD*)Map_MapMemory(0x020C8180,8*sizeof(DWORD));
	tempsense0set=tempsense0+1;
	tempsense0clr=tempsense0+2;
	tempsense0tog=tempsense0+3;
 
	tempsense1=tempsense0+4;
	tempsense1set=tempsense1+1;
	tempsense1clr=tempsense1+2;
	tempsense1tog=tempsense1+3;
 
	// disable auto updates
	*tempsense1clr=0xFFFFFFFF;
 
	//set alarm to max value (we are not using the interrupt)
	*tempsense0set=0xFFF00000;
 
	// power-on sensor
	*tempsense0clr=0x00000001;
 
	// measure
	for (;;)
	{
		// clears start flag
		*tempsense0clr=0x00000002;
 
		_tprintf(TEXT("%08x\r\n"),*tempsense0);
 
		// start
		*tempsense0set=0x00000002;
		Sleep(1);
 
		// wait until measured value is valid
		while (!(*tempsense0 & 0x00000004))
			Sleep(1);
 
		_tprintf(TEXT("%08x\r\n"),*tempsense0);
 
		// calculate temperature in Celsius
		DWORD tempcount=(*tempsense0 >> 8) & 0x00000FFF;
		DWORD tmeas=(DWORD)((double)hottemp-(tempcount-hotcount)*((hottemp-25.0)/(roomcount-hotcount)));
 
		// print it out
		_tprintf(TEXT("Temperature: %d\r\n"),tmeas);
		RETAILMSG(1,(TEXT("Temperature: %d\r\n"),tmeas));
 
		// wait a second before doing a new measurement
		Sleep(1000);
	}
	return 0;
}

Download projects

You can download demo source code for Apalis/Colibri Txx from here, for Colibri VFxx from here and for Apalis/Colibri iMX6 from here.