|
14 | 14 | #include <zephyr/drivers/i2c.h>
|
15 | 15 | #include <stdio.h>
|
16 | 16 | #include <stdlib.h>
|
| 17 | +#include <zephyr/sys/util.h> |
17 | 18 | #include "si7006.h"
|
18 | 19 | #include <zephyr/logging/log.h>
|
19 | 20 |
|
@@ -112,25 +113,58 @@ static int si7006_channel_get(const struct device *dev,
|
112 | 113 | struct si7006_data *si_data = dev->data;
|
113 | 114 |
|
114 | 115 | if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
|
115 |
| - |
116 |
| - int32_t temp_ucelcius = (((17572 * (int32_t)si_data->temperature) |
117 |
| - / 65536) - 4685) * 10000; |
118 |
| - |
119 |
| - val->val1 = temp_ucelcius / 1000000; |
120 |
| - val->val2 = temp_ucelcius % 1000000; |
121 |
| - |
122 |
| - LOG_DBG("temperature = val1:%d, val2:%d", val->val1, val->val2); |
| 116 | + /* Raw formula: (temp * 175.72) / 65536 - 46.85 |
| 117 | + * To use integer math, scale the 175.72 factor by 128 and move the offset to |
| 118 | + * inside the division. This gives us: |
| 119 | + * |
| 120 | + * (temp * 175.72 * 128 - 46.86 * 128 * 65536) / (65536 * 128) |
| 121 | + * The constants can be calculated now: |
| 122 | + * (temp * 22492 - 393006285) / 2^23 |
| 123 | + * |
| 124 | + * There is a very small amount of round-off error in the factor of 22492. To |
| 125 | + * compenstate, a constant of 5246 is used to center the error about 0, thus |
| 126 | + * reducing the overall MSE. |
| 127 | + */ |
| 128 | + |
| 129 | + /* Temperature value times two to the 23rd power, i.e. temp_23 = temp << 23 */ |
| 130 | + const int32_t temp_23 = si_data->temperature * 22492 - (393006285 - 5246); |
| 131 | + /* Integer component of temperature */ |
| 132 | + int32_t temp_int = temp_23 >> 23; |
| 133 | + /* Fractional component of temperature */ |
| 134 | + int32_t temp_frac = temp_23 & BIT_MASK(23); |
| 135 | + |
| 136 | + /* Deal with the split twos-complement / BCD format oddness with negatives */ |
| 137 | + if (temp_23 < 0) { |
| 138 | + temp_int += 1; |
| 139 | + temp_frac -= BIT(23); |
| 140 | + } |
| 141 | + val->val1 = temp_int; |
| 142 | + /* Remove a constant factor of 64 from (temp_frac * 1000000) >> 23 */ |
| 143 | + val->val2 = (temp_frac * 15625ULL) >> 17; |
| 144 | + |
| 145 | + LOG_DBG("temperature %u = val1:%d, val2:%d", si_data->temperature, |
| 146 | + val->val1, val->val2); |
123 | 147 |
|
124 | 148 | return 0;
|
125 | 149 | } else if (chan == SENSOR_CHAN_HUMIDITY) {
|
126 |
| - |
127 |
| - int32_t relative_humidity = (((125 * (int32_t)si_data->humidity) |
128 |
| - / 65536) - 6) * 1000000; |
129 |
| - |
130 |
| - val->val1 = relative_humidity / 1000000; |
131 |
| - val->val2 = relative_humidity % 1000000; |
132 |
| - |
133 |
| - LOG_DBG("humidity = val1:%d, val2:%d", val->val1, val->val2); |
| 150 | + /* Humidity times two to the 16th power. Offset of -6 not applied yet. */ |
| 151 | + const uint32_t rh_16 = si_data->humidity * 125U; |
| 152 | + /* Integer component of humidity */ |
| 153 | + const int16_t rh_int = rh_16 >> 16; |
| 154 | + /* Fraction component of humidity */ |
| 155 | + const uint16_t rh_frac = rh_16 & BIT_MASK(16); |
| 156 | + |
| 157 | + val->val1 = rh_int - 6; /* Apply offset now */ |
| 158 | + /* Remove a constant factor of 64 from (rh_frac * 1000000) >> 16 */ |
| 159 | + val->val2 = (rh_frac * 15625) >> 10; |
| 160 | + |
| 161 | + /* Deal with the split twos-complement / BCD format oddness with negatives */ |
| 162 | + if (val->val1 < 0) { |
| 163 | + val->val1 += 1; |
| 164 | + val->val2 -= 1000000; |
| 165 | + } |
| 166 | + |
| 167 | + LOG_DBG("humidity %u = val1:%d, val2:%d", si_data->humidity, val->val1, val->val2); |
134 | 168 |
|
135 | 169 | return 0;
|
136 | 170 | } else {
|
|
0 commit comments