SoC Temperature Readout (WinCE)
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.