I2C protocol¶
The SF06 command set as the driver uses it: framing, every command, the frames the sensor returns, scaling and the status word.
Source: SFM4300 datasheet,
section 4. The constants are in inc/sfm_commands.hpp.
Framing¶
- A command is 16 bits, MSB first, written without a register byte.
- A command with an argument adds a 16-bit argument and its CRC-8: five bytes in all.
- A read returns 16-bit words, each followed by a CRC-8. The host may stop after any word with a NACK and a
STOP. The driver checks every CRC and returns
DriverError::Crcon the first mismatch. - The CRC-8 covers the two bytes before it: polynomial 0x31 (x⁸ + x⁵ + x⁴ + 1), initial value 0xFF, no
reflection, no final XOR. Test vector: CRC(0xBEEF) = 0x92, checked at compile time by a
static_assert.
Commands¶
| Code | Command (argument) | Driver call, notes |
|---|---|---|
0x3603 |
Start, O2 | StartContinuous(Gas::O2) |
0x3608 |
Start, air | StartContinuous(Gas::Air) |
0x3615 |
Start, N2O | StartContinuous(Gas::N2O); SFM4300-20 only |
0x361E |
Start, CO2 | StartContinuous(Gas::CO2); SFM4300-20 only |
0x3632 |
Start, air / O2 (O2 ‰) | StartContinuous(Gas::AirO2Mix, o2) |
0x3639 |
Start, N2O / O2 (O2 ‰) | StartContinuous(Gas::N2OO2Mix, o2); SFM4300-20 only |
0x3646 |
Start, CO2 / O2 (O2 ‰) | StartContinuous(Gas::CO2O2Mix, o2); SFM4300-20 only |
0xE17D |
Transmit concentration (O2 ‰) | UpdateConcentration(); while measuring |
0xE000 |
Reset I2C address pointer | UpdateConcentration(), after 0xE17D |
0x3FF9 |
Stop continuous measurement | Stop(); idle after up to 0.5 ms, which Stop() waits |
0x366A |
Configure averaging (N) | ConfigureAveraging(); idle only; 0 = average-until-read, 1 to 128 = fixed N |
0x3661 |
Read scale factor, offset, unit (start code) | ReadScaleOffsetUnit(); idle only; three words back |
0x3677 |
Enter sleep | EnterSleep(); idle only |
| (address + W) | Exit sleep | ExitSleep(); not acknowledged, poll until the address ACKs (typically 16 ms) |
0xE102 |
Read product identifier | ReadProductIdentifier(); idle only; six words back |
0x06 to 0x00 |
Soft reset (general call) | SoftReset(); about 16 ms, 20 ms maximum |
Codes 0x3624 and 0x362F are reserved on the SFM4300. While a continuous measurement runs, the sensor accepts
only stop, soft reset and the two concentration commands: stop it before anything else.
Frames the sensor returns¶
| After | Words (each + CRC) | Bytes |
|---|---|---|
| A start command | flow, temperature, status | 9 (3 for flow only) |
0x3661 |
scale factor, offset, unit | 9 |
0xE102 |
product number (2 words), serial number (4 words) | 18 |
Flow, temperature, scale factor and offset are signed 16-bit (two's complement); the unit and the status are
unsigned. A read header while no new sample exists is NACKed (DriverError::NoData).
Scaling¶
The sensor reports raw counts. The physical value is (raw - offset) / scale, with the scale factor and offset of
the gas table in use:
| Signal | Scale factor | Offset | Unit |
|---|---|---|---|
| Flow, SFM4300-20 (every gas and mixture) | 2500 | -28672 | slm |
| Flow, SFM4300-50 (O2, air, air/O2) | 1000 | -28672 | slm |
| Temperature | 200 | 0 | °C |
The driver does not hard-code the flow scaling: StartContinuous() reads it from the sensor (0x3661) for the
gas you start, and ReadMeasurement() applies it. The temperature scale (200 per °C) is a constant,
sfm::kTemperatureScalePerC.
The flow unit is 0x0148 on every SFM4300 table: standard litres per minute at 20 °C and 1013.25 mbar
(bits 12:8 = 1 standard litre, bits 7:4 = 4 per minute, bits 3:0 = 8 prefix 10⁰).
Status word¶
The third word of each measurement frame.
| Bits | Name | Meaning |
|---|---|---|
15:12 |
running command | Index of the start command in the table below |
11 |
exponential smoothing | 1: average-until-read has switched to exponential smoothing (no read for over 64 ms) |
10 |
averaging mode | 0: average-until-read; 1: fixed-N averaging |
9:0 |
gas concentration | O2 volume fraction in ‰ for a mixture; 0x3FF for a pure gas |
| Bits 15:12 | Start code | Measurement |
|---|---|---|
| 0 | 0x3603 |
O2 |
| 1 | 0x3608 |
Air |
| 2 | 0x3615 |
N2O |
| 3 | 0x361E |
CO2 |
| 4, 5 | 0x3624, 0x362F |
Reserved |
| 6 | 0x3632 |
Air / O2 |
| 7 | 0x3639 |
N2O / O2 |
| 8 | 0x3646 |
CO2 / O2 |
sfm::StatusWord decodes the fields: command_nibble(), exponential_smoothing(), fixed_n_averaging(),
gas_fraction_permille() and pure_gas().
sfm::GasFromStatusNibble(family, nibble) turns bits 15:12 back into an sfm::Gas using this table (SF06) or
the SFx6000 one, and sfm::StatusNibbleIsKnown(family, nibble) tells a real code from a reserved one: a reserved
nibble decodes as Gas::Air. On the SFM3013-300-CLM, 2 and 7 are HeOx and HeOx / O2: the
GasFromStatusNibble(variant, nibble) overload decodes them.
Product identifier¶
Bytes 1 to 4 of the 0xE102 reply form a 32-bit product number; the last 8 bits are a revision. The driver
ignores them when it decodes the variant.
| Product number | Variant | sfm::Variant |
|---|---|---|
0x0403011x |
SFM4300-20-B | Sfm4300_20_B |
0x0403021x |
SFM4300-20-O | Sfm4300_20_O |
0x0403031x |
SFM4300-20-P | Sfm4300_20_P |
0x0403091x |
SFM4300-50-B | Sfm4300_50_B |
0x0403071x |
SFM4300-50-O | Sfm4300_50_O |
0x0403061x |
SFM4300-50-P | Sfm4300_50_P |
The datasheet marks ...8x revisions as prototypes and ...1x as production parts. The 64-bit serial number,
read as a decimal, has the form yywwxxxxxx: calibration year and week, then a sequence number.
Next: Measurement and averaging.