M5Unit-ENV 1.6.0 git rev:f6fd6b0
Loading...
Searching...
No Matches
unit_SPA06_data.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
3 *
4 * SPDX-License-Identifier: MIT
5 */
13#ifndef M5_UNIT_ENV_UNIT_SPA06_DATA_HPP
14#define M5_UNIT_ENV_UNIT_SPA06_DATA_HPP
15
16#include <array>
17#include <cstdint>
18#include <cmath>
19#include <limits>
20
21namespace m5 {
22namespace unit {
23namespace spa06 {
24
29enum class Oversampling : uint8_t {
30 X1,
31 X2,
32 X4,
33 X8,
34 X16,
35 X32,
36 X64,
37 X128,
38};
39
44enum class Rate : uint8_t {
45 Rate1,
46 Rate2,
47 Rate4,
48 Rate8,
49 Rate16,
50 Rate32,
51 Rate64,
52 Rate128,
53};
54
59enum class Mode : uint8_t {
60 Pressure = 0x05,
61 Temperature = 0x06,
63};
64
66inline float scale_factor(const Oversampling oversampling)
67{
68 switch (oversampling) {
69 case Oversampling::X1:
70 return 524288.0f;
71 case Oversampling::X2:
72 return 1572864.0f;
73 case Oversampling::X4:
74 return 3670016.0f;
75 case Oversampling::X8:
76 return 7864320.0f;
77 case Oversampling::X16:
78 return 253952.0f;
79 case Oversampling::X32:
80 return 516096.0f;
81 case Oversampling::X64:
82 return 1040384.0f;
83 case Oversampling::X128:
84 return 2088960.0f;
85 }
86 return std::numeric_limits<float>::quiet_NaN(); // Out-of-range enum value
87}
88
90inline uint32_t measurement_time_x10(const Oversampling oversampling)
91{
92 constexpr uint32_t t[] = {36, 52, 84, 148, 276, 532, 1044, 2068};
93 return t[static_cast<uint8_t>(oversampling)];
94}
95
102inline bool valid_combination(const Oversampling osrs_p, const Oversampling osrs_t, const Rate rate, const Mode mode)
103{
104 const uint32_t r = static_cast<uint32_t>(1) << static_cast<uint8_t>(rate); // measurements per second
105 uint32_t budget_x10{};
106 switch (mode) {
107 case Mode::Pressure:
108 budget_x10 = measurement_time_x10(osrs_p);
109 break;
110 case Mode::Temperature:
111 budget_x10 = measurement_time_x10(osrs_t);
112 break;
113 case Mode::PressureAndTemperature:
114 budget_x10 = measurement_time_x10(osrs_p) + measurement_time_x10(osrs_t);
115 break;
116 }
117 return r * budget_x10 < 10000u; // < 1000 ms (values are ms x10)
118}
119
121constexpr int32_t NOT_MEASURED{-8388608};
122
124inline int32_t sign_extend(const uint32_t v, const uint8_t bits)
125{
126 const uint32_t m = static_cast<uint32_t>(1) << (bits - 1);
127 return static_cast<int32_t>((v ^ m) - m);
128}
129
131struct coeffs_t {
132 int32_t c0{}, c1{};
133 int32_t c00{}, c10{};
134 int32_t c01{}, c11{}, c20{}, c21{}, c30{};
135 int32_t c31{}, c40{};
136};
137
139inline coeffs_t parse_coeffs(const std::array<uint8_t, 21>& r)
140{
141 coeffs_t c{};
142 c.c0 = sign_extend((static_cast<uint32_t>(r[0]) << 4) | (r[1] >> 4), 12);
143 c.c1 = sign_extend(((static_cast<uint32_t>(r[1]) & 0x0F) << 8) | r[2], 12);
144 c.c00 = sign_extend((static_cast<uint32_t>(r[3]) << 12) | (static_cast<uint32_t>(r[4]) << 4) | (r[5] >> 4), 20);
145 c.c10 = sign_extend(((static_cast<uint32_t>(r[5]) & 0x0F) << 16) | (static_cast<uint32_t>(r[6]) << 8) | r[7], 20);
146 c.c01 = sign_extend((static_cast<uint32_t>(r[8]) << 8) | r[9], 16);
147 c.c11 = sign_extend((static_cast<uint32_t>(r[10]) << 8) | r[11], 16);
148 c.c20 = sign_extend((static_cast<uint32_t>(r[12]) << 8) | r[13], 16);
149 c.c21 = sign_extend((static_cast<uint32_t>(r[14]) << 8) | r[15], 16);
150 c.c30 = sign_extend((static_cast<uint32_t>(r[16]) << 8) | r[17], 16);
151 c.c31 = sign_extend((static_cast<uint32_t>(r[18]) << 4) | (r[19] >> 4), 12);
152 c.c40 = sign_extend(((static_cast<uint32_t>(r[19]) & 0x0F) << 8) | r[20], 12);
153 return c;
154}
155
157inline float compensate_temperature(const int32_t tmp_raw, const coeffs_t& c, const float kt)
158{
159 const float traw_sc = tmp_raw / kt;
160 return c.c0 * 0.5f + c.c1 * traw_sc;
161}
162
164inline float compensate_pressure(const int32_t psr_raw, const int32_t tmp_raw, const coeffs_t& c, const float kp,
165 const float kt)
166{
167 const float praw_sc = psr_raw / kp;
168 const float traw_sc = tmp_raw / kt;
169 return c.c00 + praw_sc * (c.c10 + praw_sc * (c.c20 + praw_sc * (c.c30 + praw_sc * c.c40))) + traw_sc * c.c01 +
170 traw_sc * praw_sc * (c.c11 + praw_sc * (c.c21 + praw_sc * c.c31));
171}
172
174inline float altitude_m(const float pressure_hpa, const float sea_level_hpa)
175{
176 return 44330.0f * (1.0f - std::pow(pressure_hpa / sea_level_hpa, 1.0f / 5.255f));
177}
178
183struct Data {
184 std::array<uint8_t, 6> raw{};
190 float kp{};
191 float kt{};
192
194 inline int32_t psr_raw() const
195 {
196 return sign_extend((static_cast<uint32_t>(raw[0]) << 16) | (static_cast<uint32_t>(raw[1]) << 8) | raw[2], 24);
197 }
199 inline int32_t tmp_raw() const
200 {
201 return sign_extend((static_cast<uint32_t>(raw[3]) << 16) | (static_cast<uint32_t>(raw[4]) << 8) | raw[5], 24);
202 }
204 inline float temperature() const
205 {
206 return (kt != 0.0f && tmp_raw() != NOT_MEASURED) ? compensate_temperature(tmp_raw(), coeffs, kt)
207 : std::numeric_limits<float>::quiet_NaN();
208 }
210 inline float celsius() const
211 {
212 return temperature();
213 }
215 inline float fahrenheit() const
216 {
217 return celsius() * 9.0f / 5.0f + 32.0f;
218 }
220 inline float pressure() const
221 {
222 return (kp != 0.0f && kt != 0.0f && psr_raw() != NOT_MEASURED)
223 ? compensate_pressure(psr_raw(), tmp_raw(), coeffs, kp, kt) / 100.0f // Pa -> hPa
224 : std::numeric_limits<float>::quiet_NaN();
225 }
226};
227
228} // namespace spa06
229} // namespace unit
230} // namespace m5
231#endif
Top level namespace of M5Stack.
Unit-related namespace.
One SPA06 sample: a 6-byte burst from PSR_B2 (0x00) = PSR(24) + TMP(24), big-endian.
Definition unit_SPA06_data.hpp:183
coeffs_t coeffs
Calibration coefficients for compensation.
Definition unit_SPA06_data.hpp:189
float kt
Temperature scale factor kT at measurement time (0 = not populated)
Definition unit_SPA06_data.hpp:191
int32_t psr_raw() const
Raw pressure (24-bit 2's complement)
Definition unit_SPA06_data.hpp:194
std::array< uint8_t, 6 > raw
PSR B2/B1/B0 + TMP B2/B1/B0.
Definition unit_SPA06_data.hpp:184
float pressure() const
Compensated pressure (hPa); NaN if not populated/measured.
Definition unit_SPA06_data.hpp:220
float fahrenheit() const
Compensated temperature (Fahrenheit)
Definition unit_SPA06_data.hpp:215
int32_t tmp_raw() const
Raw temperature (24-bit 2's complement)
Definition unit_SPA06_data.hpp:199
float celsius() const
Compensated temperature (Celsius)
Definition unit_SPA06_data.hpp:210
float temperature() const
Compensated temperature (Celsius); NaN if not populated/measured.
Definition unit_SPA06_data.hpp:204
float kp
Pressure scale factor kP at measurement time (0 = not populated)
Definition unit_SPA06_data.hpp:190
Factory calibration coefficients (all 2's complement, already sign-extended)
Definition unit_SPA06_data.hpp:131
Oversampling
Oversampling factor; the enum value is the PM_PRC/TM_PRC nibble (datasheet Table 4)
Definition unit_SPA06_data.hpp:29
@ X128
x128 (highest precision)
float altitude_m(const float pressure_hpa, const float sea_level_hpa)
Relative altitude (m) from a pressure and a reference (both hPa), barometric formula.
Definition unit_SPA06_data.hpp:174
Rate
Measurement rate; the enum value is the PM_RATE/TMP_RATE nibble (measurements per second)
Definition unit_SPA06_data.hpp:44
@ Rate4
4 measurements/s
@ Rate16
16 measurements/s
@ Rate64
64 measurements/s
@ Rate1
1 measurement/s
@ Rate2
2 measurements/s
@ Rate8
8 measurements/s
@ Rate32
32 measurements/s
@ Rate128
128 measurements/s
float compensate_pressure(const int32_t psr_raw, const int32_t tmp_raw, const coeffs_t &c, const float kp, const float kt)
Compensated pressure (Pa) from raw PSR/TMP readings and scales kP/kT (datasheet 4....
Definition unit_SPA06_data.hpp:164
float scale_factor(const Oversampling oversampling)
Compensation scale factor kP/kT for an oversampling rate (datasheet Table 4)
Definition unit_SPA06_data.hpp:66
float compensate_temperature(const int32_t tmp_raw, const coeffs_t &c, const float kt)
Compensated temperature (degC) from a raw TMP reading and scale kT.
Definition unit_SPA06_data.hpp:157
uint32_t measurement_time_x10(const Oversampling oversampling)
Measurement time (ms x10) for an oversampling rate (datasheet Table 8), indexed by nibble.
Definition unit_SPA06_data.hpp:90
Mode
Continuous measurement type; the enum value is the MEAS_CFG MEAS_CTRL[2:0] background-mode code.
Definition unit_SPA06_data.hpp:59
@ Pressure
Continuous pressure only (temperature() returns NaN)
@ PressureAndTemperature
Continuous pressure and temperature (both valid)
coeffs_t parse_coeffs(const std::array< uint8_t, 21 > &r)
Parse the 21 COEF register bytes (0x10..0x24) into coeffs_t (datasheet Table 10)
Definition unit_SPA06_data.hpp:139
int32_t sign_extend(const uint32_t v, const uint8_t bits)
Sign-extend the low bits of v (2's complement)
Definition unit_SPA06_data.hpp:124
constexpr int32_t NOT_MEASURED
Sentinel value of psr_raw()/tmp_raw() for a register not measured yet (reset value 0x800000)
Definition unit_SPA06_data.hpp:121
bool valid_combination(const Oversampling osrs_p, const Oversampling osrs_t, const Rate rate, const Mode mode)
True if a rate/oversampling/mode combination fits the datasheet timing budget.
Definition unit_SPA06_data.hpp:102