BMI323.Sampler (bmi323 v0.1.0)

Copy Markdown

GenServer that drains the BMI323's on-chip FIFO and dispatches sample frames to a subscriber process.

Why this exists

Polling the BMI323's data-ready bits from the BEAM is unreliable at higher ODRs: the scheduler can lose samples between polls. The chip's 2 KB FIFO and hardware interrupt pin solve this by buffering samples and notifying the host on a watermark threshold. This module wires those features up.

Configurable FIFO frame format

The sampler accepts any non-empty subset of :accelerometer, :gyroscope, :temperature, and :sensor_time via the :sources option. The chip emits frames in the canonical order (accel → gyro → temp → sensor_time), and BMI323.Fifo.parse_frames/3 decodes whichever subset is enabled. See BMI323.Fifo for the protocol details.

Each sample is dispatched as a {BMI323.Sampler, sampler_pid, [frame, ...]} message. Frames are maps containing only the enabled sources — see BMI323.Fifo.frame/0.

Usage

{:ok, i2c} = Wafer.Driver.Circuits.I2C.acquire(bus_name: "i2c-1", address: 0x68)
{:ok, bmi} = BMI323.acquire(conn: i2c, soft_reset: true)
{:ok, bmi} = BMI323.configure_accelerometer(bmi, mode: :normal, range: 4, odr: 200)
{:ok, bmi} = BMI323.configure_gyroscope(bmi, mode: :normal, range: 2000, odr: 200)

{:ok, int1} = Wafer.Driver.Circuits.GPIO.acquire(pin: 17, direction: :in)

{:ok, _sampler} =
  BMI323.Sampler.start_link(
    bmi: bmi,
    int1: int1,
    sources: [:accelerometer, :gyroscope, :sensor_time],
    watermark_frames: 8
  )

receive do
  {BMI323.Sampler, _pid, frames} -> IO.inspect(frames)
end

Summary

Types

Options accepted by start_link/1.

t()

Internal sampler state.

Functions

Returns a specification to start this module under a supervisor.

Synchronously drain the FIFO and return any complete frames. Used in pull-only mode (no INT1 wired) or when the caller wants the latest state on demand.

Issue a FIFO flush via FIFO_CTRL.

Start a FIFO sampler.

Types

option()

@type option() ::
  {:bmi, BMI323.t()}
  | {:int1, Wafer.Conn.t() | nil}
  | {:subscriber, pid()}
  | {:watermark_frames, pos_integer()}
  | {:sources, [BMI323.Fifo.source()]}
  | {:stop_on_full, boolean()}
  | {:name, GenServer.name()}

Options accepted by start_link/1.

t()

@type t() :: %BMI323.Sampler{
  bmi: BMI323.t(),
  frame_words: pos_integer(),
  int1: Wafer.Conn.t() | nil,
  ranges: BMI323.Fifo.ranges(),
  sources: [BMI323.Fifo.source()],
  subscriber: pid(),
  watermark_frames: pos_integer()
}

Internal sampler state.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

drain(server)

@spec drain(GenServer.server()) :: {:ok, [BMI323.Fifo.frame()]} | {:error, term()}

Synchronously drain the FIFO and return any complete frames. Used in pull-only mode (no INT1 wired) or when the caller wants the latest state on demand.

flush(server)

@spec flush(GenServer.server()) :: :ok | {:error, term()}

Issue a FIFO flush via FIFO_CTRL.

start_link(opts)

@spec start_link([option()]) :: GenServer.on_start()

Start a FIFO sampler.

Options

  • :bmi (required) — a BMI323 struct. The cached ranges on the struct must cover every scaled source (:accelerometer_range if :accelerometer is in :sources, :gyroscope_range for :gyroscope).
  • :int1 (optional) — a Wafer.GPIO-implementing connection wired to the device's INT1 pin. If absent the sampler runs in pull-only mode; call drain/1 to fetch buffered frames.
  • :subscriber (default self()) — process to which sample messages are delivered.
  • :watermark_frames (default 8) — fire the watermark interrupt after this many frames have accumulated in the FIFO.
  • :sources (default [:accelerometer, :gyroscope, :temperature, :sensor_time]) — list of FIFO sources to enable. Order is irrelevant; the chip always emits in canonical order.
  • :stop_on_full (default false) — when true, the FIFO stops accepting new data on overflow instead of overwriting oldest.
  • :name — optional GenServer registration name.