#include <M5Unified.h>
#include <M5UnitUnified.h>
#include <M5UnitUnifiedIMU.h>
m5::unit::UnitUnified units;
m5::unit::UnitBMM350 bmm350{0x14};
m5::imu::imu_convert_param_t convert_param{};
constexpr uint16_t COLOR_BG = TFT_BLACK;
constexpr uint16_t COLOR_CARD = TFT_BLACK;
constexpr uint16_t COLOR_BORDER = TFT_BLACK;
constexpr uint16_t COLOR_ACCENT = TFT_CYAN;
constexpr uint16_t COLOR_MUTED = TFT_DARKGREY;
constexpr uint16_t COLOR_GOOD = 0x5CE0;
void drawHeader(bool connected) {
M5.Display.fillScreen(COLOR_BG);
M5.Display.setTextSize(1);
M5.Display.setTextColor(TFT_CYAN, COLOR_CARD);
M5.Display.setCursor(12, 8);
M5.Display.print("UNIT BMM350");
M5.Display.setTextSize(1);
M5.Display.setTextColor(connected ? TFT_GREEN : TFT_ORANGE, COLOR_CARD);
M5.Display.setCursor(220, 8);
M5.Display.print(connected ? "READY" : "WAIT");
M5.Display.fillCircle(304, 18, 5, connected ? COLOR_GOOD : TFT_ORANGE);
}
void drawStatus(const char* message, uint16_t color) {
M5.Display.fillScreen(COLOR_BG);
drawHeader(false);
M5.Display.setTextSize(1);
M5.Display.setTextColor(color, COLOR_BG);
M5.Display.setCursor(12, 76);
M5.Display.print(message);
M5.Display.setTextSize(1);
M5.Display.setTextColor(COLOR_MUTED, COLOR_BG);
M5.Display.setCursor(12, 112);
M5.Display.print("I2C bus / sensor status");
}
void drawData(float mx, float my, float mz) {
M5.Display.startWrite();
M5.Display.fillRect(0, 56, 320, 120, TFT_BLACK);
M5.Display.setTextSize(1);
M5.Display.setTextColor(COLOR_ACCENT, COLOR_CARD);
M5.Display.setCursor(22, 68);
M5.Display.print("MAGNETIC FIELD");
M5.Display.setTextColor(COLOR_MUTED, COLOR_CARD);
M5.Display.setCursor(22, 84);
M5.Display.print("COMPENSATED OUTPUT / uT");
M5.Display.setTextColor(TFT_WHITE, COLOR_CARD);
M5.Display.setTextSize(1);
M5.Display.setCursor(22, 108);
M5.Display.printf("X % 8.2f ", mx);
M5.Display.setCursor(22, 132);
M5.Display.printf("Y % 8.2f ", my);
M5.Display.setCursor(22, 156);
M5.Display.printf("Z % 8.2f ", mz);
M5.Display.setTextSize(1);
M5.Display.setTextColor(COLOR_MUTED, COLOR_BG);
M5.Display.setCursor(12, 218);
M5.Display.print("LIVE | 500 ms | I2C 400 kHz");
M5.Display.endWrite();
}
void setup() {
Serial.begin(115200);
const uint32_t serial_start = millis();
while (!Serial && millis() - serial_start < 3000) {
delay(10);
}
Serial.println("Starting Unit BMM350...");
auto config = M5.config();
M5.begin(config);
M5.Display.setFont(&fonts::FreeSansBold9pt7b);
M5.Display.setTextSize(1);
M5.Display.setRotation(1);
M5.Display.setTextWrap(false, false);
drawStatus("Initializing...", COLOR_ACCENT);
auto cfg = bmm350.component_config();
cfg.clock = 400000;
bmm350.component_config(cfg);
if (!M5.Ex_I2C.begin() || !units.add(bmm350, M5.Ex_I2C) || !units.begin()) {
while (true) {
Serial.println("Unit BMM350 not found. Check wiring or I2C address.");
drawStatus("Sensor not found", TFT_ORANGE);
delay(1000);
}
}
bmm350.imuConvertParam(convert_param);
Serial.println("Unit BMM350 ready, address: 0x14");
drawHeader(true);
}
void loop() {
M5.update();
units.update();
static uint32_t last_output = 0;
if (millis() - last_output < 500) {
return;
}
last_output = millis();
m5::imu::imu_raw_data_t raw{};
static bool waiting_shown = false;
if (m5::imu::any(bmm350.readImuRaw(raw))) {
waiting_shown = false;
const float mx = raw.mag[0] * convert_param.mag_res;
const float my = raw.mag[1] * convert_param.mag_res;
const float mz = raw.mag[2] * convert_param.mag_res;
Serial.printf("Magnetic field: X %.2f, Y %.2f, Z %.2f uT\n",
mx, my, mz);
drawData(mx, my, mz);
} else {
if (!waiting_shown) {
waiting_shown = true;
Serial.println("Waiting for Unit BMM350 data...");
drawStatus("Waiting for data...", COLOR_ACCENT);
}
}
}