Calibrating the [temperature sensor](https://www.onzuu.com/category/temperature-sensors) on an [STM32](https://www.ampheo.com/search/STM32) IoT device (like the [B-L475E-IOT01A](https://www.onzuu.com/search/B-L475E-IOT01A) with [HTS221](https://www.ampheo.com/product/hts221tr-26836612) or similar boards) is crucial for accurate readings. Here's a comprehensive guide:

**Types of STM32 Temperature Sensors**
**1. Internal Die Temperature Sensor**
* Built into the STM32 MCU core
* Measures the chip's junction temperature
* Less accurate (± few °C) but useful for monitoring chip temperature
**2. External Humidity/Temperature Sensors (HTS221 on IoT Node)**
* More accurate for ambient temperature
* Typically ±0.5°C accuracy (can be improved with calibration)
3. Dedicated Temperature ICs (if connected externally)
**Method 1: Calibrating the Internal Die Sensor**
The internal sensor requires a 2-point calibration for reasonable accuracy.
**Calibration Procedure:**
**1. Read the Factory Calibration Data**
STM32 chips have factory-calibrated temperature values stored in system memory.
```
c
// For STM32L4 series (check your reference manual for addresses)
#define TEMP30_CAL_ADDR ((uint16_t*) ((void*) 0x1FFF75A8))
#define TEMP130_CAL_ADDR ((uint16_t*) ((void*) 0x1FFF75CA))
#define VREFINT_CAL_ADDR ((uint16_t*) ((void*) 0x1FFF75AA))
// Read calibration values
uint16_t temp30_cal = *TEMP30_CAL_ADDR;
uint16_t temp130_cal = *TEMP130_CAL_ADDR;
uint16_t vrefint_cal = *VREFINT_CAL_ADDR;
```
**2. Implementation Code**
```
c
float read_calibrated_internal_temp(ADC_HandleTypeDef* hadc) {
uint32_t vrefint_raw, tsense_raw;
float temperature;
// Read VREFINT and temperature sensor
HAL_ADC_Start(hadc);
vrefint_raw = read_adc_channel(hadc, ADC_CHANNEL_VREFINT);
tsense_raw = read_adc_channel(hadc, ADC_CHANNEL_TEMPSENSOR);
HAL_ADC_Stop(hadc);
// Calculate actual VREFINT voltage (from calibration)
float vrefint_voltage = (3.0f * vrefint_cal) / vrefint_raw;
// Calculate temperature using 2-point calibration
temperature = ((float)(tsense_raw - temp30_cal))
* (130.0f - 30.0f)
/ (temp130_cal - temp30_cal)
+ 30.0f;
return temperature;
}
```
**Method 2: Calibrating External HTS221 Sensor (STM32 IoT Node)**
The HTS221 humidity/temperature sensor is much more accurate and easier to calibrate.
**One-Point Offset Calibration:**
**1. Reference Measurement**
* Use a calibrated, accurate thermometer as reference
* Place both [sensors](https://www.ampheo.com/c/sensors) in a stable temperature environment
* Wait for temperatures to stabilize (15-30 minutes)
**2. Calculate Offset**
```
c
// Pseudo-code for offset calculation
float reference_temp = 23.5f; // From calibrated thermometer
float hts221_temp = read_hts221_temperature(); // Raw reading
// Calculate calibration offset
float temp_offset = reference_temp - hts221_temp;
// Store this offset in non-volatile memory
store_calibration_data(temp_offset, 0, 0); // Store offset, 0, 0 for 1-point cal
```
**3. Apply Calibration**
```
c
float read_calibrated_temperature(void) {
float raw_temp = read_hts221_temperature();
float temp_offset = load_temp_offset(); // Load from Flash/EEPROM
return raw_temp + temp_offset;
}
```
**Two-Point Calibration (More Accurate):**
**1. Take measurements at two different known temperatures**
```
c
// Calibration at point 1 (e.g., room temperature)
float ref_temp1 = 25.0f;
float raw_temp1 = read_hts221_temperature();
// Calibration at point 2 (e.g., warmer environment)
float ref_temp2 = 35.0f;
float raw_temp2 = read_hts221_temperature();
// Calculate gain and offset
float gain = (ref_temp2 - ref_temp1) / (raw_temp2 - raw_temp1);
float offset = ref_temp1 - (raw_temp1 * gain);
```
**2. Apply Two-Point Calibration**
```
c
float apply_two_point_calibration(float raw_temp) {
float gain = load_temp_gain();
float offset = load_temp_offset();
return (raw_temp * gain) + offset;
}
```
**Method 3: Multi-Point Calibration with Curve Fitting**
For highest accuracy across a wide temperature range:
```
c
// Take multiple reference points
typedef struct {
float reference_temp;
float sensor_reading;
} cal_point_t;
// Example calibration points
cal_point_t cal_points[] = {
{15.0f, 14.8f},
{25.0f, 24.7f},
{35.0f, 34.6f},
{45.0f, 44.4f}
};
// Calculate polynomial coefficients (linear fit for simplicity)
void calculate_calibration_coefficients(float* slope, float* intercept) {
float sum_x = 0, sum_y = 0, sum_xy = 0, sum_xx = 0;
int n = sizeof(cal_points) / sizeof(cal_points[0]);
for (int i = 0; i < n; i++) {
sum_x += cal_points[i].sensor_reading;
sum_y += cal_points[i].reference_temp;
sum_xy += cal_points[i].sensor_reading * cal_points[i].reference_temp;
sum_xx += cal_points[i].sensor_reading * cal_points[i].sensor_reading;
}
*slope = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x);
*intercept = (sum_y - *slope * sum_x) / n;
}
```
**Complete Implementation for STM32 IoT Node**
**HTS221 Calibration Example:**
```
c
#include "hts221.h"
#include "stdio.h"
// Calibration structure
typedef struct {
float temp_offset;
float temp_gain;
uint8_t calibrated;
} temp_calibration_t;
temp_calibration_t temp_cal = {0.0f, 1.0f, 0};
void calibrate_temperature_sensor(float known_reference_temp) {
float raw_temp;
float temp_sum = 0;
int num_samples = 100;
// Take multiple samples for stability
for (int i = 0; i < num_samples; i++) {
HTS221_GetTemperature(&raw_temp);
temp_sum += raw_temp;
HAL_Delay(100);
}
float avg_raw_temp = temp_sum / num_samples;
// Simple one-point offset calibration
temp_cal.temp_offset = known_reference_temp - avg_raw_temp;
temp_cal.calibrated = 1;
printf("Calibration complete:\n");
printf("Reference: %.2f°C, Sensor: %.2f°C, Offset: %.2f°C\n",
known_reference_temp, avg_raw_temp, temp_cal.temp_offset);
// Save to Flash
save_calibration_data();
}
float read_calibrated_temperature(void) {
float raw_temp;
HTS221_GetTemperature(&raw_temp);
if (temp_cal.calibrated) {
return raw_temp + temp_cal.temp_offset;
} else {
return raw_temp; // Return uncalibrated with warning
}
}
```
**Storage in Flash Memory:**
```
c
#define CALIBRATION_FLASH_ADDR 0x0801F000 // Last sector of Flash
void save_calibration_data(void) {
HAL_FLASH_Unlock();
// Erase page
FLASH_EraseInitTypeDef erase;
erase.TypeErase = FLASH_TYPEERASE_PAGES;
erase.Page = 127; // Adjust for your MCU
erase.NbPages = 1;
uint32_t error;
HAL_FLASHEx_Erase(&erase, &error);
// Write data
uint32_t* data = (uint32_t*)&temp_cal;
for (int i = 0; i < sizeof(temp_cal)/4; i++) {
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
CALIBRATION_FLASH_ADDR + i*4,
data[i]);
}
HAL_FLASH_Lock();
}
void load_calibration_data(void) {
temp_calibration_t* stored_cal = (temp_calibration_t*)CALIBRATION_FLASH_ADDR;
if (stored_cal->calibrated == 1) {
temp_cal = *stored_cal;
printf("Loaded calibration: offset=%.2f, gain=%.2f\n",
temp_cal.temp_offset, temp_cal.temp_gain);
}
}
```
**Practical Calibration Setup**
**Equipment Needed:**
1. Reference thermometer (accurate to ±0.1°C or better)
2. Temperature-controlled environment (or stable room temperature)
3. Thermal insulation to ensure both sensors at same temperature
4. Adequate stabilization time (15-30 minutes)
**Calibration Process:**
1. Place sensors in close thermal contact
2. Wait for stabilization - minimum 15 minutes
3. Record reference temperature
4. Take multiple sensor readings (average them)
5. Calculate calibration parameters
6. Store parameters in non-volatile memory
7. Verify with a different known temperature
**Environmental Considerations:**
* Avoid self-heating: Don't place sensors near MCU or other heat sources
* Ensure good airflow for ambient temperature sensing
* Avoid direct sunlight or heat sources
* Allow thermal stabilization after power-on
**Validation and Testing**
```
c
void validate_calibration(void) {
printf("Calibration Validation:\n");
printf("======================\n");
for (int i = 0; i < 10; i++) {
float cal_temp = read_calibrated_temperature();
printf("Reading %d: %.2f°C\n", i+1, cal_temp);
HAL_Delay(1000);
}
// Check stability
float min_temp = 100.0f, max_temp = -100.0f, sum = 0;
for (int i = 0; i < 50; i++) {
float temp = read_calibrated_temperature();
min_temp = fminf(min_temp, temp);
max_temp = fmaxf(max_temp, temp);
sum += temp;
HAL_Delay(200);
}
printf("Stability: Min=%.2f°C, Max=%.2f°C, Avg=%.2f°C\n",
min_temp, max_temp, sum/50);
}
```
This approach will significantly improve your [STM32](https://www.ampheoelec.de/search/STM32) IoT device's temperature measurement accuracy, typically achieving ±0.5°C accuracy or better with proper calibration.