SSCMEx
SSCMEx is an Elixir NIF wrapper for SSCMA-Micro on SG2002/reCamera.
It provides:
-
camera access (
SSCMEx.Camera) -
model loading/inference (
SSCMEx.Engine,SSCMEx.Model) -
zero-copy image structs (
SSCMEx.Image)
Installation
Add sscmex to your dependencies:
def deps do
[
{:sscmex, "~> 0.1.0"}
]
endPrecompiled NIF target selection
SSCMEx uses elixir_make + cc_precompiler for precompiled NIFs.
- In host builds, target detection follows the current host triplet.
-
In Nerves cross-builds for
MIX_TARGET=nerves_system_sg2002,SSCMExmaps the target toriscv64-buildroot-linux-muslautomatically. -
For this known Nerves target,
SSCMExnormalizesTARGET_ARCH,TARGET_OS, andTARGET_ABIto match published precompiled artifacts, even if those env vars are already set by the host toolchain. -
To preserve externally provided
TARGET_*values for custom experiments, setSSCMEX_KEEP_TARGET_TRIPLET=1.
Example manual override:
export SSCMEX_KEEP_TARGET_TRIPLET=1
export TARGET_ARCH=riscv64
export TARGET_OS=nerves
export TARGET_ABI=musl
MIX_TARGET=nerves_system_sg2002 mix compileManual IEx flow (camera -> TPU -> results)
Use this when you want to test manually without SSCMEx.Examples.*.
# 1) Load NIF
:ok = SSCMEx.load_nif()
# 2) Device + camera
{:ok, device} = SSCMEx.Device.get_instance()
{:ok, camera} = SSCMEx.Camera.get(device, 0)
# 3) TPU engine + model
model_path = "/data/yolov8n_cv181x_int8.cvimodel"
{:ok, engine} = SSCMEx.Engine.new()
:ok = SSCMEx.Engine.load(engine, model_path)
{:ok, model} = SSCMEx.Model.create(engine)
:ok = SSCMEx.Model.set_config(model, :threshold_score, 0.5)
:ok = SSCMEx.Model.set_config(model, :threshold_nms, 0.45)
# 4) Camera config and stream
{:ok, :initialized} = SSCMEx.Camera.init(camera, 0)
{:ok, :ok} = SSCMEx.Camera.set_ctrl(camera, :channel, 0)
{:ok, :ok} = SSCMEx.Camera.set_ctrl(camera, :window, {640, 640})
{:ok, :ok} = SSCMEx.Camera.set_ctrl(camera, :format, :rgb888)
{:ok, :ok} = SSCMEx.Camera.set_ctrl(camera, :fps, 3)
{:ok, :streaming} = SSCMEx.Camera.start_stream(camera, :refresh_on_return)
Process.sleep(1500)
# 5) Grab frame and run inference
# retrieve_frame already returns %SSCMEx.Image{}
{:ok, image} = SSCMEx.Camera.retrieve_frame(camera, :rgb888)
{:ok, results} = SSCMEx.Model.run(model, image)
{:ok, perf} = SSCMEx.Model.get_perf(model)
IO.inspect(results, label: "results")
IO.inspect(perf, label: "perf")
# 6) Cleanup
{:ok, :stopped} = SSCMEx.Camera.stop_stream(camera)
{:ok, :deinitialized} = SSCMEx.Camera.deinit(camera)SSCMEx.Model.run/2 returns different result maps depending on model output type:
:boxes(detection):%{x, y, w, h, score, target}:classes(classification):%{score, target}:points:%{x, y, score, target}:keypoints(pose):%{box: %{x, y, w, h, score, target}, points: [%{x, y, z}, ...]}:segments(segmentation):%{box: %{x, y, w, h, score, target}, mask: %{width, height, data}}
For backward compatibility, detection models still return the same bbox fields (x, y, w, h, score, target).
Notes
SSCMEx.Camera.retrieve_frame/2now returns%SSCMEx.Image{}directly.-
For one-shot tests, keep
fpslow (for example3) to reduce memory pressure.
Runtime observability (SG2002)
When debugging camera/TPU contention, these runtime stats are useful:
VB/ION pool status (best signal for camera-side memory pressure):
cat /proc/cvitek/vb-
Look at per-pool
BlkSz,BlkCnt,Free, and especiallyMinFree. -
If
MinFreedrops near0, the pipeline is close to buffer exhaustion.
TPU usage profiling:
-
Enable:
echo 1 > /proc/tpu/usage_profiling -
Read:
cat /proc/tpu/usage_profiling -
Disable:
echo 0 > /proc/tpu/usage_profiling
-
Enable:
Per-inference model timings (already exposed by SSCMEx):
{:ok, perf} = SSCMEx.Model.get_perf(model)-
Returns
%{preprocess: ms, inference: ms, postprocess: ms}from the last run.
Optional bandwidth monitor (if your image enables it):
echo 1 > /proc/mon/bw_profilingcat /proc/mon/profiling_window_ms