diff --git a/Adafruit_MLX90632.cpp b/Adafruit_MLX90632.cpp index d92f160..1daef48 100644 --- a/Adafruit_MLX90632.cpp +++ b/Adafruit_MLX90632.cpp @@ -87,6 +87,16 @@ uint16_t Adafruit_MLX90632::getProductCode() { return product_code_reg.read(); } +/*! + * @brief Read the EEPROM version + * @return EEPROM version (16-bit value) + */ +uint16_t Adafruit_MLX90632::getEEPROMVersion() { + Adafruit_BusIO_Register version_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_EE_VERSION), 2, MSBFIRST, 2); + return version_reg.read(); +} + /*! * @brief Start a single measurement (SOC) * @return True if write succeeded, false otherwise @@ -249,6 +259,186 @@ bool Adafruit_MLX90632::isNewData() { return new_data_bit.read(); } +/*! + * @brief Set the refresh rate for both measurement registers + * @param refresh_rate The refresh rate to set + * @return True if both writes succeeded, false otherwise + */ +bool Adafruit_MLX90632::setRefreshRate(mlx90632_refresh_rate_t refresh_rate) { + // Set refresh rate in EE_MEAS_1 register (bits 10:8) + Adafruit_BusIO_Register meas1_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_EE_MEAS_1), 2, MSBFIRST, 2); + Adafruit_BusIO_RegisterBits meas1_refresh_bits = + Adafruit_BusIO_RegisterBits(&meas1_reg, 3, 8); + + if (!meas1_refresh_bits.write(refresh_rate)) { + return false; + } + + // Set refresh rate in EE_MEAS_2 register (bits 10:8) + Adafruit_BusIO_Register meas2_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_EE_MEAS_2), 2, MSBFIRST, 2); + Adafruit_BusIO_RegisterBits meas2_refresh_bits = + Adafruit_BusIO_RegisterBits(&meas2_reg, 3, 8); + + return meas2_refresh_bits.write(refresh_rate); +} + +/*! + * @brief Get the refresh rate from EE_MEAS_1 register + * @return The current refresh rate + */ +mlx90632_refresh_rate_t Adafruit_MLX90632::getRefreshRate() { + Adafruit_BusIO_Register meas1_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_EE_MEAS_1), 2, MSBFIRST, 2); + Adafruit_BusIO_RegisterBits meas1_refresh_bits = + Adafruit_BusIO_RegisterBits(&meas1_reg, 3, 8); + + return (mlx90632_refresh_rate_t)meas1_refresh_bits.read(); +} + +/*! + * @brief Helper function to read 32-bit values from consecutive registers + * @param lsw_addr Address of the least significant word register + * @return 32-bit value (LSW + MSW) + */ +uint32_t Adafruit_MLX90632::read32BitRegister(uint16_t lsw_addr) { + Adafruit_BusIO_Register lsw_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(lsw_addr), 2, MSBFIRST, 2); + Adafruit_BusIO_Register msw_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(lsw_addr + 1), 2, MSBFIRST, 2); + + uint16_t lsw = lsw_reg.read(); + uint16_t msw = msw_reg.read(); + + return ((uint32_t)msw << 16) | lsw; +} + +/*! + * @brief Read all calibration constants from EEPROM + * @return True if all reads succeeded, false otherwise + */ +bool Adafruit_MLX90632::getCalibrations() { + // Read 32-bit calibration constants + uint32_t ee_p_r = read32BitRegister(MLX90632_REG_EE_P_R_LSW); + uint32_t ee_p_g = read32BitRegister(MLX90632_REG_EE_P_G_LSW); + uint32_t ee_p_t = read32BitRegister(MLX90632_REG_EE_P_T_LSW); + uint32_t ee_p_o = read32BitRegister(MLX90632_REG_EE_P_O_LSW); + uint32_t ee_aa = read32BitRegister(MLX90632_REG_EE_AA_LSW); + uint32_t ee_ab = read32BitRegister(MLX90632_REG_EE_AB_LSW); + uint32_t ee_ba = read32BitRegister(MLX90632_REG_EE_BA_LSW); + uint32_t ee_bb = read32BitRegister(MLX90632_REG_EE_BB_LSW); + uint32_t ee_ca = read32BitRegister(MLX90632_REG_EE_CA_LSW); + uint32_t ee_cb = read32BitRegister(MLX90632_REG_EE_CB_LSW); + uint32_t ee_da = read32BitRegister(MLX90632_REG_EE_DA_LSW); + uint32_t ee_db = read32BitRegister(MLX90632_REG_EE_DB_LSW); + uint32_t ee_ea = read32BitRegister(MLX90632_REG_EE_EA_LSW); + uint32_t ee_eb = read32BitRegister(MLX90632_REG_EE_EB_LSW); + uint32_t ee_fa = read32BitRegister(MLX90632_REG_EE_FA_LSW); + uint32_t ee_fb = read32BitRegister(MLX90632_REG_EE_FB_LSW); + uint32_t ee_ga = read32BitRegister(MLX90632_REG_EE_GA_LSW); + + // Read 16-bit calibration constants + Adafruit_BusIO_Register gb_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_EE_GB), 2, MSBFIRST, 2); + Adafruit_BusIO_Register ka_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_EE_KA), 2, MSBFIRST, 2); + Adafruit_BusIO_Register kb_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_EE_KB), 2, MSBFIRST, 2); + Adafruit_BusIO_Register ha_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_EE_HA), 2, MSBFIRST, 2); + Adafruit_BusIO_Register hb_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_EE_HB), 2, MSBFIRST, 2); + + // Convert to proper double values with scaling factors from datasheet + P_R = (double)(int32_t)ee_p_r * (double)pow(2, -8); // 2^-8 + P_G = (double)(int32_t)ee_p_g * (double)pow(2, -20); // 2^-20 + P_T = (double)(int32_t)ee_p_t * (double)pow(2, -44); // 2^-44 + P_O = (double)(int32_t)ee_p_o * (double)pow(2, -8); // 2^-8 + Aa = (double)(int32_t)ee_aa * (double)pow(2, -16); // 2^-16 + Ab = (double)(int32_t)ee_ab * (double)pow(2, -8); // 2^-8 + Ba = (double)(int32_t)ee_ba * (double)pow(2, -16); // 2^-16 + Bb = (double)(int32_t)ee_bb * (double)pow(2, -8); // 2^-8 + Ca = (double)(int32_t)ee_ca * (double)pow(2, -16); // 2^-16 + Cb = (double)(int32_t)ee_cb * (double)pow(2, -8); // 2^-8 + Da = (double)(int32_t)ee_da * (double)pow(2, -16); // 2^-16 + Db = (double)(int32_t)ee_db * (double)pow(2, -8); // 2^-8 + Ea = (double)(int32_t)ee_ea * (double)pow(2, -16); // 2^-16 + Eb = (double)(int32_t)ee_eb * (double)pow(2, -8); // 2^-8 + Fa = (double)(int32_t)ee_fa * (double)pow(2, -46); // 2^-46 + Fb = (double)(int32_t)ee_fb * (double)pow(2, -36); // 2^-36 + Ga = (double)(int32_t)ee_ga * (double)pow(2, -36); // 2^-36 + + // 16-bit signed values with scaling + Gb = (double)(int16_t)gb_reg.read() * (double)pow(2, -10); // 2^-10 + Ka = (double)(int16_t)ka_reg.read() * (double)pow(2, -10); // 2^-10 + Kb = (int16_t)kb_reg.read(); // No scaling + Ha = (double)(int16_t)ha_reg.read() * (double)pow(2, -14); // 2^-14 + Hb = (double)(int16_t)hb_reg.read() * (double)pow(2, -10); // 2^-10 + + // Debug: Print calibration constants + Serial.println("Calibration constants:"); + Serial.print("P_R = "); Serial.println(P_R, 8); + Serial.print("P_G = "); Serial.println(P_G, 8); + Serial.print("P_T = "); Serial.println(P_T, 12); + Serial.print("P_O = "); Serial.println(P_O, 8); + Serial.print("Aa = "); Serial.println(Aa, 8); + Serial.print("Ab = "); Serial.println(Ab, 8); + Serial.print("Ba = "); Serial.println(Ba, 8); + Serial.print("Bb = "); Serial.println(Bb, 8); + Serial.print("Ca = "); Serial.println(Ca, 8); + Serial.print("Cb = "); Serial.println(Cb, 8); + Serial.print("Da = "); Serial.println(Da, 8); + Serial.print("Db = "); Serial.println(Db, 8); + Serial.print("Ea = "); Serial.println(Ea, 8); + Serial.print("Eb = "); Serial.println(Eb, 8); + Serial.print("Fa = "); Serial.println(Fa, 12); + Serial.print("Fb = "); Serial.println(Fb, 10); + Serial.print("Ga = "); Serial.println(Ga, 10); + Serial.print("Gb = "); Serial.println(Gb, 8); + Serial.print("Ka = "); Serial.println(Ka, 8); + Serial.print("Kb = "); Serial.println(Kb); + Serial.print("Ha = "); Serial.println(Ha, 8); + Serial.print("Hb = "); Serial.println(Hb, 8); + + return true; +} + +/*! + * @brief Calculate ambient temperature + * @return Ambient temperature in degrees Celsius + */ +double Adafruit_MLX90632::getAmbientTemperature() { + // Read raw data from RAM registers + Adafruit_BusIO_Register ram6_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_6), 2, MSBFIRST, 2); + Adafruit_BusIO_Register ram9_reg = + Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_9), 2, MSBFIRST, 2); + + int16_t ram6 = (int16_t)ram6_reg.read(); + int16_t ram9 = (int16_t)ram9_reg.read(); + + // Pre-calculations for ambient temperature + // Gb = EE_Gb * 2^-10 (already calculated in getCalibrations()) + double VRTA = (double)ram9 + Gb * ((double)ram6 / 12.0); + double AMB = ((double)ram6 / 12.0) / VRTA * (double)pow(2, 19); + + // Calculate ambient temperature: P_O + (AMB - P_R)/P_G + P_T * (AMB - P_R)^2 + double amb_diff = AMB - P_R; + double ambient_temp = P_O + (amb_diff / P_G) + P_T * (amb_diff * amb_diff); + + // Debug output + Serial.print("RAM_6 = "); Serial.println(ram6); + Serial.print("RAM_9 = "); Serial.println(ram9); + Serial.print("Gb = "); Serial.println(Gb, 8); + Serial.print("VRTA = "); Serial.println(VRTA, 8); + Serial.print("AMB = "); Serial.println(AMB, 8); + Serial.print("AMB - P_R = "); Serial.println(amb_diff, 8); + Serial.print("Ambient Temp = "); Serial.println(ambient_temp, 8); + + return ambient_temp; +} + /*! * @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 bb99e9a..030d8e1 100644 --- a/Adafruit_MLX90632.h +++ b/Adafruit_MLX90632.h @@ -141,6 +141,20 @@ typedef enum { MLX90632_MEAS_MEDICAL = 0x00, ///< Medical measurement MLX90632_MEAS_EXTENDED_RANGE = 0x11 ///< Extended range measurement } mlx90632_meas_select_t; + +/*! + * @brief MLX90632 refresh rates + */ +typedef enum { + MLX90632_REFRESH_0_5HZ = 0, ///< 0.5 Hz (2000ms) + MLX90632_REFRESH_1HZ = 1, ///< 1 Hz (1000ms) + MLX90632_REFRESH_2HZ = 2, ///< 2 Hz (500ms) + MLX90632_REFRESH_4HZ = 3, ///< 4 Hz (250ms) + MLX90632_REFRESH_8HZ = 4, ///< 8 Hz (125ms) + MLX90632_REFRESH_16HZ = 5, ///< 16 Hz (62.5ms) + MLX90632_REFRESH_32HZ = 6, ///< 32 Hz (31.25ms) + MLX90632_REFRESH_64HZ = 7 ///< 64 Hz (15.625ms) +} mlx90632_refresh_rate_t; /*=========================================================================*/ /*! @@ -154,6 +168,7 @@ public: bool begin(uint8_t i2c_addr = MLX90632_DEFAULT_ADDR, TwoWire *wire = &Wire); uint64_t getProductID(); uint16_t getProductCode(); + uint16_t getEEPROMVersion(); bool startSingleMeasurement(); bool startFullMeasurement(); bool setMode(mlx90632_mode_t mode); @@ -166,10 +181,39 @@ public: uint8_t readCyclePosition(); bool resetNewData(); bool isNewData(); + bool setRefreshRate(mlx90632_refresh_rate_t refresh_rate); + mlx90632_refresh_rate_t getRefreshRate(); + bool getCalibrations(); + double getAmbientTemperature(); private: Adafruit_I2CDevice *i2c_dev; ///< Pointer to I2C bus interface uint16_t swapBytes(uint16_t value); ///< Byte swap helper for register addresses + uint32_t read32BitRegister(uint16_t lsw_addr); ///< Helper to read 32-bit values + + // Calibration constants + double P_R; ///< P_R calibration constant + double P_G; ///< P_G calibration constant + double P_T; ///< P_T calibration constant + double P_O; ///< P_O calibration constant + double Aa; ///< Aa calibration constant + double Ab; ///< Ab calibration constant + double Ba; ///< Ba calibration constant + double Bb; ///< Bb calibration constant + double Ca; ///< Ca calibration constant + double Cb; ///< Cb calibration constant + double Da; ///< Da calibration constant + double Db; ///< Db calibration constant + double Ea; ///< Ea calibration constant + double Eb; ///< Eb calibration constant + double Fa; ///< Fa calibration constant + double Fb; ///< Fb calibration constant + double Ga; ///< Ga calibration constant + double Gb; ///< Gb calibration constant + double Ka; ///< Ka calibration constant + int16_t Kb; ///< Kb calibration constant (16-bit signed) + double Ha; ///< Ha calibration constant + double Hb; ///< Hb calibration constant }; #endif \ No newline at end of file diff --git a/examples/test_MLX90632/test_MLX90632.ino b/examples/test_MLX90632/test_MLX90632.ino index 00bf1eb..4735b91 100644 --- a/examples/test_MLX90632/test_MLX90632.ino +++ b/examples/test_MLX90632/test_MLX90632.ino @@ -32,6 +32,10 @@ void setup() { Serial.print("Product Code: 0x"); Serial.println(productCode, HEX); + uint16_t eepromVersion = mlx.getEEPROMVersion(); + Serial.print("EEPROM Version: 0x"); + Serial.println(eepromVersion, HEX); + // Decode product code bits uint8_t fov = (productCode >> 8) & 0x3; uint8_t package = (productCode >> 5) & 0x7; @@ -97,6 +101,52 @@ void setup() { default: Serial.println("Unknown"); } + + // Set and get refresh rate (default to 2Hz) + Serial.println("\n--- Refresh Rate Settings ---"); + if (!mlx.setRefreshRate(MLX90632_REFRESH_2HZ)) { + Serial.println("Failed to set refresh rate to 2Hz"); + while (1) { delay(10); } + } + + mlx90632_refresh_rate_t currentRefreshRate = mlx.getRefreshRate(); + Serial.print("Current refresh rate: "); + switch (currentRefreshRate) { + case MLX90632_REFRESH_0_5HZ: + Serial.println("0.5 Hz"); + break; + case MLX90632_REFRESH_1HZ: + Serial.println("1 Hz"); + break; + case MLX90632_REFRESH_2HZ: + Serial.println("2 Hz"); + break; + case MLX90632_REFRESH_4HZ: + Serial.println("4 Hz"); + break; + case MLX90632_REFRESH_8HZ: + Serial.println("8 Hz"); + break; + case MLX90632_REFRESH_16HZ: + Serial.println("16 Hz"); + break; + case MLX90632_REFRESH_32HZ: + Serial.println("32 Hz"); + break; + case MLX90632_REFRESH_64HZ: + Serial.println("64 Hz"); + break; + default: + Serial.println("Unknown"); + } + + // Load calibration constants + Serial.println("\n--- Calibration Constants ---"); + if (!mlx.getCalibrations()) { + Serial.println("Failed to load calibration constants"); + while (1) { delay(10); } + } + Serial.println("Calibration constants loaded successfully"); } void loop() { @@ -109,5 +159,11 @@ void loop() { Serial.print(" Cycle Position: "); Serial.println(mlx.readCyclePosition()); + // Read ambient temperature + double ambientTemp = mlx.getAmbientTemperature(); + Serial.print("Ambient Temperature: "); + Serial.print(ambientTemp, 4); + Serial.println(" °C"); + delay(500); } \ No newline at end of file