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: ![STM32-Blue-Pill-DS18B20-Sensor-with-OLED-view-temperature-readings](https://hackmd.io/_uploads/HyYpmojalg.jpg) **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.