Skip to content

Commit bde7dad

Browse files
authored
Implement CPUTemperature() (#1225)
1 parent 06bdb99 commit bde7dad

File tree

11 files changed

+140
-12
lines changed

11 files changed

+140
-12
lines changed

hal/architecture/AVR/MyHwAVR.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,19 @@ uint16_t hwCPUFrequency(void)
334334

335335
int8_t hwCPUTemperature(void)
336336
{
337-
return -127; // not implemented yet
337+
#if defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328BP__) || defined(__AVR_ATmega32U4__)
338+
// Set the internal reference and mux.
339+
ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3));
340+
ADCSRA |= _BV(ADEN); // enable the ADC
341+
delay(20); // wait for voltages to become stable.
342+
ADCSRA |= _BV(ADSC); // Start the ADC
343+
// Wait until conversion done
344+
while (bit_is_set(ADCSRA, ADSC));
345+
// temperature is in degrees Celsius
346+
return static_cast<int8_t>((ADCW - MY_AVR_TEMPERATURE_OFFSET) / MY_AVR_TEMPERATURE_GAIN);
347+
#else
348+
return -127; // not available
349+
#endif
338350
}
339351

340352
uint16_t hwFreeMem(void)

hal/architecture/AVR/MyHwAVR.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@
4343
#define MY_DEBUGDEVICE MY_SERIALDEVICE
4444
#endif
4545

46+
// AVR temperature calibration reference: http://ww1.microchip.com/downloads/en/AppNotes/Atmel-8108-Calibration-of-the-AVRs-Internal-Temperature-Reference_ApplicationNote_AVR122.pdf
47+
#ifndef MY_AVR_TEMPERATURE_OFFSET
48+
#define MY_AVR_TEMPERATURE_OFFSET (324.31f)
49+
#endif
50+
51+
#ifndef MY_AVR_TEMPERATURE_GAIN
52+
#define MY_AVR_TEMPERATURE_GAIN (1.22f)
53+
#endif
54+
4655
// Define these as macros to save valuable space
4756
#define hwDigitalWrite(__pin, __value) digitalWriteFast(__pin, __value)
4857
#define hwDigitalRead(__pin) digitalReadFast(__pin)

hal/architecture/ESP32/MyHwESP32.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,9 @@ uint16_t hwCPUFrequency(void)
133133

134134
int8_t hwCPUTemperature(void)
135135
{
136-
return -127; // not implemented yet
136+
// CPU temperature in °C
137+
return static_cast<int8_t>((temperatureRead() - MY_ESP32_TEMPERATURE_OFFSET) /
138+
MY_ESP32_TEMPERATURE_GAIN);
137139
}
138140

139141
uint16_t hwFreeMem(void)

hal/architecture/ESP32/MyHwESP32.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@
5555
#define MY_DEBUGDEVICE MY_SERIALDEVICE
5656
#endif
5757

58+
#ifndef MY_ESP32_TEMPERATURE_OFFSET
59+
#define MY_ESP32_TEMPERATURE_OFFSET (0.0f)
60+
#endif
61+
62+
#ifndef MY_ESP32_TEMPERATURE_GAIN
63+
#define MY_ESP32_TEMPERATURE_GAIN (1.0f)
64+
#endif
65+
5866
#define MY_EEPROM_SIZE 1024
5967

6068
#define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value)

hal/architecture/ESP8266/MyHwESP8266.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ uint16_t hwCPUFrequency(void)
147147

148148
int8_t hwCPUTemperature(void)
149149
{
150-
return -127;
150+
return -127; // not available
151151
}
152152

153153
uint16_t hwFreeMem(void)

hal/architecture/Linux/MyHwLinuxGeneric.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ uint16_t hwCPUFrequency(void)
149149

150150
int8_t hwCPUTemperature(void)
151151
{
152-
return -127;
152+
return -127; // not implemented yet
153153
}
154154

155155
uint16_t hwFreeMem(void)

hal/architecture/MyHwHAL.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,14 @@ uint16_t hwCPUVoltage(void);
108108
uint16_t hwCPUFrequency(void);
109109

110110
/**
111-
* Non-calibrated CPU temperature (if available)
112-
* @return CPU temperature in °C
111+
* CPU temperature (if available)
112+
* Adjust calibration parameters via MY_<ARCH>_TEMPERATURE_OFFSET and MY_<ARCH>_TEMPERATURE_GAIN
113+
* @return CPU temperature in °C, -127 if not available
113114
*/
114115
int8_t hwCPUTemperature(void);
115116

