diff --git a/Adafruit_MLX90632.cpp b/Adafruit_MLX90632.cpp index 248cfb5..d92f160 100644 --- a/Adafruit_MLX90632.cpp +++ b/Adafruit_MLX90632.cpp @@ -77,6 +77,178 @@ uint64_t Adafruit_MLX90632::getProductID() { return ((uint64_t)id2 << 32) | ((uint64_t)id1 << 16) | id0; } +/*! + * @brief Read the product code + * @return Product code (16-bit value) + */ +uint16_t Adafruit_MLX90632::getProductCode() { + Adafruit_BusIO_Register product_code_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_EE_PRODUCT_CODE), 2, MSBFIRST, 2); + return product_code_reg.read(); +} + +/*! + * @brief Start a single measurement (SOC) + * @return True if write succeeded, false otherwise + */ +bool Adafruit_MLX90632::startSingleMeasurement() { + Adafruit_BusIO_Register control_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_CONTROL), 2, MSBFIRST, 2); + Adafruit_BusIO_RegisterBits soc_bit = + Adafruit_BusIO_RegisterBits(&control_reg, 1, 3); + + return soc_bit.write(1); +} + +/*! + * @brief Start a full measurement table (SOB) + * @return True if write succeeded, false otherwise + */ +bool Adafruit_MLX90632::startFullMeasurement() { + Adafruit_BusIO_Register control_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_CONTROL), 2, MSBFIRST, 2); + Adafruit_BusIO_RegisterBits sob_bit = + Adafruit_BusIO_RegisterBits(&control_reg, 1, 11); + + return sob_bit.write(1); +} + +/*! + * @brief Set the measurement mode + * @param mode The measurement mode to set + * @return True if write succeeded, false otherwise + */ +bool Adafruit_MLX90632::setMode(mlx90632_mode_t mode) { + Adafruit_BusIO_Register control_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_CONTROL), 2, MSBFIRST, 2); + Adafruit_BusIO_RegisterBits mode_bits = + Adafruit_BusIO_RegisterBits(&control_reg, 2, 1); + + return mode_bits.write(mode); +} + +/*! + * @brief Get the measurement mode + * @return The current measurement mode + */ +mlx90632_mode_t Adafruit_MLX90632::getMode() { + Adafruit_BusIO_Register control_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_CONTROL), 2, MSBFIRST, 2); + Adafruit_BusIO_RegisterBits mode_bits = + Adafruit_BusIO_RegisterBits(&control_reg, 2, 1); + + return (mlx90632_mode_t)mode_bits.read(); +} + +/*! + * @brief Set the measurement select type + * @param meas_select The measurement select type to set + * @return True if write succeeded, false otherwise + */ +bool Adafruit_MLX90632::setMeasurementSelect(mlx90632_meas_select_t meas_select) { + Adafruit_BusIO_Register control_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_CONTROL), 2, MSBFIRST, 2); + Adafruit_BusIO_RegisterBits meas_select_bits = + Adafruit_BusIO_RegisterBits(&control_reg, 5, 4); + + return meas_select_bits.write(meas_select); +} + +/*! + * @brief Get the measurement select type + * @return The current measurement select type + */ +mlx90632_meas_select_t Adafruit_MLX90632::getMeasurementSelect() { + Adafruit_BusIO_Register control_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_CONTROL), 2, MSBFIRST, 2); + Adafruit_BusIO_RegisterBits meas_select_bits = + Adafruit_BusIO_RegisterBits(&control_reg, 5, 4); + + return (mlx90632_meas_select_t)meas_select_bits.read(); +} + +/*! + * @brief Check if device is busy with measurement + * @return True if device is busy, false otherwise + */ +bool Adafruit_MLX90632::isBusy() { + Adafruit_BusIO_Register status_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_STATUS), 2, MSBFIRST, 2); + Adafruit_BusIO_RegisterBits device_busy_bit = + Adafruit_BusIO_RegisterBits(&status_reg, 1, 10); + + return device_busy_bit.read(); +} + +/*! + * @brief Check if EEPROM is busy + * @return True if EEPROM is busy, false otherwise + */ +bool Adafruit_MLX90632::isEEPROMBusy() { + Adafruit_BusIO_Register status_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_STATUS), 2, MSBFIRST, 2); + Adafruit_BusIO_RegisterBits eeprom_busy_bit = + Adafruit_BusIO_RegisterBits(&status_reg, 1, 9); + + return eeprom_busy_bit.read(); +} + +/*! + * @brief Reset device using addressed reset command + * @return True if reset succeeded, false otherwise + */ +bool Adafruit_MLX90632::reset() { + // Send addressed reset command: 0x3005, 0x0006 + uint8_t reset_cmd[] = {0x30, 0x05, 0x00, 0x06}; + if (!i2c_dev->write(reset_cmd, 4)) { + return false; + } + + // Wait for reset to complete (at least 150us as per datasheet) + delay(1); + + return true; +} + +/*! + * @brief Read the cycle position + * @return Current cycle position (0-31) + */ +uint8_t Adafruit_MLX90632::readCyclePosition() { + Adafruit_BusIO_Register status_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_STATUS), 2, MSBFIRST, 2); + Adafruit_BusIO_RegisterBits cycle_position_bits = + Adafruit_BusIO_RegisterBits(&status_reg, 5, 2); + + return cycle_position_bits.read(); +} + +/*! + * @brief Reset the new data flag to 0 + * @return True if write succeeded, false otherwise + */ +bool Adafruit_MLX90632::resetNewData() { + Adafruit_BusIO_Register status_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_STATUS), 2, MSBFIRST, 2); + Adafruit_BusIO_RegisterBits new_data_bit = + Adafruit_BusIO_RegisterBits(&status_reg, 1, 0); + + return new_data_bit.write(0); +} + +/*! + * @brief Check if new data is available + * @return True if new data is available, false otherwise + */ +bool Adafruit_MLX90632::isNewData() { + Adafruit_BusIO_Register status_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_STATUS), 2, MSBFIRST, 2); + Adafruit_BusIO_RegisterBits new_data_bit = + Adafruit_BusIO_RegisterBits(&status_reg, 1, 0); + + return new_data_bit.read(); +} + /*! * @brief Byte swap helper for register addresses * @param value 16-bit value to swap diff --git a/Adafruit_MLX90632.h b/Adafruit_MLX90632.h index 2a6d87b..bb99e9a 100644 --- a/Adafruit_MLX90632.h +++ b/Adafruit_MLX90632.h @@ -121,6 +121,28 @@ #define MLX90632_REG_RAM_60 0x403B ///< Raw data 60 /*=========================================================================*/ +/*========================================================================= + CONTROL REGISTER ENUMS + -----------------------------------------------------------------------*/ +/*! + * @brief MLX90632 measurement modes + */ +typedef enum { + MLX90632_MODE_HALT = 0x00, ///< Halt mode for EEPROM operations + MLX90632_MODE_SLEEPING_STEP = 0x01, ///< Sleeping step mode + MLX90632_MODE_STEP = 0x02, ///< Step mode + MLX90632_MODE_CONTINUOUS = 0x03 ///< Continuous mode +} mlx90632_mode_t; + +/*! + * @brief MLX90632 measurement types + */ +typedef enum { + MLX90632_MEAS_MEDICAL = 0x00, ///< Medical measurement + MLX90632_MEAS_EXTENDED_RANGE = 0x11 ///< Extended range measurement +} mlx90632_meas_select_t; +/*=========================================================================*/ + /*! * @brief Class that stores state and functions for interacting with * MLX90632 Far Infrared Temperature Sensor @@ -131,6 +153,19 @@ public: ~Adafruit_MLX90632(); bool begin(uint8_t i2c_addr = MLX90632_DEFAULT_ADDR, TwoWire *wire = &Wire); uint64_t getProductID(); + uint16_t getProductCode(); + bool startSingleMeasurement(); + bool startFullMeasurement(); + bool setMode(mlx90632_mode_t mode); + mlx90632_mode_t getMode(); + bool setMeasurementSelect(mlx90632_meas_select_t meas_select); + mlx90632_meas_select_t getMeasurementSelect(); + bool isBusy(); + bool isEEPROMBusy(); + bool reset(); + uint8_t readCyclePosition(); + bool resetNewData(); + bool isNewData(); private: Adafruit_I2CDevice *i2c_dev; ///< Pointer to I2C bus interface diff --git a/examples/test_MLX90632/test_MLX90632.ino b/examples/test_MLX90632/test_MLX90632.ino index 027bdb9..00bf1eb 100644 --- a/examples/test_MLX90632/test_MLX90632.ino +++ b/examples/test_MLX90632/test_MLX90632.ino @@ -16,12 +16,98 @@ void setup() { } Serial.println("MLX90632 Found!"); + // Reset the device + if (!mlx.reset()) { + Serial.println("Device reset failed"); + while (1) { delay(10); } + } + Serial.println("Device reset: SUCCESS"); + uint64_t productID = mlx.getProductID(); Serial.print("Product ID: 0x"); Serial.print((uint32_t)(productID >> 32), HEX); Serial.println((uint32_t)(productID & 0xFFFFFFFF), HEX); + + uint16_t productCode = mlx.getProductCode(); + Serial.print("Product Code: 0x"); + Serial.println(productCode, HEX); + + // Decode product code bits + uint8_t fov = (productCode >> 8) & 0x3; + uint8_t package = (productCode >> 5) & 0x7; + uint8_t accuracy = productCode & 0x1F; + + Serial.print("FOV: "); + Serial.println(fov == 0 ? "50°" : "Unknown"); + + Serial.print("Package: "); + Serial.println(package == 1 ? "SFN 3x3" : "Unknown"); + + Serial.print("Accuracy: "); + if (accuracy == 1) { + Serial.println("Medical"); + } else if (accuracy == 2) { + Serial.println("Standard"); + } else { + Serial.println("Unknown"); + } + + // Set and get mode (continuous) + Serial.println("\n--- Mode Settings ---"); + if (!mlx.setMode(MLX90632_MODE_CONTINUOUS)) { + Serial.println("Failed to set mode to Continuous"); + while (1) { delay(10); } + } + + mlx90632_mode_t currentMode = mlx.getMode(); + Serial.print("Current mode: "); + switch (currentMode) { + case MLX90632_MODE_HALT: + Serial.println("Halt"); + break; + case MLX90632_MODE_SLEEPING_STEP: + Serial.println("Sleeping Step"); + break; + case MLX90632_MODE_STEP: + Serial.println("Step"); + break; + case MLX90632_MODE_CONTINUOUS: + Serial.println("Continuous"); + break; + default: + Serial.println("Unknown"); + } + + // Set and get measurement select (medical) + Serial.println("\n--- Measurement Select Settings ---"); + if (!mlx.setMeasurementSelect(MLX90632_MEAS_MEDICAL)) { + Serial.println("Failed to set measurement select to Medical"); + while (1) { delay(10); } + } + + mlx90632_meas_select_t currentMeasSelect = mlx.getMeasurementSelect(); + Serial.print("Current measurement select: "); + switch (currentMeasSelect) { + case MLX90632_MEAS_MEDICAL: + Serial.println("Medical"); + break; + case MLX90632_MEAS_EXTENDED_RANGE: + Serial.println("Extended Range"); + break; + default: + Serial.println("Unknown"); + } } void loop() { + Serial.print("Device Busy: "); + Serial.print(mlx.isBusy() ? "YES" : "NO"); + Serial.print(" EEPROM Busy: "); + Serial.print(mlx.isEEPROMBusy() ? "YES" : "NO"); + Serial.print(" New Data: "); + Serial.print(mlx.isNewData() ? "YES" : "NO"); + Serial.print(" Cycle Position: "); + Serial.println(mlx.readCyclePosition()); + delay(500); } \ No newline at end of file