Sense.M.3G
Triaxial geomagnetic magnetometer driver for Sense.M.3G (BMM350).
Examples
Polled example (Cores SDK)
tile_t mag;
tile_sense_m_3g_init(core_tiles_pal(&core_i2c1), 0, &mag, NULL);
tile_sense_m_3g_set_mode(&mag, SENSE_M_3G_MODE_NORMAL);
while (1) {
if (tile_sense_m_3g_data_ready(&mag)) {
tile_sense_m_3g_read(&mag);
printf("%ld %ld %ld nT\n",
tile_sense_m_3g_get_x_nt(&mag),
tile_sense_m_3g_get_y_nt(&mag),
tile_sense_m_3g_get_z_nt(&mag));
}
core_delay_ms(10);
}Interrupt-driven example (INT wired to a Core pad)
sense_m_3g_cfg_t cfg = {
.odr = SENSE_M_3G_ODR_50HZ,
.averaging = SENSE_M_3G_AVG_4,
.int_pin = 9, // Core pad carrying INT
.on_data = on_mag_sample,
};
tile_sense_m_3g_init(core_tiles_pal(&core_i2c1), 0, &mag, &cfg);
tile_sense_m_3g_set_mode(&mag, SENSE_M_3G_MODE_NORMAL);
while (1) { tile_sense_m_3g_process(&mag); }API reference
Initialization
tile_sense_m_3g_find
uint8_t tile_sense_m_3g_find(tiles_pal_t *hal, uint8_t instance)Probe the bus for a BMM350.
- hal
- Tiles HAL handle (I2C bus)
- instance
- 0 for address 0x14 (Sense.M.3G), 1 for 0x15
Returns 1 if a device ACKs and reports CHIP_ID 0x33, 0 otherwise
tile_sense_m_3g_init
void tile_sense_m_3g_init(tiles_pal_t *hal, uint8_t instance, tile_t *tile, const sense_m_3g_cfg_t *cfg)Soft-resets the device, verifies CHIP_ID, downloads the 32 OTP trim words and derives the compensation coefficients from them, powers the OTP back down, then runs a full magnetic reset so the transducer starts from a known magnetic state. Leaves the device in suspend — call set_mode() to start measuring. Takes roughly 100 ms, most of it the OTP download and the magnetic reset's bit-reset and flip-gain-reset settling.
- hal
- Tiles HAL handle (I2C bus)
- instance
- 0 for 0x14, 1 for 0x15
- tile
- Tile handle to initialize
- cfg
- Optional config. NULL for defaults.
Lifecycle
tile_sense_m_3g_set_mode
Studiovoid tile_sense_m_3g_set_mode(tile_t *tile, uint8_t mode)Forced mode is reachable only from suspend, so a request to enter it from normal mode is routed through suspend first. Each transition blocks for the settling time the device needs, which for suspend to forced depends on the averaging setting.
- tile
- Tile handle
- mode
- Target mode (sense_m_3g_mode_t)
tile_sense_m_3g_trigger_measurement
Studiouint8_t tile_sense_m_3g_trigger_measurement(tile_t *tile)Uses the fast forced mode when the configured ODR is 25 Hz or above and the slow one otherwise, per datasheet §5.1.4. The device returns to suspend on its own once the conversion completes. Does not read the sample — call read() after.
- tile
- Tile handle
Returns 1 if a conversion completed, 0 on timeout
tile_sense_m_3g_sleep
Studiovoid tile_sense_m_3g_sleep(tile_t *tile)Put the device in suspend mode (lowest power, settings kept).
- tile
- Tile handle
tile_sense_m_3g_wake
Studiovoid tile_sense_m_3g_wake(tile_t *tile)Return the device to normal (free-running) mode.
- tile
- Tile handle
tile_sense_m_3g_reset
Studiovoid tile_sense_m_3g_reset(tile_t *tile)Re-downloads the OTP trim data and repeats the magnetic reset, so the compensation coefficients survive. Leaves the device in suspend.
- tile
- Tile handle
tile_sense_m_3g_magnetic_reset
Studiouint8_t tile_sense_m_3g_magnetic_reset(tile_t *tile)Restores the transducer's magnetic state after exposure to a strong field. The device does this automatically every ODR tick while measuring and once at boot, so it is only needed after the part has sat in suspend through a field event — the sensor cannot detect one while suspended (datasheet §5.1.5). Worth calling after more than a couple of seconds in suspend, which also recharges the CRST capacitor. Must be run from suspend; a device in normal mode is parked, reset, and restored.
- tile
- Tile handle
Returns 1 if both reset phases were acknowledged, 0 otherwise
Runtime
tile_sense_m_3g_read
Studiouint8_t tile_sense_m_3g_read(tile_t *tile)Burst-reads magnetic and temperature data in a single transaction — mandatory, because the device freezes the data registers for the duration of a burst and single reads would tear across an update (datasheet §5.2).
- tile
- Tile handle
Returns 1 on success, 0 if the bus read failed
tile_sense_m_3g_process
Studiovoid tile_sense_m_3g_process(tile_t *tile)Call from your main loop. Checks data-ready (or the INT flag when an INT pin is configured), and on a new sample calls read() and fires the callback. Cheap when nothing is ready.
- tile
- Tile handle
tile_sense_m_3g_on_data
Studiovoid tile_sense_m_3g_on_data(tile_t *tile, sense_m_3g_data_cb_t cb, void *ctx)Register or change the new-sample callback.
- tile
- Tile handle
- cb
- Callback (NULL to disable)
- ctx
- User context passed to the callback
tile_sense_m_3g_get_x_nt
Studioint32_t tile_sense_m_3g_get_x_nt(tile_t *tile)Compensated X field from the last read, in nanotesla.
- tile
- Tile handle
Returns X in nT (1000 nT = 1 uT)
tile_sense_m_3g_get_y_nt
Studioint32_t tile_sense_m_3g_get_y_nt(tile_t *tile)Compensated Y field from the last read, in nanotesla.
- tile
- Tile handle
Returns Y in nT
tile_sense_m_3g_get_z_nt
Studioint32_t tile_sense_m_3g_get_z_nt(tile_t *tile)Compensated Z field from the last read, in nanotesla.
- tile
- Tile handle
Returns Z in nT
tile_sense_m_3g_get_temperature_mc
Studioint32_t tile_sense_m_3g_get_temperature_mc(tile_t *tile)This is the compensation chain's own temperature, not an ambient reading — the die sits above ambient by whatever the board is doing.
- tile
- Tile handle
Returns Temperature in m°C (25000 = 25.000 °C)
tile_sense_m_3g_get_magnitude_nt
Studiouint32_t tile_sense_m_3g_get_magnitude_nt(tile_t *tile)sqrt(x² + y² + z²), computed with an integer square root. Useful as a sanity check: a quiet indoor spot should land in the 25000-65000 nT band, and a magnet nearby will swamp it.
- tile
- Tile handle
Returns Magnitude in nT
tile_sense_m_3g_data_ready
Studiouint8_t tile_sense_m_3g_data_ready(tile_t *tile)Check whether the device has a new sample waiting.
- tile
- Tile handle
Returns 1 if INT_STATUS reports data ready
tile_sense_m_3g_get_sensortime
Studiouint32_t tile_sense_m_3g_get_sensortime(tile_t *tile)Ticks at 40 µs resolution and marks when the last sample was generated, not when you read it. Only advances in normal mode unless sensor-time always-on is enabled. Wraps at 24 bits without saturating.
- tile
- Tile handle
Returns Raw 24-bit counter value
Config
tile_sense_m_3g_set_odr_averaging
Studiovoid tile_sense_m_3g_set_odr_averaging(tile_t *tile, uint8_t odr, uint8_t averaging)The pair is constrained: 400 Hz forces no averaging, 200 Hz caps at 2x, 100 Hz at 4x (datasheet Table 5). An illegal combination is clamped to the highest averaging the requested rate allows rather than rejected. Both live in one register and need an update command, which this issues.
- tile
- Tile handle
- odr
- Output data rate (sense_m_3g_odr_t)
- averaging
- Averaging (sense_m_3g_avg_t)
tile_sense_m_3g_set_axes
Studiovoid tile_sense_m_3g_set_axes(tile_t *tile, uint8_t mask)A disabled axis stops converting, saving current, and reads back 0.
- tile
- Tile handle
- mask
- OR of BMM350_EN_X / _Y / _Z
tile_sense_m_3g_configure_interrupt
Studiovoid tile_sense_m_3g_configure_interrupt(tile_t *tile, uint8_t enable, uint8_t active_high, uint8_t push_pull, uint8_t latched)Configure the data-ready interrupt on the INT pin.
- tile
- Tile handle
- enable
- 1 to drive the INT pin, 0 to leave it idle
- active_high
- 1 for active-high, 0 for active-low
- push_pull
- 1 for push-pull, 0 for open-drain (needs a pull-up)
- latched
- 1 to latch until INT_STATUS is read, 0 for a pulse
tile_sense_m_3g_set_pad_drive
Studiovoid tile_sense_m_3g_set_pad_drive(tile_t *tile, uint8_t drive)Set the INT/SDA/SCL pad drive strength (0-7, weakest to strongest).
- tile
- Tile handle
- drive
- Drive strength, 0-7
tile_sense_m_3g_set_i2c_watchdog
Studiovoid tile_sense_m_3g_set_i2c_watchdog(tile_t *tile, uint8_t enable, uint8_t long_wdt)Recovers the bus if the host stalls mid-transaction. Independent of the Core's own watchdog.
- tile
- Tile handle
- enable
- 1 to enable, 0 to disable
- long_wdt
- 1 for the ~40 ms timeout, 0 for ~1.28 ms
tile_sense_m_3g_set_sensortime_always_on
Studiovoid tile_sense_m_3g_set_sensortime_always_on(tile_t *tile, uint8_t enable)Keep the sensor-time counter running outside normal mode.
- tile
- Tile handle
- enable
- 1 to keep counting in suspend and forced mode
Advanced
tile_sense_m_3g_get_error
Studiouint8_t tile_sense_m_3g_get_error(tile_t *tile)Read the device's error register.
- tile
- Tile handle
Returns ERR_REG contents; bit 0 set means the last PMU command was rejected
tile_sense_m_3g_get_pmu_status
Studiouint8_t tile_sense_m_3g_get_pmu_status(tile_t *tile)Read the PMU command status register.
- tile
- Tile handle
Returns PMU_CMD_STATUS_0: [3:0] last command, plus busy / normal-mode flags
tile_sense_m_3g_get_otp_word
Studiouint16_t tile_sense_m_3g_get_otp_word(tile_t *tile, uint8_t word)The compensation coefficients are derived from these. Exposed for diagnostics — comparing them against a known-good part is the fastest way to tell a compensation bug from a broken OTP download.
- tile
- Tile handle
- word
- Word index, 0-31
Returns The cached 16-bit OTP word, or 0 if the index is out of range
tile_sense_m_3g_get_raw
Studioint32_t tile_sense_m_3g_get_raw(tile_t *tile, uint8_t axis)Straight from the data registers with no compensation applied — the input to the compensation chain. For debugging only; these are not field values and are not in spec.
- tile
- Tile handle
- axis
- 0 = X, 1 = Y, 2 = Z, 3 = temperature
Returns Signed raw counts from the last read()
tile_sense_m_3g_read_reg
Studiouint8_t tile_sense_m_3g_read_reg(tile_t *tile, uint8_t reg)Read a raw 8-bit register, dummy bytes handled.
- tile
- Tile handle
- reg
- Register address
Returns Register value, or 0 if the tile is not ready
tile_sense_m_3g_write_reg
Studiovoid tile_sense_m_3g_write_reg(tile_t *tile, uint8_t reg, uint8_t value)Write a raw 8-bit register.
- tile
- Tile handle
- reg
- Register address
- value
- Value to write
Enums
sense_m_3g_avg_t
- SENSE_M_3G_AVG_NONE
- 1 sample — "low power"
- SENSE_M_3G_AVG_2
- 2 samples — "regular power"
- SENSE_M_3G_AVG_4
- 4 samples — "low noise"
- SENSE_M_3G_AVG_8
- 8 samples — "ultra low noise"
sense_m_3g_odr_t
Output data rate (PMU_CMD_AGGR_SET bits [3:0]).
- SENSE_M_3G_ODR_400HZ
- SENSE_M_3G_ODR_200HZ
- SENSE_M_3G_ODR_100HZ
- SENSE_M_3G_ODR_50HZ
- SENSE_M_3G_ODR_25HZ
- SENSE_M_3G_ODR_12_5HZ
- SENSE_M_3G_ODR_6_25HZ
- SENSE_M_3G_ODR_3_125HZ
- SENSE_M_3G_ODR_1_5625HZ
sense_m_3g_mode_t
Power mode.
Constants
| TILE_SENSE_M_3G_VERSION_MAJOR | 0 | |
| TILE_SENSE_M_3G_VERSION_MINOR | 9 | |
| TILE_SENSE_M_3G_VERSION_PATCH | 0 | |
| BMM350_I2C_ADDR_LOW | 0x14 | |
| BMM350_I2C_ADDR_HIGH | 0x15 | |
| BMM350_CHIP_ID | 0x33 | |
| BMM350_DUMMY_BYTES | 2 | |
| BMM350_MAG_TEMP_DATA_LEN | 12 | |
| BMM350_PMU_CMD_SUS | 0x00 | Suspend mode |
| BMM350_PMU_CMD_NM | 0x01 | Normal mode |
| BMM350_PMU_CMD_UPD_OAE | 0x02 | Apply a new ODR / averaging setting |
| BMM350_PMU_CMD_FM | 0x03 | Forced mode |
| BMM350_PMU_CMD_FM_FAST | 0x04 | Forced mode, fast (ODR >= 25 Hz) |
| BMM350_PMU_CMD_FGR | 0x05 | Flip-gain reset (magnetic reset) |
| BMM350_PMU_CMD_FGR_FAST | 0x06 | |
| BMM350_PMU_CMD_BR | 0x07 | Bit reset (magnetic reset) |
| BMM350_PMU_CMD_BR_FAST | 0x08 | |
| BMM350_CMD_SOFTRESET | 0xB6 | |
| BMM350_EN_XYZ | 0x07 |

