This article demonstrates how to read Colibri/Apalis internal Soc temperature.
PXAxxx processors do not have internal temperature sensors. External temperature sensor must be added to the carrier board if temperature measurements are required.
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); }
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; }
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; }
You can download demo source code for Apalis/Colibri Txx from here, for Colibri VFxx from here and for Apalis/Colibri iMX6 from here.