116117
/**
117-
* Free memory
118+
* Report free memory (if function available)
118119
* @return free memory in bytes
119120
*/
120121
uint16_t hwFreeMem(void);

hal/architecture/SAMD/MyHwSAMD.cpp

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ bool hwInit(void)
7373
while (!MY_SERIALDEVICE) {}
7474
#endif
7575
#endif
76+
77+
SYSCTRL->VREF.reg |= SYSCTRL_VREF_TSEN; // Enable the temperature sensor
78+
while (ADC->STATUS.bit.SYNCBUSY ==
79+
1); // Wait for synchronization of registers between the clock domains
80+
7681
const uint8_t eepInit = eep.begin(MY_EXT_EEPROM_TWI_CLOCK, &Wire);
7782
#if defined(SENSEBENDER_GW_SAMD_V1)
7883
// check connection to external EEPROM - only sensebender GW
@@ -178,7 +183,68 @@ uint16_t hwCPUFrequency(void)
178183

179184
int8_t hwCPUTemperature(void)
180185
{
181-
return -127; // not implemented yet
186+
// taken from https://github.com/arduino/ArduinoCore-samd/pull/277
187+
// Set to 12 bits resolution
188+
ADC->CTRLB.reg = ADC_CTRLB_RESSEL_12BIT | ADC_CTRLB_PRESCALER_DIV256;
189+
syncADC();
190+
// Ensure we are sampling slowly
191+
ADC->SAMPCTRL.reg = ADC_SAMPCTRL_SAMPLEN(0x3f);
192+
syncADC();
193+
// Set ADC reference to internal 1v
194+
ADC->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val;
195+
ADC->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INT1V_Val;
196+
syncADC();
197+
// Select MUXPOS as temperature channel, and MUXNEG as internal ground
198+
ADC->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_TEMP_Val;
199+
ADC->INPUTCTRL.bit.MUXNEG = ADC_INPUTCTRL_MUXNEG_GND_Val;
200+
syncADC();
201+
// Enable ADC
202+
ADC->CTRLA.bit.ENABLE = 1;
203+
syncADC();
204+
// Start ADC conversion
205+
ADC->SWTRIG.bit.START = 1;
206+
// Clear the Data Ready flag
207+
ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY;
208+
syncADC();
209+
// Start conversion again, since The first conversion after the reference is changed must not be used.
210+
ADC->SWTRIG.bit.START = 1;
211+
// Wait until ADC conversion is done
212+
while (!(ADC->INTFLAG.bit.RESRDY));
213+
syncADC();
214+
// Get result
215+
// This is signed so that the math later is done signed
216+
const int32_t adcReading = ADC->RESULT.reg;
217+
// Clear result ready flag
218+
ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY;
219+
syncADC();
220+
// Disable ADC
221+
ADC->CTRLA.bit.ENABLE = 0;
222+
syncADC();
223+
// Factory room temperature readings
224+
const uint8_t roomInteger = (*(uint32_t *)FUSES_ROOM_TEMP_VAL_INT_ADDR &
225+
FUSES_ROOM_TEMP_VAL_INT_Msk)
226+
>> FUSES_ROOM_TEMP_VAL_INT_Pos;
227+
const uint8_t roomDecimal = (*(uint32_t *)FUSES_ROOM_TEMP_VAL_DEC_ADDR &
228+
FUSES_ROOM_TEMP_VAL_DEC_Msk)
229+
>> FUSES_ROOM_TEMP_VAL_DEC_Pos;
230+
const int32_t roomReading = ((*(uint32_t *)FUSES_ROOM_ADC_VAL_ADDR & FUSES_ROOM_ADC_VAL_Msk) >>
231+
FUSES_ROOM_ADC_VAL_Pos);
232+
const int32_t roomTemperature = 1000 * roomInteger + 100 * roomDecimal;
233+
// Factory hot temperature readings
234+
const uint8_t hotInteger = (*(uint32_t *)FUSES_HOT_TEMP_VAL_INT_ADDR & FUSES_HOT_TEMP_VAL_INT_Msk)
235+
>>
236+
FUSES_HOT_TEMP_VAL_INT_Pos;
237+
const uint8_t hotDecimal = (*(uint32_t *)FUSES_HOT_TEMP_VAL_DEC_ADDR & FUSES_HOT_TEMP_VAL_DEC_Msk)
238+
>>
239+
FUSES_HOT_TEMP_VAL_DEC_Pos;
240+
const int32_t hotReading = ((*(uint32_t *)FUSES_HOT_ADC_VAL_ADDR & FUSES_HOT_ADC_VAL_Msk) >>
241+
FUSES_HOT_ADC_VAL_Pos);
242+
const int32_t hotTemperature = 1000 * hotInteger + 100 * hotDecimal;
243+
// Linear interpolation of temperature using factory room temperature and hot temperature
244+
const int32_t temperature = roomTemperature + ((hotTemperature - roomTemperature) *
245+
(adcReading - roomReading)) / (hotReading - roomReading);
246+
return static_cast<int8_t>(((temperature / 1000) - MY_SAMD_TEMPERATURE_OFFSET) /
247+
MY_SAMD_TEMPERATURE_GAIN);
182248
}
183249

