Guten Morgen,
ich hab ein hartnäckiges Problem mit dem STM32-internen
Temperatursensor.
Dieser liefert kontinuierlich Werte, die ca 10°C zu hoch sind.
Meine Initialisierung:
1 | static void MX_ADC_Init(void) {
|
2 | __HAL_RCC_ADC1_CLK_ENABLE();
|
3 |
|
4 | ADC_ChannelConfTypeDef sConfig = { 0 };
|
5 | hadc.Instance = ADC1;
|
6 | hadc.Init.OversamplingMode = DISABLE;
|
7 | hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
|
8 | hadc.Init.Resolution = ADC_RESOLUTION_12B;
|
9 | hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
|
10 | hadc.Init.SamplingTime = ADC_SAMPLETIME_160CYCLES_5;
|
11 | hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
|
12 | hadc.Init.ContinuousConvMode = DISABLE;
|
13 | hadc.Init.DiscontinuousConvMode = ENABLE;
|
14 | hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
|
15 | hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
|
16 | hadc.Init.DMAContinuousRequests = DISABLE;
|
17 | hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
|
18 | hadc.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
|
19 | hadc.Init.LowPowerAutoWait = DISABLE;
|
20 | hadc.Init.LowPowerFrequencyMode = DISABLE;
|
21 | hadc.Init.LowPowerAutoPowerOff = DISABLE;
|
22 | if (HAL_ADC_Init(&hadc) != HAL_OK) {
|
23 | Error_Handler();
|
24 | }
|
25 | /**Configure for the selected ADC regular channel to be converted.
|
26 | */
|
27 | sConfig.Channel = ADC_CHANNEL_0;
|
28 | sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
|
29 |
|
30 | if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) {
|
31 | Error_Handler();
|
32 | }
|
33 | /**Configure for the selected ADC regular channel to be converted.
|
34 | */
|
35 | sConfig.Channel = ADC_CHANNEL_1;
|
36 | if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) {
|
37 | Error_Handler();
|
38 | }
|
39 | /**Configure for the selected ADC regular channel to be converted.
|
40 | */
|
41 | sConfig.Channel = ADC_CHANNEL_VREFINT; //Initialize VREFINT_CAL reference voltage
|
42 | sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
|
43 | if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
|
44 | {
|
45 | Error_Handler();
|
46 | }
|
47 |
|
48 | sConfig.Channel = ADC_CHANNEL_TEMPSENSOR; // Initialize the chip temperature sensor
|
49 | sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
|
50 | if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
|
51 | {
|
52 | Error_Handler();
|
53 | }
|
54 |
|
55 | HAL_ADCEx_EnableVREFINT();
|
56 | HAL_ADCEx_EnableVREFINTTempSensor();
|
57 | }
|
Zur Umrechnung der ADC-Werte hab ich die Code-Snippts aus dem Reference
Manual und auch aus Example-Projekten aus dem STM32Cube Repository für
die L0.
1 | #define TEMP30_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FF8007A)) /* Internal temperature sensor, parameter TS_CAL1: TS ADC raw data acquired at a temperature of 30 DegC (+-5 DegC), VDDA = 3.3 V (+-10 mV). */
|
2 | #define TEMP130_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FF8007E)) /* Internal temperature sensor, parameter TS_CAL2: TS ADC raw data acquired at a temperature of 130 DegC (+-5 DegC), VDDA = 3.3 V (+-10 mV). */
|
3 |
|
4 | #define VDDA_APPLI ((uint32_t) 3300) /* Value of analog voltage supply Vdda (unit: mV) */
|
5 | #define VDDA_TEMP_CAL ((uint32_t) 3000) /* Vdda value with which temperature sensor has been calibrated in production (+-10 mV). */
|
6 |
|
7 | /* Private macro -------------------------------------------------------------*/
|
8 | /**
|
9 | * @brief Computation of temperature (unit: degree Celsius) from the internal
|
10 | * temperature sensor measurement by ADC.
|
11 | * Computation is using temperature sensor calibration values done
|
12 | * in production.
|
13 | * Computation formula:
|
14 | * Temperature = (TS_ADC_DATA - TS_CAL1) * (130degC - 30degC)
|
15 | * / (TS_CAL2 - TS_CAL1) + 30degC
|
16 | * with TS_ADC_DATA = temperature sensor raw data measured by ADC
|
17 | * Avg_Slope = (TS_CAL2 - TS_CAL1) / (130 - 30)
|
18 | * TS_CAL1 = TS_ADC_DATA @30degC (calibrated in factory)
|
19 | * TS_CAL2 = TS_ADC_DATA @130degC (calibrated in factory)
|
20 | * Calculation validity conditioned to settings:
|
21 | * - ADC resolution 12 bits (need to scale conversion value
|
22 | * if using a different resolution).
|
23 | * - Power supply of analog voltage set to literal VDDA_APPLI
|
24 | * (need to scale value if using a different value of analog
|
25 | * voltage supply).
|
26 | * @param TS_ADC_DATA: Temperature sensor digital value measured by ADC
|
27 | * @retval None
|
28 | */
|
29 | #define COMPUTATION_TEMPERATURE_TEMP30_TEMP130(TS_ADC_DATA) \
|
30 | (((( ((int32_t)((TS_ADC_DATA * VDDA_APPLI) / VDDA_TEMP_CAL) \
|
31 | - (int32_t) *TEMP30_CAL_ADDR) \
|
32 | ) * (int32_t)(130 - 30) \
|
33 | ) / (int32_t)(*TEMP130_CAL_ADDR - *TEMP30_CAL_ADDR) \
|
34 | ) + 30 \
|
35 | )
|
Eigentlich kann man doch da nicht viel falsch machen - statt 25°C
erhalte ich Werte, die rund 10°C höher sind.
Ich kann mir beim besten Willen nicht vorstellen, dass ich die
Temperatur meines µCs um 10°C falsch einschätze.
Mein ADC wird mit 3,3V bepowert - das ist aber in der Umrechnung von als
VDD_APPLI einberechnet.
ADC Kalibrierung kann es nicht sein, weil ich auch eine
Batterie-Spannungsmessung eingebaut hab, die auf 5mV genau misst.
Hat jemand ähnliche Probleme mal festgestellt?
Viele Grüße,
Mampf
*edit*: Die beiden Kalibrierwerte:
658 für 30°C bei 3,0Vadc entspricht 598 @ 3,3Vadc
931 für 130°C bei 3,0Vadc entspricht 846 @ 3,3Vadc
ADC hat gelesen: 612 bei 3,3Vadc
Das wären definitiv mehr als 30°C
m = (130-30)/(846-598) = 0,40322
t = 30 - 0,40322 * 598 = -211,12556
Temp = 612 * 0,40322 - 211,12556 = 35,645°C
Hmm, kann da keinen Fehler entdecken.
*edit2*: Die slope (über die Kalibrierwerte) ist außerhalb des
max-Wertes: 1,81mv/°C
Angegeben ist: 1,48 (min), 1,61 (typ), 1.75 (max).
Das ist ja seltsam ...