Skip to content

Commit b251e78

Browse files
committed
samd: size-optimize microcontroller temp calc
Perform most arithmetic with scaled integer values. For my calibration values ``` const uint32_t NVMCTRL_TEMP_LOG[]={0xfc05511e, 0xcc7ac0f7}; ``` the maximum difference between the old and new calculation is 0.50°C. The difference is smallest (0.13°) at 25.87°C in the old scale. This reduces mcu_processor_get_temperature from 568 bytes to 348 bytes (-220 bytes)
1 parent e3688b4 commit b251e78

File tree

1 file changed

+34
-51
lines changed

1 file changed

+34
-51
lines changed

ports/atmel-samd/common-hal/microcontroller/Processor.c

Lines changed: 34 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -73,101 +73,84 @@
7373
#include "peripheral_clk_config.h"
7474

7575
#define ADC_TEMP_SAMPLE_LENGTH 4
76-
#define INT1V_VALUE_FLOAT 1.0
77-
#define INT1V_DIVIDER_1000 1000.0
78-
#define ADC_12BIT_FULL_SCALE_VALUE_FLOAT 4095.0
76+
#define INT1V_VALUE_FLOAT MICROPY_FLOAT_CONST(1.0)
77+
#define INT1V_DIVIDER_1000 MICROPY_FLOAT_CONST(1000.0)
78+
#define ADC_12BIT_FULL_SCALE_VALUE_FLOAT MICROPY_FLOAT_CONST(4095.0)
7979

8080
// channel argument (ignored in calls below)
8181
#define IGNORED_CHANNEL 0
8282

83-
// Decimal to fraction conversion. (adapted from ASF sample).
84-
STATIC float convert_dec_to_frac(uint8_t val) {
85-
float float_val = (float)val;
86-
if (val < 10) {
87-
return float_val / 10.0;
88-
} else if (val < 100) {
89-
return float_val / 100.0;
90-
} else {
91-
return float_val / 1000.0;
92-
}
93-
}
9483

