|
73 | 73 | #include "peripheral_clk_config.h"
|
74 | 74 |
|
75 | 75 | #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) |
79 | 79 |
|
80 | 80 | // channel argument (ignored in calls below)
|
81 | 81 | #define IGNORED_CHANNEL 0
|
82 | 82 |
|
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 |
| -} |
94 | 83 |
|
95 | 84 | // Extract the production calibration data information from NVM (adapted from ASF sample),
|
96 | 85 | // then calculate the temperature
|
| 86 | +// |
| 87 | +// This code performs almost all operations with scaled integers. For |
| 88 | +// instance, tempR is in units of 1/10°C, INT1VR is in units of 1mV, etc, |
| 89 | +// This is important to reduce the code size of the function. The effect on |
| 90 | +// precision is a ~.9°C difference vs the floating point algorithm on an |
| 91 | +// approximate 0..60°C range with a difference of ~.5°C at 25°C. When the fine |
| 92 | +// calculation step is skipped, the additional error approximately doubles. |
| 93 | +// |
| 94 | +// To save code size, rounding is neglected. However, trying to add back rounding |
| 95 | +// (by computing (a + b/2) / b instead of just a / b) actually didn't help |
| 96 | +// accuracy anyway. |
97 | 97 | #ifdef SAMD21
|
98 | 98 | 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 |
| 99 | + uint32_t val1; /* Temperature Log Row Content first 32 bits */ |
| 100 | + uint32_t val2; /* Temperature Log Row Content another 32 bits */ |
| 101 | + int room_temp_val_int; /* Integer part of room temperature in °C */ |
| 102 | + int room_temp_val_dec; /* Decimal part of room temperature in °C */ |
| 103 | + int hot_temp_val_int; /* Integer part of hot temperature in °C */ |
| 104 | + int hot_temp_val_dec; /* Decimal part of hot temperature in °C */ |
| 105 | + int room_int1v_val; /* internal 1V reference drift at room temperature */ |
| 106 | + int hot_int1v_val; /* internal 1V reference drift at hot temperature*/ |
116 | 107 |
|
117 | 108 | uint32_t *temp_log_row_ptr = (uint32_t *)NVMCTRL_TEMP_LOG;
|
118 | 109 |
|
119 | 110 | val1 = *temp_log_row_ptr;
|
120 | 111 | temp_log_row_ptr++;
|
121 | 112 | val2 = *temp_log_row_ptr;
|
122 | 113 |
|
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); |
| 114 | + room_temp_val_int = ((val1 & FUSES_ROOM_TEMP_VAL_INT_Msk) >> FUSES_ROOM_TEMP_VAL_INT_Pos); |
| 115 | + room_temp_val_dec = ((val1 & FUSES_ROOM_TEMP_VAL_DEC_Msk) >> FUSES_ROOM_TEMP_VAL_DEC_Pos); |
125 | 116 |
|
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); |
| 117 | + hot_temp_val_int = ((val1 & FUSES_HOT_TEMP_VAL_INT_Msk) >> FUSES_HOT_TEMP_VAL_INT_Pos); |
| 118 | + hot_temp_val_dec = ((val1 & FUSES_HOT_TEMP_VAL_DEC_Msk) >> FUSES_HOT_TEMP_VAL_DEC_Pos); |
128 | 119 |
|
| 120 | + // necessary casts: must interpret 8 bits as signed |
129 | 121 | room_int1v_val = (int8_t)((val1 & FUSES_ROOM_INT1V_VAL_Msk) >> FUSES_ROOM_INT1V_VAL_Pos);
|
130 | 122 | hot_int1v_val = (int8_t)((val2 & FUSES_HOT_INT1V_VAL_Msk) >> FUSES_HOT_INT1V_VAL_Pos);
|
131 | 123 |
|
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); |
134 |
| - |
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); |
| 124 | + int ADCR = ((val2 & FUSES_ROOM_ADC_VAL_Msk) >> FUSES_ROOM_ADC_VAL_Pos); |
| 125 | + int ADCH = ((val2 & FUSES_HOT_ADC_VAL_Msk) >> FUSES_HOT_ADC_VAL_Pos); |
137 | 126 |
|
138 |
| - INT1VR = 1 - ((float)room_int1v_val / INT1V_DIVIDER_1000); |
139 |
| - INT1VH = 1 - ((float)hot_int1v_val / INT1V_DIVIDER_1000); |
| 127 | + int tempR = 10 * room_temp_val_int + room_temp_val_dec; |
| 128 | + int tempH = 10 * hot_temp_val_int + hot_temp_val_dec; |
140 | 129 |
|
141 |
| - VADCR = ((float)ADCR * INT1VR) / ADC_12BIT_FULL_SCALE_VALUE_FLOAT; |
142 |
| - VADCH = ((float)ADCH * INT1VH) / ADC_12BIT_FULL_SCALE_VALUE_FLOAT; |
| 130 | + int INT1VR = 1000 - room_int1v_val; |
| 131 | + int INT1VH = 1000 - hot_int1v_val; |
143 | 132 |
|
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 */ |
| 133 | + int VADCR = ADCR * INT1VR; |
| 134 | + int VADCH = ADCH * INT1VH; |
147 | 135 |
|
148 |
| - VADC = ((float)raw_value * INT1V_VALUE_FLOAT) / ADC_12BIT_FULL_SCALE_VALUE_FLOAT; |
| 136 | + int VADC = raw_value * 1000; |
149 | 137 |
|
150 | 138 | // Hopefully compiler will remove common subepxressions here.
|
151 | 139 |
|
152 | 140 | // calculate fine temperature using Equation1 and Equation
|
153 | 141 | // 1b as mentioned in data sheet section "Temperature Sensor Characteristics"
|
154 | 142 | // of Electrical Characteristics. (adapted from ASF sample code).
|
155 | 143 | // Coarse Temp Calculation by assume INT1V=1V for this ADC conversion
|
156 |
| - float coarse_temp = tempR + (((tempH - tempR) / (VADCH - VADCR)) * (VADC - VADCR)); |
| 144 | + int coarse_temp = tempR + (tempH - tempR) * (VADC - VADCR) / (VADCH - VADCR); |
157 | 145 |
|
| 146 | + #if CIRCUITPY_FULL_BUILD |
158 | 147 | // Calculation to find the real INT1V value during the ADC conversion
|
| 148 | + int INT1VM; /* Voltage calculation for reality INT1V value during the ADC conversion */ |
| 149 | + |
159 | 150 | INT1VM = INT1VR + (((INT1VH - INT1VR) * (coarse_temp - tempR)) / (tempH - tempR));
|
160 | 151 |
|
161 |
| - VADCM = ((float)raw_value * INT1VM) / ADC_12BIT_FULL_SCALE_VALUE_FLOAT; |
| 152 | + int VADCM = raw_value * INT1VM; |
162 | 153 |
|
163 | 154 | // Fine Temp Calculation by replace INT1V=1V by INT1V = INT1Vm for ADC conversion
|
164 |
| - float fine_temp = tempR + (((tempH - tempR) / (VADCH - VADCR)) * (VADCM - VADCR)); |
| 155 | + float fine_temp = tempR + (((tempH - tempR) * (VADCM - VADCR)) / (VADCH - VADCR)); |
165 | 156 |
|
166 |
| - return fine_temp; |
| 157 | + return fine_temp / 10; |
| 158 | + #else |
| 159 | + return coarse_temp / 10.; |
| 160 | + #endif |
167 | 161 | }
|
168 | 162 | #endif // SAMD21
|
169 | 163 |
|
170 | 164 | #ifdef SAM_D5X_E5X
|
| 165 | +// Decimal to fraction conversion. (adapted from ASF sample). |
| 166 | +STATIC float convert_dec_to_frac(uint8_t val) { |
| 167 | + return val / MICROPY_FLOAT_CONST(10.); |
| 168 | +} |
171 | 169 | STATIC float calculate_temperature(uint16_t TP, uint16_t TC) {
|
172 | 170 | uint32_t TLI = (*(uint32_t *)FUSES_ROOM_TEMP_VAL_INT_ADDR & FUSES_ROOM_TEMP_VAL_INT_Msk) >> FUSES_ROOM_TEMP_VAL_INT_Pos;
|
173 | 171 | 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