184250

hal/architecture/SAMD/MyHwSAMD.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@
3535
#define MY_DEBUGDEVICE MY_SERIALDEVICE
3636
#endif
3737

38+
#ifndef MY_SAMD_TEMPERATURE_OFFSET
39+
#define MY_SAMD_TEMPERATURE_OFFSET (0.0f)
40+
#endif
41+
42+
#ifndef MY_SAMD_TEMPERATURE_GAIN
43+
#define MY_SAMD_TEMPERATURE_GAIN (1.0f)
44+
#endif
45+
3846
// defines for sensebender gw variant.h
3947
#define MY_EXT_EEPROM_I2C_ADDRESS (0x50u)
4048
#define MY_EXT_EEPROM_SIZE (kbits_512)

hal/architecture/STM32F1/MyHwSTM32F1.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ bool hwInit(void)
5050
while (!MY_SERIALDEVICE) {}
5151
#endif
5252
#endif
53-
adc_calibrate(ADC1);
54-
5553
if (EEPROM.init() == EEPROM_OK) {
5654
uint16 cnt;
5755
EEPROM.count(&cnt);
@@ -146,6 +144,7 @@ void hwRandomNumberInit(void)
146144
seed ^= ( (newValue + hwMillis()) & 7) << i;
147145
}
148146
randomSeed(seed);
147+
regs->CR2 &= ~ADC_CR2_TSVREFE; // disable VREFINT and temp sensor
149148
}
150149

151150
bool hwUniqueID(unique_id_t *uniqueID)
@@ -159,7 +158,11 @@ uint16_t hwCPUVoltage(void)
159158
adc_reg_map *regs = ADC1->regs;
160159
regs->CR2 |= ADC_CR2_TSVREFE; // enable VREFINT and temp sensor
161160
regs->SMPR1 = ADC_SMPR1_SMP17; // sample rate for VREFINT ADC channel
162-
return 1200 * 4096 / adc_read(ADC1, 17);
161+
adc_calibrate(ADC1);
162+
163+
const uint16_t vdd = adc_read(ADC1, 17);
164+
regs->CR2 &= ~ADC_CR2_TSVREFE; // disable VREFINT and temp sensor
165+
return 1200 * 4096 / vdd;
163166
}
164167

165168
uint16_t hwCPUFrequency(void)
@@ -169,7 +172,18 @@ uint16_t hwCPUFrequency(void)
169172

170173
int8_t hwCPUTemperature(void)
171174
{
172-
return -127; // not implemented yet
175+
adc_reg_map *regs = ADC1->regs;
176+
regs->CR2 |= ADC_CR2_TSVREFE; // enable VREFINT and Temperature sensor
177+
regs->SMPR1 |= ADC_SMPR1_SMP16 | ADC_SMPR1_SMP17;
178+
adc_calibrate(ADC1);
179+
180+
//const uint16_t adc_temp = adc_read(ADC1, 16);
181+
//const uint16_t vref = 1200 * 4096 / adc_read(ADC1, 17);
182+
// calibrated at 25°C, ADC output = 1430mV, avg slope = 4.3mV / °C, increasing temp ~ lower voltage
183+
const int8_t temp = static_cast<int8_t>((1430.0 - (adc_read(ADC1, 16) * 1200 / adc_read(ADC1,
184+
17))) / 4.3 + 25.0);
185+
regs->CR2 &= ~ADC_CR2_TSVREFE; // disable VREFINT and temp sensor
186+
return (temp - MY_STM32F1_TEMPERATURE_OFFSET) / MY_STM32F1_TEMPERATURE_GAIN;
173187
}
174188

175189
uint16_t hwFreeMem(void)

0 commit comments

Comments
 (0)