9584
// Extract the production calibration data information from NVM (adapted from ASF sample),
9685
// then calculate the temperature
9786
#ifdef SAMD21
9887
STATIC float calculate_temperature(uint16_t raw_value) {
99-
volatile uint32_t val1; /* Temperature Log Row Content first 32 bits */
100-
volatile uint32_t val2; /* Temperature Log Row Content another 32 bits */
101-
uint8_t room_temp_val_int; /* Integer part of room temperature in °C */
102-
uint8_t room_temp_val_dec; /* Decimal part of room temperature in °C */
103-
uint8_t hot_temp_val_int; /* Integer part of hot temperature in °C */
104-
uint8_t hot_temp_val_dec; /* Decimal part of hot temperature in °C */
105-
int8_t room_int1v_val; /* internal 1V reference drift at room temperature */
106-
int8_t hot_int1v_val; /* internal 1V reference drift at hot temperature*/
107-
108-
float tempR; // Production Room temperature
109-
float tempH; // Production Hot temperature
110-
float INT1VR; // Room temp 2's complement of the internal 1V reference value
111-
float INT1VH; // Hot temp 2's complement of the internal 1V reference value
112-
uint16_t ADCR; // Production Room temperature ADC value
113-
uint16_t ADCH; // Production Hot temperature ADC value
114-
float VADCR; // Room temperature ADC voltage
115-
float VADCH; // Hot temperature ADC voltage
88+
uint32_t val1; /* Temperature Log Row Content first 32 bits */
89+
uint32_t val2; /* Temperature Log Row Content another 32 bits */
90+
int room_temp_val_int; /* Integer part of room temperature in °C */
91+
int room_temp_val_dec; /* Decimal part of room temperature in °C */
92+
int hot_temp_val_int; /* Integer part of hot temperature in °C */
93+
int hot_temp_val_dec; /* Decimal part of hot temperature in °C */
94+
int room_int1v_val; /* internal 1V reference drift at room temperature */
95+
int hot_int1v_val; /* internal 1V reference drift at hot temperature*/
11696

11797
uint32_t *temp_log_row_ptr = (uint32_t *)NVMCTRL_TEMP_LOG;
11898

11999
val1 = *temp_log_row_ptr;
120100
temp_log_row_ptr++;
121101
val2 = *temp_log_row_ptr;
122102

123-
room_temp_val_int = (uint8_t)((val1 & FUSES_ROOM_TEMP_VAL_INT_Msk) >> FUSES_ROOM_TEMP_VAL_INT_Pos);
124-
room_temp_val_dec = (uint8_t)((val1 & FUSES_ROOM_TEMP_VAL_DEC_Msk) >> FUSES_ROOM_TEMP_VAL_DEC_Pos);
103+
room_temp_val_int = ((val1 & FUSES_ROOM_TEMP_VAL_INT_Msk) >> FUSES_ROOM_TEMP_VAL_INT_Pos);
104+
room_temp_val_dec = ((val1 & FUSES_ROOM_TEMP_VAL_DEC_Msk) >> FUSES_ROOM_TEMP_VAL_DEC_Pos);
125105

126-
hot_temp_val_int = (uint8_t)((val1 & FUSES_HOT_TEMP_VAL_INT_Msk) >> FUSES_HOT_TEMP_VAL_INT_Pos);
127-
hot_temp_val_dec = (uint8_t)((val1 & FUSES_HOT_TEMP_VAL_DEC_Msk) >> FUSES_HOT_TEMP_VAL_DEC_Pos);
106+
hot_temp_val_int = ((val1 & FUSES_HOT_TEMP_VAL_INT_Msk) >> FUSES_HOT_TEMP_VAL_INT_Pos);
107+
hot_temp_val_dec = ((val1 & FUSES_HOT_TEMP_VAL_DEC_Msk) >> FUSES_HOT_TEMP_VAL_DEC_Pos);
128108

109+
// necessary casts: must interpret 8 bits as signed
129110
room_int1v_val = (int8_t)((val1 & FUSES_ROOM_INT1V_VAL_Msk) >> FUSES_ROOM_INT1V_VAL_Pos);
130111
hot_int1v_val = (int8_t)((val2 & FUSES_HOT_INT1V_VAL_Msk) >> FUSES_HOT_INT1V_VAL_Pos);
131112

132-
ADCR = (uint16_t)((val2 & FUSES_ROOM_ADC_VAL_Msk) >> FUSES_ROOM_ADC_VAL_Pos);
133-
ADCH = (uint16_t)((val2 & FUSES_HOT_ADC_VAL_Msk) >> FUSES_HOT_ADC_VAL_Pos);
113+
int ADCR = ((val2 & FUSES_ROOM_ADC_VAL_Msk) >> FUSES_ROOM_ADC_VAL_Pos);
114+
int ADCH = ((val2 & FUSES_HOT_ADC_VAL_Msk) >> FUSES_HOT_ADC_VAL_Pos);
134115

135-
tempR = room_temp_val_int + convert_dec_to_frac(room_temp_val_dec);
136-
tempH = hot_temp_val_int + convert_dec_to_frac(hot_temp_val_dec);
116+
int tempR = 10 * room_temp_val_int + room_temp_val_dec;
117+
int tempH = 10 * hot_temp_val_int + hot_temp_val_dec;
137118

138-
INT1VR = 1 - ((float)room_int1v_val / INT1V_DIVIDER_1000);
139-
INT1VH = 1 - ((float)hot_int1v_val / INT1V_DIVIDER_1000);
119+
int INT1VR = 1000 - room_int1v_val;
120+
int INT1VH = 1000 - hot_int1v_val;
140121

141-
VADCR = ((float)ADCR * INT1VR) / ADC_12BIT_FULL_SCALE_VALUE_FLOAT;
142-
VADCH = ((float)ADCH * INT1VH) / ADC_12BIT_FULL_SCALE_VALUE_FLOAT;
122+
int VADCR = ADCR * INT1VR;
123+
int VADCH = ADCH * INT1VH;
143124

144-
float VADC; /* Voltage calculation using ADC result for Coarse Temp calculation */
145-
float VADCM; /* Voltage calculation using ADC result for Fine Temp calculation. */
146-
float INT1VM; /* Voltage calculation for reality INT1V value during the ADC conversion */
125+
int INT1VM; /* Voltage calculation for reality INT1V value during the ADC conversion */
147126

148-
VADC = ((float)raw_value * INT1V_VALUE_FLOAT) / ADC_12BIT_FULL_SCALE_VALUE_FLOAT;
127+
int VADC = raw_value * 1000;
149128

150129
// Hopefully compiler will remove common subepxressions here.
151130

152131
// calculate fine temperature using Equation1 and Equation
153132
// 1b as mentioned in data sheet section "Temperature Sensor Characteristics"
154133
// of Electrical Characteristics. (adapted from ASF sample code).
155134
// Coarse Temp Calculation by assume INT1V=1V for this ADC conversion
156-
float coarse_temp = tempR + (((tempH - tempR) / (VADCH - VADCR)) * (VADC - VADCR));
135+
int coarse_temp = tempR + (tempH - tempR) * (VADC - VADCR) / (VADCH - VADCR);
157136

158137
// Calculation to find the real INT1V value during the ADC conversion
159138
INT1VM = INT1VR + (((INT1VH - INT1VR) * (coarse_temp - tempR)) / (tempH - tempR));
160139

161-
VADCM = ((float)raw_value * INT1VM) / ADC_12BIT_FULL_SCALE_VALUE_FLOAT;
140+
int VADCM = raw_value * INT1VM;
162141

163142
// Fine Temp Calculation by replace INT1V=1V by INT1V = INT1Vm for ADC conversion
164-
float fine_temp = tempR + (((tempH - tempR) / (VADCH - VADCR)) * (VADCM - VADCR));
143+
float fine_temp = tempR + (((tempH - tempR) * (VADCM - VADCR)) / (VADCH - VADCR));
165144

166-
return fine_temp;
145+
return fine_temp / 10;
167146
}
168147
#endif // SAMD21
169148

170149
#ifdef SAM_D5X_E5X
150+
// Decimal to fraction conversion. (adapted from ASF sample).
151+
STATIC float convert_dec_to_frac(uint8_t val) {
152+
return val / MICROPY_FLOAT_CONST(10.);
153+
}
171154
STATIC float calculate_temperature(uint16_t TP, uint16_t TC) {
172155
uint32_t TLI = (*(uint32_t *)FUSES_ROOM_TEMP_VAL_INT_ADDR & FUSES_ROOM_TEMP_VAL_INT_Msk) >> FUSES_ROOM_TEMP_VAL_INT_Pos;
173156
uint32_t TLD = (*(uint32_t *)FUSES_ROOM_TEMP_VAL_DEC_ADDR & FUSES_ROOM_TEMP_VAL_DEC_Msk) >> FUSES_ROOM_TEMP_VAL_DEC_Pos;

0 commit comments

Comments
 (0)