diff --git a/Doc/drivers/si72xx.md b/Doc/drivers/si72xx.md new file mode 100644 index 0000000..d5f4954 --- /dev/null +++ b/Doc/drivers/si72xx.md @@ -0,0 +1,85 @@ +# SI72XX - Hall Effect Magnetic Position and Temperature Sensor Driver + +The Si7210 family of Hall effect magnetic sensors from Silicon Labs combines a +chopper-stabilized Hall element with a low-noise analog amplifier, 13-bit +analog-to-digital converter, and an I2C interface. Leveraging Silicon Labs' proven +CMOS design techniques, the Si7210 family incorporates digital signal processing +to provide precise compensation for temperature and offset drift. + +## Sources + - Datasheet: https://www.silabs.com/documents/public/data-sheets/si7210-datasheet.pdf + - Application Note AN1018: https://www.silabs.com/documents/public/application-notes/an1018-si72xx-sensors.pdf + +## Setup the SI72XX +As all the drivers you need to enable it and setup it in the _configDrivers.h_ + +## Using the SI72XX + +### SI72XX HW versions + + +Constant declared in `drivers/hall/si72xx/si72xx.h` + +```C +#define SI72XX_ADDR_0 0x30 +#define SI72XX_ADDR_1 0x31 +#define SI72XX_ADDR_2 0x32 +#define SI72XX_ADDR_3 0x33 +``` + +Based on the sensor version must be used proper I2C address: + - SI72XX_ADDR_0 (0x30): + - Si7210-B-00-IV(R) + - Si7210-B-01-IV(R) + - Si7210-B-10-IM2(R) + - Si7210-B-11-IM2(R) + - SI72XX_ADDR_1 (0x31): + - Si7210-B-02-IV(R) + - Si7210-B-12-IM2(R) + - SI72XX_ADDR_2 (0x32): + - Si7210-B-03-IV(R) + - Si7210-B-13-IM2(R) + - SI72XX_ADDR_3 (0x33): + - Si7210-B-04-IV(R) + - Si7210-B-05-IV(R) + - Si7210-B-14-IM2(R) + - Si7210-B-15-IM2(R) + + +### Measurement of magnetic field + +Read magnetic field with sensor SI72XX_ADDR_0 and go to sleep. + +```C +... + +int16_t data = 0; + +if (Si72xx_ReadMagFieldDataAndSleep(SI72XX_ADDR_0, SI7210_20MT, SI72XX_SLEEP_MODE, &data) == __SI72XX_OK) +{ + return __SI72XX_ERROR; +} + +return data; + +... +``` + +### Measurement of temperature + +Read temperature with sensor SI72XX_ADDR_0 and go to sleep. + +```C +... + +int32_t temp_mC = 0; /* output in milli Celsius */ + +if (Si72xx_ReadTemperatureAndSleep(SI72XX_ADDR_0, &temp_mC) != __SI72XX_OK) +{ + return __SI72XX_ERROR; +} + +return temp_mC; + +... +``` \ No newline at end of file diff --git a/Inc/drivers/hall/si72xx/si72xx.h b/Inc/drivers/hall/si72xx/si72xx.h new file mode 100755 index 0000000..9a63ba0 --- /dev/null +++ b/Inc/drivers/hall/si72xx/si72xx.h @@ -0,0 +1,154 @@ +/* ========================================================== + * si72xx.h - Driver for the Si72xx Hall Effect Sensor + * ---------------------------------------------------------- + * + * Created on: 21 dec 2021 + * Author: Zbynek Kocur + * ---------------------------------------------------------- + * Copyright (C) 2021 CTU in Prague + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU LESSER General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * ========================================================== + * Datasheet - https://www.silabs.com/documents/public/data-sheets/si7210-datasheet.pdf + * App Note - AN1018: Using the Si72xx Hall-effect Magnetic Position Sensors - https://www.silabs.com/documents/public/application-notes/an1018-si72xx-sensors.pdf + * + * ========================================================== + * Some peaces of that code directly comes from Silicon Laboratories Inc. + * and identified with << Copyright 2018 Silicon Laboratories Inc. www.silabs.com >> + * + * ========================================================== + */ + +#ifndef DRIVERS_HALL_SI72XX_SI72XX_H +#define DRIVERS_HALL_SI72XX_SI72XX_H + +/******************************************************************************* + ******************************* DEFINES *********************************** + ******************************************************************************/ + +/** I2C device address for Si72xx */ +#define SI72XX_ADDR_0 0x30 +#define SI72XX_ADDR_1 0x31 +#define SI72XX_ADDR_2 0x32 +#define SI72XX_ADDR_3 0x33 + +/** I2C registers for Si72xx */ +#define SI72XX_HREVID 0xC0 +#define SI72XX_DSPSIGM 0xC1 +#define SI72XX_DSPSIGL 0xC2 +#define SI72XX_DSPSIGSEL 0xC3 +#define SI72XX_POWER_CTRL 0xC4 +#define SI72XX_ARAUTOINC 0xC5 +#define SI72XX_CTRL1 0xC6 +#define SI72XX_CTRL2 0xC7 +#define SI72XX_SLTIME 0xC8 +#define SI72XX_CTRL3 0xC9 +#define SI72XX_A0 0xCA +#define SI72XX_A1 0xCB +#define SI72XX_A2 0xCC +#define SI72XX_CTRL4 0xCD +#define SI72XX_A3 0xCE +#define SI72XX_A4 0xCF +#define SI72XX_A5 0xD0 +#define SI72XX_OTP_ADDR 0xE1 +#define SI72XX_OTP_DATA 0xE2 +#define SI72XX_OTP_CTRL 0xE3 +#define SI72XX_TM_FG 0xE4 + +#define SI72XX_OTP_20MT_ADDR 0x21 +#define SI72XX_OTP_200MT_ADDR 0x27 + +/******************************************************************************* + ******************************** ENUMS ************************************ + ******************************************************************************/ +/** Si72xx magnetic field full-scales */ +typedef enum { + SI7210_20MT, + SI7210_200MT +} Si72xxFieldScale_t; + +/** Si72xx sleep modes */ +typedef enum { + SI72XX_SLEEP_MODE, + SI72XX_SLTIMEENA_MODE, + SI72XX_IDLE_MODE +} Si72xxSleepMode_t; + + +/*! + * @brief Si72xx API status result code. + */ +typedef enum drivers_si72xx_ret_e +{ + __SI72XX_OK = 0, + __SI72XX_ERROR = 1, + __SI72XX_BUSY = 2, + __SI72XX_TIMEOUT = 3, /* until here, I2C errors (cf. _I2C_Status) */ + __SI72XX_NODATA = 4, + __SI72XX_MISCALIB = 5, + __SI72XX_UNKNOWN = 6, + __SI72XX_INVALID_ARG = 7 +} drivers_si72xx_ret_e; + +/******************************************************************************* + ***************************** PROTOTYPES ********************************** + ******************************************************************************/ + +drivers_si72xx_ret_e Si72xx_WakeUpAndIdle(uint8_t addr); +drivers_si72xx_ret_e Si72xx_Read_MagField_Data(uint8_t addr, + int16_t *magData); +drivers_si72xx_ret_e Si72xx_FromIdle_GoToSleep(uint8_t addr); +drivers_si72xx_ret_e Si72xx_FromIdle_GoToSltimeena(uint8_t addr); + +drivers_si72xx_ret_e Si72xx_Set_mT_Range(uint8_t addr, + Si72xxFieldScale_t mTScale); +drivers_si72xx_ret_e Si72xx_ReadMagFieldDataAndSleep(uint8_t addr, + Si72xxFieldScale_t mTScale, + Si72xxSleepMode_t sleepMode, + int16_t *magFieldData); +drivers_si72xx_ret_e Si72xx_EnterSleepMode(uint8_t addr, + Si72xxSleepMode_t sleepMode); +drivers_si72xx_ret_e Si72xx_EnterLatchMode (uint8_t addr); +drivers_si72xx_ret_e Si72xx_ReadTemperatureAndSleep(uint8_t addr, + int32_t *rawTemp); +drivers_si72xx_ret_e Si72xx_ReadCorrectedTempAndSleep(uint8_t addr, + int16_t offsetData, + int16_t gainData, + int32_t *correctedTemp); +drivers_si72xx_ret_e Si72xx_ReadTempCorrectionDataAndSleep(uint8_t addr, + int16_t *offsetValue, + int16_t *gainValue); + +drivers_si72xx_ret_e Si72xx_IdentifyAndSleep(uint8_t addr, + uint8_t *partId, + uint8_t *partRev); +drivers_si72xx_ret_e Si72xx_ReadVariantAndSleep(uint8_t addr, + uint8_t *basePn, + uint8_t *pnVariant); +drivers_si72xx_ret_e Si72xx_SelfTest(uint8_t addr); + + +// ============================================================================================= + + int32_t Si72xx_ConvertDataCodesToMagneticField(Si72xxFieldScale_t fieldScale, int16_t dataCode); + +drivers_si72xx_ret_e Si72xx_Set_Threshold (uint8_t addr, + Si72xxFieldScale_t mTScale, + float threshold); +drivers_si72xx_ret_e Si72xx_Set_Hysteresis (uint8_t addr, + Si72xxFieldScale_t mTScale, + float hysteresis); +drivers_si72xx_ret_e Debug_Si72xx_register (uint8_t addr); + +#endif /* DRIVERS_HALL_SI72XX_SI72XX_H */ diff --git a/Inc/drivers/lorawan/utilities.h b/Inc/drivers/lorawan/utilities.h old mode 100644 new mode 100755 index 84c49e6..47e3faa --- a/Inc/drivers/lorawan/utilities.h +++ b/Inc/drivers/lorawan/utilities.h @@ -70,7 +70,9 @@ typedef uint32_t TimerTime_t; * \param [IN] b 2nd value * \retval minValue Minimum value */ -#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) +#ifndef MIN + #define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) +#endif /*! * \brief Returns the maximum value between a and b @@ -79,8 +81,9 @@ typedef uint32_t TimerTime_t; * \param [IN] b 2nd value * \retval maxValue Maximum value */ -#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) - +#ifndef MAX + #define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) +#endif /*! * \brief Returns 2 raised to the power of n * diff --git a/Inc/it_sdk/configDrivers.h.template b/Inc/it_sdk/configDrivers.h.template index 830123b..f7c30c9 100644 --- a/Inc/it_sdk/configDrivers.h.template +++ b/Inc/it_sdk/configDrivers.h.template @@ -299,5 +299,18 @@ #define ITSDK_DRIVERS_SL353_INT_BANK __BANK_A // HALL pin configuration #define ITSDK_DRIVERS_SL353_INT_PIN __LP_GPIO_0 // __LP_GPIO_NONE if not used +// ------------------------------------------------------------------------ +// Hall : SI72XX + +#define ITSDK_DRIVERS_SI72XX __DISABLE // Si72xx Hall Effect Sensor +#if ITSDK_DRIVERS_SI72XX == __ENABLE + #ifndef __I2C_INCLUDED + #define __I2C_INCLUDED + #include "i2c.h" + #endif + #include +#endif +#define ITSDK_DRIVERS_SI72XX_I2C hi2c1 // I2C port to be used for communications + #endif /* INC_IT_SDK_CONFIGDRIVERS_H_ */ \ No newline at end of file diff --git a/Src/drivers/hall/si72xx/si72xx.c b/Src/drivers/hall/si72xx/si72xx.c new file mode 100755 index 0000000..42c08bc --- /dev/null +++ b/Src/drivers/hall/si72xx/si72xx.c @@ -0,0 +1,1117 @@ +/* ========================================================== + * si72xx.c - Driver for the Si72xx Hall Effect Sensor + * ---------------------------------------------------------- + * + * Created on: 21 dec 2021 + * Author: Zbynek Kocur + * ---------------------------------------------------------- + * Copyright (C) 2021 CTU in Prague + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU LESSER General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * ========================================================== + * Datasheet - https://www.silabs.com/documents/public/data-sheets/si7210-datasheet.pdf + * App Note - AN1018: Using the Si72xx Hall-effect Magnetic Position Sensors - https://www.silabs.com/documents/public/application-notes/an1018-si72xx-sensors.pdf + * + * ========================================================== + * Some peaces of that code directly comes from Silicon Laboratories Inc. + * and identified with << Copyright 2018 Silicon Laboratories Inc. www.silabs.com >> + * + * ========================================================== + */ + +#include + +#include +#include +#include +#include + +#include + + +#if ITSDK_DRIVERS_SI72XX == __ENABLE + +/******************************************************************************* + ******************************* DEFINES *********************************** + ******************************************************************************/ + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +#define SI72XX_SWOP_LATCHMODE 0x7F +#define SI72XX_FIELDPOLSEL_LATCHMODE 2 +#define SI72XX_FIELDPOLSEL_SHIFT 6 +#define SI72XX_SWHYST_LATCHMODE 0x12 + +#define SI72XX_OTP_BUSY_MASK 1 +#define SI72XX_OTP_READ_EN_MASK 2 + +#define SI72XX_DSPSIGSEL_MASK 0x07 +#define SI72XX_DSPSIGSEL_TEMP 0x01 + +#define SI72XX_ZERO_FIELD 16384 +#define SI72XX_FRESH_BIT_MASK 0x80 +#define SI72XX_FRESH_BIT_SHIFT 7 +#define SI72XX_DSPSIGM_MASK 0x7F +#define SI72XX_DSPSIGM_SHIFT 8 + +#define SI72XX_SLEEP_MASK 1 +#define SI72XX_STOP_MASK 2 +#define SI72XX_ONEBURST_MASK 4 +#define SI72XX_USESTORE_MASK 8 +#define SI72XX_POWERCTRL_MASK 0x0F +#define SI72XX_MEASRO_MASK 0x80 +#define SI72XX_MEASRO_SHIFT 7 + +#define SI72XX_SW_LOW4FIELD_MASK 0x80 +#define SI72XX_SW_OP_MASK 0x7F + +#define SI72XX_SWFIELDPOLSEL_MASK 0xC0 +#define SI72XX_SWHYST_MASK 0x3F + +#define SI72XX_SLTIMEENA_MASK 1 +#define SI72XX_SL_FAST_MASK 2 +#define SI72XX_SW_TAMPER_MASK 0xFC + +/* Burst sizes for mag. measurement */ +#define SI72XX_DF_BW_1 0x0U << 1 +#define SI72XX_DF_BW_2 0x1U << 1 +#define SI72XX_DF_BW_4 0x2U << 1 +#define SI72XX_DF_BW_8 0x3U << 1 +#define SI72XX_DF_BW_16 0x4U << 1 +#define SI72XX_DF_BW_32 0x5U << 1 +#define SI72XX_DF_BW_64 0x6U << 1 +#define SI72XX_DF_BW_128 0x7U << 1 /* default */ +#define SI72XX_DF_BW_256 0x8U << 1 +#define SI72XX_DF_BW_512 0x9U << 1 +#define SI72XX_DF_BW_1024 0xAU << 1 +#define SI72XX_DF_BW_2048 0xBU << 1 +#define SI72XX_DF_BW_4096 0xCU << 1 +#define SI72XX_DF_BURSTSIZE_1 0x0U << 5 /* default */ +#define SI72XX_DF_BURSTSIZE_2 0x1U << 5 +#define SI72XX_DF_BURSTSIZE_4 0x2U << 5 +#define SI72XX_DF_BURSTSIZE_8 0x3U << 5 +#define SI72XX_DF_BURSTSIZE_16 0x4U << 5 +#define SI72XX_DF_BURSTSIZE_32 0x5U << 5 +#define SI72XX_DF_BURSTSIZE_64 0x6U << 5 +#define SI72XX_DF_BURSTSIZE_128 0x7U << 5 +#define SI72XX_DFBW_MASK 0x1E +#define SI72XX_DFIIR_MASK 1 + +#define SI72XX_REV_MASK 0x0F +#define SI72XX_ID_MASK 0xF0 +#define SI72XX_ID_SHIFT 4 + +#define SI72XX_BASE_PART_NUMBER 0x14 +#define SI72XX_PART_VARIANT 0x15 + +#define SI72XX_OFFSET_ADDR 0x1D +#define SI72XX_GAIN_ADDR 0x1E +/** @endcond */ + +// macros + +// convert type _I2C_Status -> drivers_si72xx_ret_e +// (which reflects original I2C errors, but it has some extra values) +#define SI72XX_FROM_I2C_STATUS(i2c_st) \ + i2c_st == __I2C_ERROR ? __SI72XX_ERROR : \ + i2c_st == __I2C_BUSY ? __SI72XX_BUSY : \ + i2c_st == __I2C_TIMEOUT ? __SI72XX_TIMEOUT : \ + __SI72XX_UNKNOWN + +/***********************************************************************//** + * @brief + * Reads register from the Si72xx sensor. + * Command can only be issued if Si72xx is idle mode. + * @param[in] i2c + * The I2C peripheral to use (not used). + * @param[in] addr + * The I2C address of the sensor. + * @param[in] reg_addr + * The register address to read from in the sensor. + * @param[out] read_ptr + * The data read from the sensor. + * @return + * the behavior can be changed easily so that it, e.g., does not check the status and only + * OR's the I2C status as follows: i2c_st |= i2c_read8BRegister(...); + **************************************************************************/ +#define SI72XX_READ_8B(reg_addr, read_ptr) \ + i2c_st = i2c_read8BRegister(&ITSDK_DRIVERS_SI72XX_I2C, addr, reg_addr, read_ptr, 1); \ + if (i2c_st != __I2C_OK) \ + { \ + log_info("\r\n(d) ERROR SI72XX_READ_8B\r\n"); \ + res = SI72XX_FROM_I2C_STATUS(i2c_st); \ + goto RETURN; \ + } + +/***********************************************************************//** + * @brief + * Writes register in the Si72xx sensor. + * Command can only be issued if Si72xx is idle mode. + * @param[in] i2c + * The I2C peripheral to use (not used). + * @param[in] addr + * The I2C address of the sensor. + * @param[in] reg_addr + * The register address to write to in the sensor. + * @param[in] write_val + * The data to write to the sensor. + * @return + * the behavior can be changed easily so that it, e.g., does not check the status and only + * OR's the I2C status as follows: i2c_st |= i2c_write8BRegister(...); + **************************************************************************/ +#define SI72XX_WRITE_8B(reg_addr, write_val) \ + i2c_st = i2c_write8BRegister(&ITSDK_DRIVERS_SI72XX_I2C, addr, reg_addr, write_val, 1); \ + if (i2c_st != __I2C_OK) \ + { \ + log_info("\r\n(d) ERROR SI72XX_WRITE_8B\r\n"); \ + res = SI72XX_FROM_I2C_STATUS(i2c_st); \ + goto RETURN; \ + } + +#define SI72XX_INT_CALL(func) \ + res = func; \ + if (res != __SI72XX_OK) goto RETURN; + +// "private" functions + +//static inline int32_t Si72xx_ConvertDataCodesToMagneticField(Si72xxFieldScale_t fieldScale, int16_t dataCode); + + +/***********************************************************************//** + * @brief + * Read out Si72xx Magnetic Field Conversion Data + * Command can only be issued if Si72xx is idle mode. + * @param[in] addr + * The I2C address of the sensor + * @param[out] magData + * Mag-field conversion reading, signed 16-bit integer + **************************************************************************/ +drivers_si72xx_ret_e Si72xx_Read_MagField_Data(uint8_t addr, + int16_t *magData) +{ + // required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call + drivers_si72xx_ret_e res = __SI72XX_OK; + _I2C_Status i2c_st = __I2C_OK; + + uint8_t read = 0; + uint8_t freshBit = 0; + + SI72XX_READ_8B(SI72XX_DSPSIGM, &read); + + freshBit = ((read & SI72XX_FRESH_BIT_MASK) >> SI72XX_FRESH_BIT_SHIFT); + if (freshBit == 0) + { + res = __SI72XX_NODATA; + goto RETURN; + } + + *magData = ((((uint16_t)read) & SI72XX_DSPSIGM_MASK) << SI72XX_DSPSIGM_SHIFT); + + SI72XX_READ_8B(SI72XX_DSPSIGL, &read); + /* Data code output is 15-bit unsigned value where 0mT=16384 */ + *magData |= read; + /* Converts data code output to a signed integer */ + *magData = *magData - SI72XX_ZERO_FIELD; + + RETURN: + return res; +} + +/***********************************************************************//** + * @brief + * Puts Si72xx into Sleep mode (lowest power).. + * Command can only be issued if Si72xx is idle mode. + * @param[in] addr + * The I2C address of the sensor. + **************************************************************************/ +drivers_si72xx_ret_e Si72xx_FromIdle_GoToSleep(uint8_t addr) +{ + // required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call + drivers_si72xx_ret_e res = __SI72XX_OK; + _I2C_Status i2c_st = __I2C_OK; + + uint8_t read = 0; + + SI72XX_READ_8B(SI72XX_CTRL3, &read); + read = (read & (~SI72XX_SLTIMEENA_MASK)); + SI72XX_WRITE_8B(SI72XX_CTRL3, read); + SI72XX_READ_8B(SI72XX_POWER_CTRL, &read); + read = (read | SI72XX_SLEEP_MASK); + SI72XX_WRITE_8B(SI72XX_POWER_CTRL, read); + + RETURN: + return res; +} + +/***********************************************************************//** + * @brief + * Puts Si72xx into Sleep-Timer-Enable mode. + * Si72xx periodically wakes-up, samples the magnetic field, updates the + * output, and goes back to sleep-timer-enabled mode. + * Command can only be issued if Si72xx is idle mode. + * @param[in] addr + * The I2C address of the sensor. + **************************************************************************/ +drivers_si72xx_ret_e Si72xx_FromIdle_GoToSltimeena(uint8_t addr) +{ + // required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call + drivers_si72xx_ret_e res = __SI72XX_OK; + _I2C_Status i2c_st = __I2C_OK; + + /* To store read register value */ + uint8_t read = 0; + + /* Setting SLTIMEENA to enable the sleep timer in order to make periodic measurements and update output pin + * Resetting ONEBURST, SLEEP and STOP to don't go to classic sleep + * Setting USESTORE to not reloaded after each sleep cycle the SI72XX_CTRL1 and SI72XX_CTRL2 registers + * */ + SI72XX_READ_8B(SI72XX_CTRL3, &read); + read = ((read & ~SI72XX_SL_FAST_MASK) | SI72XX_SLTIMEENA_MASK); + SI72XX_WRITE_8B(SI72XX_CTRL3, read); + SI72XX_READ_8B(SI72XX_POWER_CTRL, &read); + /* Reset the ONEBURST, SLEEP and STOP bits + * Set the USESTORE bit + * */ + read = (read & ~( SI72XX_ONEBURST_MASK | + SI72XX_STOP_MASK | + SI72XX_SLEEP_MASK)) | + SI72XX_USESTORE_MASK; + SI72XX_WRITE_8B(SI72XX_POWER_CTRL, read); + + RETURN: + return res; +} + + + +/***********************************************************************//** + * @brief + * Wake-up Si72xx and places sensor in idle-mode. + * @param[in] addr + * The I2C address of the sensor. + * @return + * Returns zero on success. Otherwise returns error codes + * based on the I2CCSPM + **************************************************************************/ + +drivers_si72xx_ret_e Si72xx_WakeUpAndIdle(uint8_t devAdr) +{ + uint8_t value; + + if (i2c_write(&ITSDK_DRIVERS_SI72XX_I2C, devAdr, NULL, 0) != __I2C_OK) + return __I2C_ERROR; + + return i2c_read(&ITSDK_DRIVERS_SI72XX_I2C, devAdr, &value, 1); + +} + + +/***********************************************************************//** + * @brief + * Read Si72xx OTP Data + * Command can only be issued if Si72xx is idle mode. + * @param[in] addr + * The I2C address of the sensor + * @param[in] otpAddr + * The OTB Byte address of the coefficients + * @param[out] data + * OTP data read out + **************************************************************************/ +drivers_si72xx_ret_e Si72xx_Read_OTP(uint8_t addr, + uint8_t otpAddr, + uint8_t *otpData) +{ + // required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call + drivers_si72xx_ret_e res = __SI72XX_OK; + _I2C_Status i2c_st = __I2C_OK; + + uint8_t read = 0; + + SI72XX_READ_8B(SI72XX_OTP_CTRL, &read); + if (read & SI72XX_OTP_BUSY_MASK) + return __SI72XX_BUSY; + + SI72XX_WRITE_8B(SI72XX_OTP_ADDR, otpAddr); + SI72XX_WRITE_8B(SI72XX_OTP_CTRL, SI72XX_OTP_READ_EN_MASK); + SI72XX_READ_8B(SI72XX_OTP_DATA, &read); + + *otpData = read; + + RETURN: + return res; +} + +/***********************************************************************//** + * @brief + * Set magnetic-field output range, 20mT or 200mT full-scale + * Command can only be issued if Si72xx is idle mode. + * @param[in] addr + * The I2C address of the sensor + * @param[in] mTScale + * 20mT or 200mT + **************************************************************************/ +drivers_si72xx_ret_e Si72xx_Set_mT_Range(uint8_t addr, + Si72xxFieldScale_t mTScale) +{ + // required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call + drivers_si72xx_ret_e res = __SI72XX_OK; + _I2C_Status i2c_st = __I2C_OK; + + uint8_t srcAddr = 0; + uint8_t data = 0; + + if (mTScale == SI7210_20MT) + { + srcAddr = SI72XX_OTP_20MT_ADDR; + } + else if (mTScale == SI7210_200MT) + { + srcAddr = SI72XX_OTP_200MT_ADDR; + } + + SI72XX_INT_CALL(Si72xx_Read_OTP(addr, srcAddr++, &data)) + SI72XX_WRITE_8B(SI72XX_A0, data); + SI72XX_INT_CALL(Si72xx_Read_OTP(addr, srcAddr++, &data)) + SI72XX_WRITE_8B(SI72XX_A1, data); + SI72XX_INT_CALL(Si72xx_Read_OTP(addr, srcAddr++, &data)) + SI72XX_WRITE_8B(SI72XX_A2, data); + SI72XX_INT_CALL(Si72xx_Read_OTP(addr, srcAddr++, &data)) + SI72XX_WRITE_8B(SI72XX_A3, data); + SI72XX_INT_CALL(Si72xx_Read_OTP(addr, srcAddr++, &data)) + SI72XX_WRITE_8B(SI72XX_A4, data); + SI72XX_INT_CALL(Si72xx_Read_OTP(addr, srcAddr++, &data)) + SI72XX_WRITE_8B(SI72XX_A5, data); + + RETURN: + return res; +} + +/***********************************************************************//** + * @brief + * Wake-up SI72xx, performs a magnetic-field conversion with FIR, + * and places Si72xx back to sleep-mode or idle. + * @param[in] addr + * The I2C address of the sensor + * @param[in] mTScale + * mTScale= Si7210_20MT: 20mT full-scale magnetic-field range + * mTScale= Si7210_200MT: 200mT full-scale magnetic-field range + * @param[in] sleepMode + * SI72XX_SLEEP: Sleep mode. Lowest power & doesn't update output + * SI72XX_SLTIMEENA: Sleep-Timer-Enabled mode. Updates output periodically + * SI72XX_IDLE: No sleep + * @param[out] magFieldData + * Magnetic-field conversion reading, signed 16-bit integer + **************************************************************************/ +drivers_si72xx_ret_e Si72xx_ReadMagFieldDataAndSleep(uint8_t addr, + Si72xxFieldScale_t mTScale, + Si72xxSleepMode_t sleepMode, + int16_t *magFieldData) +{ + // required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call + drivers_si72xx_ret_e res = __SI72XX_OK; + _I2C_Status i2c_st = __I2C_OK; + + /* to get register value */ + uint8_t read = 0; + + SI72XX_INT_CALL(Si72xx_WakeUpAndIdle(addr)) + + /* set the stop-bit */ + SI72XX_READ_8B(SI72XX_POWER_CTRL, &read); + read = ((read & ~SI72XX_POWERCTRL_MASK) | SI72XX_STOP_MASK); + SI72XX_WRITE_8B(SI72XX_POWER_CTRL, read); + + SI72XX_INT_CALL(Si72xx_Set_mT_Range(addr, mTScale)) + + /* Set the burst-size for averaging */ + SI72XX_WRITE_8B(SI72XX_CTRL4, SI72XX_DF_BURSTSIZE_1 | SI72XX_DF_BW_128); // SI72XX_DF_BURSTSIZE_128 | SI72XX_DF_BW_4096 + + /* Perform a magnetic field conversion */ + SI72XX_READ_8B(SI72XX_POWER_CTRL, &read); + read = ((read & ~SI72XX_POWERCTRL_MASK) | SI72XX_ONEBURST_MASK); + SI72XX_WRITE_8B(SI72XX_POWER_CTRL, read); + + /* Wait for measurement to complete */ + SI72XX_READ_8B(SI72XX_POWER_CTRL, &read); + while ((read & SI72XX_MEASRO_MASK) >> SI72XX_MEASRO_SHIFT) + { + SI72XX_READ_8B(SI72XX_POWER_CTRL, &read); + } + + SI72XX_INT_CALL(Si72xx_Read_MagField_Data(addr, magFieldData)) + + switch (sleepMode) + { + case SI72XX_SLEEP_MODE : + SI72XX_INT_CALL(Si72xx_FromIdle_GoToSleep(addr)) + break; + case SI72XX_SLTIMEENA_MODE : + SI72XX_INT_CALL(Si72xx_FromIdle_GoToSltimeena(addr)) + break; + case SI72XX_IDLE_MODE : + // TODO + break; + default : + ; + } + + RETURN: + return res; +} + +/***********************************************************************//** + * @brief + * Wake-up Si72xx, and set sleep-mode option. + * If Si72xx is in a sleep-mode, it requires a wake-up command first. + * Useful for placing Si72xx in SLTIMEENA mode from SLEEP mode, + * or vice-versa. + * @param[in] addr + * The I2C address of the sensor + * @param[in] sleepMode + * SI72XX_SLEEP: Puts Si72xx into sleep mode. Lowest power & doesn't update + * SI72XX_SLTIMEENA: Si72xx into sltimeena mode. Updates output periodically + **************************************************************************/ +drivers_si72xx_ret_e Si72xx_EnterSleepMode(uint8_t addr, + Si72xxSleepMode_t sleepMode) +{ + // required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call + drivers_si72xx_ret_e res = __SI72XX_OK; + + SI72XX_INT_CALL(Si72xx_WakeUpAndIdle(addr)) + + switch (sleepMode) + { + case SI72XX_SLEEP_MODE : + SI72XX_INT_CALL(Si72xx_FromIdle_GoToSleep(addr)) + break; + case SI72XX_SLTIMEENA_MODE : + SI72XX_INT_CALL(Si72xx_FromIdle_GoToSltimeena(addr)) + break; + case SI72XX_IDLE_MODE : + // TODO + break; + default : + ; + } + + RETURN: + return res; +} + +/***********************************************************************//** + * @brief + * Wake-up Si72xx, and configures output for Latch mode. + * Switch point = 0mT w/ 0.2mT hysteresis + * @param[in] addr + * The I2C address of the sensor + **************************************************************************/ +drivers_si72xx_ret_e Si72xx_EnterLatchMode(uint8_t addr) +{ + // required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call + drivers_si72xx_ret_e res = __SI72XX_OK; + _I2C_Status i2c_st = __I2C_OK; + + uint8_t read = 0; + + SI72XX_INT_CALL(Si72xx_WakeUpAndIdle(addr)) + + /* Set Stop-bit */ + SI72XX_READ_8B(SI72XX_POWER_CTRL, &read); + read = (read | SI72XX_USESTORE_MASK | SI72XX_STOP_MASK); + SI72XX_WRITE_8B(SI72XX_POWER_CTRL, read); + + /* Set output high for low magnetic field */ + /* Set sw_op to zero for latch mode */ + read = (SI72XX_SWOP_LATCHMODE | SI72XX_SW_LOW4FIELD_MASK); + SI72XX_WRITE_8B(SI72XX_CTRL1, read); + + /* Set output to unipolar positive with hysteresis = 0.2mT */ + read = ((SI72XX_FIELDPOLSEL_LATCHMODE << SI72XX_FIELDPOLSEL_SHIFT) + | SI72XX_SWHYST_LATCHMODE); + SI72XX_WRITE_8B(SI72XX_CTRL2, read); + + /* Enable the sleep-timer for periodic measurements */ + SI72XX_READ_8B(SI72XX_CTRL3, &read); + read = (read | SI72XX_SLTIMEENA_MASK); + SI72XX_WRITE_8B(SI72XX_CTRL3, read); + + /* Clear stop-bit */ + SI72XX_READ_8B(SI72XX_POWER_CTRL, &read); + read = (read & ~SI72XX_STOP_MASK); + SI72XX_WRITE_8B(SI72XX_POWER_CTRL, read); + + RETURN: + return res; +} + +/***********************************************************************//** + * @brief + * Wakes up SI72xx, performs temperature conversion and places Si72xx + * into SI72XX_SLEEP sleep-mode. + * @param[in] addr + * The I2C address of the sensor + * @param[out] temp + * Temperature measurement in millidegree Celsius + **************************************************************************/ +drivers_si72xx_ret_e Si72xx_ReadTemperatureAndSleep(uint8_t addr, + int32_t *rawTemp) +{ + // required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call + drivers_si72xx_ret_e res = __SI72XX_OK; + _I2C_Status i2c_st = __I2C_OK; + + uint8_t read = 0; + uint8_t dspSigM, dspSigL; + uint8_t freshBit; + int16_t dataValue; + int32_t milliCelsius; + + uint16_t tempCtrl4Setting = 0x00; + + SI72XX_INT_CALL(Si72xx_WakeUpAndIdle(addr)) + + /* Set stop-bit */ + SI72XX_READ_8B(SI72XX_POWER_CTRL, &read); + read = ((read & ~SI72XX_POWERCTRL_MASK) | SI72XX_STOP_MASK); + SI72XX_WRITE_8B(SI72XX_POWER_CTRL, read); + + /* clear IIR & FIR filtering */ + SI72XX_WRITE_8B(SI72XX_CTRL4, tempCtrl4Setting); + + /* Select temperature conversion */ + SI72XX_READ_8B(SI72XX_DSPSIGSEL, &read); + read = ((read & ~SI72XX_DSPSIGSEL_MASK) | SI72XX_DSPSIGSEL_TEMP); + SI72XX_WRITE_8B(SI72XX_DSPSIGSEL, read); + + /* Perform temperature conversion */ + SI72XX_READ_8B(SI72XX_POWER_CTRL, &read); + read = (((read & (~SI72XX_STOP_MASK)) & ~(SI72XX_SLEEP_MASK)) + | SI72XX_ONEBURST_MASK); + SI72XX_WRITE_8B(SI72XX_POWER_CTRL, read); + + /* Read conversion res */ + SI72XX_READ_8B(SI72XX_DSPSIGM, &dspSigM); + SI72XX_READ_8B(SI72XX_DSPSIGL, &dspSigL); + + SI72XX_INT_CALL(Si72xx_FromIdle_GoToSleep(addr)) + + freshBit = dspSigM >> SI72XX_FRESH_BIT_SHIFT; + if (freshBit == 0) + { + res = __SI72XX_NODATA; + goto RETURN; + } + + /* dataValue = (Dspigm[6:0]<<5) + (Dspigl[7:0]>>3) */ + dataValue = (((uint16_t)dspSigM) & SI72XX_DSPSIGM_MASK) << 8; + dataValue = (dataValue | dspSigL) >> 3; + + /* rawTemp(mC) = ((dataValue^2)*(-3.83*10^-6))+(0.16094*dataValue)-279.8 */ + milliCelsius = ((int32_t)dataValue * (int32_t)dataValue * -383 / 100000) + + ((16094 * dataValue) / 100) - 279800; + + *rawTemp = milliCelsius; + + RETURN: + return res; +} + +/***********************************************************************//** + * @brief + * Wakes up SI72xx, performs temperature conversion and places Si72xx + * into SI72XX_SLEEP sleep-mode. + * @param[in] addr + * The I2C address of the sensor + * @param[out] offsetValue + * Temperature offset correction + * @param[out] gainValue + * Temperature gain correction + **************************************************************************/ +drivers_si72xx_ret_e Si72xx_ReadTempCorrectionDataAndSleep(uint8_t addr, + int16_t *offsetValue, + int16_t *gainValue) +{ + // required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call + drivers_si72xx_ret_e res = __SI72XX_OK; + _I2C_Status i2c_st = __I2C_OK; + + uint8_t read = 0; + + SI72XX_INT_CALL(Si72xx_WakeUpAndIdle(addr)) + + /* Set Stop-bit */ + SI72XX_READ_8B(SI72XX_POWER_CTRL, &read); + read = ((read & ~SI72XX_POWERCTRL_MASK) | SI72XX_STOP_MASK); + SI72XX_WRITE_8B(SI72XX_POWER_CTRL, read); + + /* Read offset register value */ + SI72XX_INT_CALL(Si72xx_Read_OTP(addr, SI72XX_OFFSET_ADDR, &read)) + /* Calculate offset: Offset = value(0x1D)/16 */ + *offsetValue = (int8_t)read * 1000 / 16; + + /* Read gain register value */ + SI72XX_INT_CALL(Si72xx_Read_OTP(addr, SI72XX_GAIN_ADDR, &read)) + /* calculate gain: Gain = (value(0x1E)/2048) + 1 */ + *gainValue = ((int8_t)read * 1000 / 2048) + 1000; + + SI72XX_INT_CALL(Si72xx_FromIdle_GoToSleep(addr)) + + RETURN: + return res; +} + +/**************************************************************************//** + * @brief + * Wakes up SI72xx, performs a temperature conversion, and places sensor + * back to sleep. Temperature calculation is performed using compensation + * data. + * @param[out] temp + * Temperature measurement in millidegree Celsius + * @param[in] offsetData + * Offset correction data + * @param[in] gainData + * Gain correction data + *****************************************************************************/ +drivers_si72xx_ret_e Si72xx_ReadCorrectedTempAndSleep(uint8_t addr, + int16_t offsetData, + int16_t gainData, + int32_t *correctedTemp) +{ + // required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call + drivers_si72xx_ret_e res = __SI72XX_OK; + _I2C_Status i2c_st = __I2C_OK; + + uint8_t read = 0; + uint8_t dspSigM, dspSigL; + uint8_t freshBit; + int16_t dataValue; + int32_t rawTemp; + int32_t milliCelsius; + + uint16_t tempCtrl4Setting = 0x00; + + SI72XX_INT_CALL(Si72xx_WakeUpAndIdle(addr)) + + /* Set stop-bit */ + SI72XX_READ_8B(SI72XX_POWER_CTRL, &read); + read = ((read & ~SI72XX_POWERCTRL_MASK) | SI72XX_STOP_MASK); + SI72XX_WRITE_8B(SI72XX_POWER_CTRL, read); + + /* Clear IIR and FIR filtering */ + SI72XX_WRITE_8B(SI72XX_CTRL4, tempCtrl4Setting); + + /* Select Temperature conversion */ + SI72XX_READ_8B(SI72XX_DSPSIGSEL, &read); + read = ((read & ~SI72XX_DSPSIGSEL_MASK) | SI72XX_DSPSIGSEL_TEMP); + SI72XX_WRITE_8B(SI72XX_DSPSIGSEL, read); + + /* Perform temperature conversion */ + SI72XX_READ_8B(SI72XX_POWER_CTRL, &read); + read = (((read & (~SI72XX_STOP_MASK)) & ~(SI72XX_SLEEP_MASK)) + | SI72XX_ONEBURST_MASK); + SI72XX_WRITE_8B(SI72XX_POWER_CTRL, read); + + /* Read temperature conversion result */ + SI72XX_READ_8B(SI72XX_DSPSIGM, &dspSigM); + SI72XX_READ_8B(SI72XX_DSPSIGL, &dspSigL); + + SI72XX_INT_CALL(Si72xx_FromIdle_GoToSleep(addr)) + + freshBit = dspSigM >> SI72XX_FRESH_BIT_SHIFT; + if (freshBit == 0) + { + res = __SI72XX_NODATA; + goto RETURN; + } + + /* dataValue = (Dspigm[6:0]<<5) + (Dspigl[7:0]>>3) */ + dataValue = (((uint16_t)dspSigM) & SI72XX_DSPSIGM_MASK) << 8; + dataValue = (dataValue | dspSigL) >> 3; + + /* rawTemp equation is from Si7210 datasheet */ + /* rawTemp(mC) = ((dataValue^2)*(-3.83*10^-6))+(0.16094*dataValue)-279.8 */ + rawTemp = ((int32_t)dataValue * (int32_t)dataValue * -383 / 100000) + + ((16094 * dataValue) / 100) - 279800; + + milliCelsius = ((rawTemp * (int32_t)gainData) + offsetData) / 1000; + + *correctedTemp = milliCelsius; + + RETURN: + return res; +} + +/************************************************************************** + * @brief + * Wake-up Si72xx, read out part Revision and ID, and place Si72xx + * back to SLEEP sleep-mode. + * @param[in] addr + * The I2C address of the sensor + * @param[out] partId + * Si7210 part ID + * @param[out] partRev + * Si72xx part Revision + **************************************************************************/ +drivers_si72xx_ret_e Si72xx_IdentifyAndSleep(uint8_t addr, + uint8_t *partId, + uint8_t *partRev) +{ + // required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call + drivers_si72xx_ret_e res = __SI72XX_OK; + _I2C_Status i2c_st = __I2C_OK; + + uint8_t read = 0; + + SI72XX_INT_CALL(Si72xx_WakeUpAndIdle(addr)) + SI72XX_READ_8B(SI72XX_POWER_CTRL, &read); + SI72XX_WRITE_8B(SI72XX_POWER_CTRL, (read | SI72XX_STOP_MASK)); + SI72XX_READ_8B(SI72XX_HREVID, &read); + SI72XX_INT_CALL(Si72xx_FromIdle_GoToSleep(addr)) + + *partRev = read & SI72XX_REV_MASK; + *partId = read >> SI72XX_ID_SHIFT; + + RETURN: + return res; +} + +/************************************************************************** + * @brief + * Wake-up Si72xx, read out Si72xx base part-number and variant, and + * place sensor back to SLEEP sleep-mode. + * @param[in] addr + * The I2C address of the sensor + * @param[out] basePn + * Si7210 part ID + * @param[out] partRev + * Si72xx part Revision + **************************************************************************/ +drivers_si72xx_ret_e Si72xx_ReadVariantAndSleep(uint8_t addr, + uint8_t *basePn, + uint8_t *pnVariant) +{ + // required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call + drivers_si72xx_ret_e res = __SI72XX_OK; + + uint8_t read = 0; + + SI72XX_INT_CALL(Si72xx_WakeUpAndIdle(addr)) + SI72XX_INT_CALL(Si72xx_Read_OTP(addr, SI72XX_BASE_PART_NUMBER, &read)) + *basePn = read; + SI72XX_INT_CALL(Si72xx_Read_OTP(addr, SI72XX_PART_VARIANT, &read)) + *pnVariant = read; + SI72XX_INT_CALL(Si72xx_FromIdle_GoToSleep(addr)) + + RETURN: + return res; +} + +/************************************************************************** + * @brief + * Self-test sequence offered by the device. It uses an internal + * coil to generate and test the + and - field. + * @param[in] addr + * The I2C address of the sensor + **************************************************************************/ +drivers_si72xx_ret_e Si72xx_SelfTest(uint8_t addr) +{ + // required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call + drivers_si72xx_ret_e res = __SI72XX_OK; + _I2C_Status i2c_st = __I2C_OK; + + int16_t field_pos = 0; + int16_t field_neg = 0; + + /* Enable test field generator coil in POSITIVE direction. */ + SI72XX_INT_CALL(Si72xx_WakeUpAndIdle(addr)) + SI72XX_WRITE_8B(SI72XX_TM_FG, 1); + + /* Measure field strength */ + SI72XX_INT_CALL(Si72xx_ReadMagFieldDataAndSleep(addr, SI7210_200MT, SI72XX_IDLE_MODE, &field_pos)); // 200mT + field_pos = Si72xx_ConvertDataCodesToMagneticField(SI7210_200MT, field_pos)/1000; + + /* Enable test field generator coil in POSITIVE direction. */ + SI72XX_WRITE_8B(SI72XX_TM_FG, 2); + + /* Measure field strength */ + SI72XX_INT_CALL(Si72xx_ReadMagFieldDataAndSleep(addr, SI7210_200MT, SI72XX_IDLE_MODE, &field_neg)) + field_neg = Si72xx_ConvertDataCodesToMagneticField(SI7210_200MT, field_neg)/1000; + + /* Disable test field generator coil. */ + SI72XX_WRITE_8B(SI72XX_TM_FG, 0); + + /* Send to sleep mode */ + SI72XX_INT_CALL(Si72xx_EnterSleepMode(addr, SI72XX_SLEEP_MODE)) + + /* Vdd of SI7210. This is used in device's self-test calculations */ +#define SI72xx_VDD (3.3f) + + float b_out = 1.16 * SI72xx_VDD; + float b_upper = b_out + (b_out * 0.25); /* +25% */ + float b_lower = b_out - (b_out * 0.25); /* -25% */ + + if( (field_pos <= b_upper) && + (field_pos >= b_lower) && + (field_neg >= (b_upper * -1)) && + (field_neg <= (b_lower * -1))) + { + log_info("(i) Sensor 0x%X self test PASS\r\n", addr); + } + else + { + log_info("(i) Sensor 0x%X self test FAIL!\r\n", addr); + res = __SI72XX_MISCALIB; + goto RETURN; + } + + RETURN: + return res; +} + +/**************************************************************************** + * @brief Convert Si7210 I2C Data Readings to Magnetic Field in microTeslas + * @param[in] fieldScale + * 20mT or 200mT full-scale magnetic field range + * @param[in] dataCodes + * signed 15bit value read from hall sensor after magnetic field conversion + * @return microTeslas + *****************************************************************************/ +//static inline int32_t Si72xx_ConvertDataCodesToMagneticField(Si72xxFieldScale_t fieldScale, int16_t dataCode) +int32_t Si72xx_ConvertDataCodesToMagneticField(Si72xxFieldScale_t fieldScale, int16_t dataCode) +{ + switch (fieldScale) + { + case SI7210_20MT : + /* 20mT: 1(LSB) = 1.25uT */ + return (dataCode * 125) / 100; + case SI7210_200MT : + /* 200mT: 1(LSB) = 12.5uT */ + return (dataCode * 125) / 10; + default : + return 0; + } +} + + + + +// ============================================================================= + + +/************************************************************************** + * @brief + * Function to set threshold value in sw_op register of Si7210 sensor (based on application note AN1018 and https://github.com/FARLY7/si7210-driver) + * Command can only be issued if Si72xx is idle mode. + * @param[in] addr + * The I2C address of the sensor + * @param[in] mTScale + * The magnetic scale sensor + * @param[in] threshold + * The threshold value in mT. Threshold value available from 0.08 mT to 19.2 mT (for 20 mT scale) or 0.8 mT to 192 mT (for 200 mT scale) + **************************************************************************/ +drivers_si72xx_ret_e Si72xx_Set_Threshold (uint8_t addr, Si72xxFieldScale_t mTScale, float threshold) +{ + /* required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call */ + drivers_si72xx_ret_e res = __SI72XX_OK; + _I2C_Status i2c_st = __I2C_OK; + + /* hysteresis value set to 10% of the threshold */ + float hysteresis = threshold * 0.1; + + /* Idle mode */ + SI72XX_INT_CALL(Si72xx_WakeUpAndIdle(addr)); + + /* Verifying the threshold value according to the scale */ + if (mTScale != SI7210_200MT && mTScale != SI7210_20MT) + { + return __SI72XX_INVALID_ARG; + } + + /* To store read register value */ + uint8_t read = 0; + SI72XX_READ_8B(SI72XX_POWER_CTRL, &read); + SI72XX_WRITE_8B(SI72XX_POWER_CTRL, (read & ~SI72XX_USESTORE_MASK) | SI72XX_STOP_MASK); /* Set the STOP bit */ + + /* Calculation of the threshold value and adapt his scale according to datasheet */ + if (mTScale == SI7210_200MT) + { + /* x20 (LSB = 0.05 mT) to adapt the range from 200mT to 4000 */ + threshold *= 20.0; + } + else + { + /* x200 (LSB = 0.005 mT) : to adapt the range from 20mT to 4000 */ + threshold *= 200.0; + } + + /* Available range from 16 to 3840, + * from 0.08 mT to 19.2 mT (20 mT scale) or 0.8 mT to 192 mT (200 mT scale) */ + if(threshold < 16) + { + threshold = 16; + } + else if (threshold > 3840) + { + threshold = 3840; + } + + /* sw_op register to fill for threshold + * threshold = ( 16 + sw_op[3:0] ) × 2^sw_op[6:4] */ + uint8_t div2_thr = 0; + + /* 4 bits max value : 15 */ + while (threshold >= 32) + { + threshold /= 2; + div2_thr++; + } + threshold -= 16; + + + /* Build the register value */ + uint8_t ctrl1 = 0; /* reset sw_low4field to have 0V by default on alert pin */ + ctrl1 |= ((div2_thr & 0x07) << 4) | ((uint8_t)(roundf(threshold)) & 0x0F); + + /* Write ctrl1 into SI72XX_CTRL1 register */ + SI72XX_WRITE_8B(SI72XX_CTRL1, ctrl1); + + RETURN: + return res; +} + + + +/************************************************************************** + * @brief + * Function to set hysteresis value in sw_hyst register of Si7210 sensor (based on application note AN1018) + * Command can only be issued if Si72xx is idle mode. + * @param[in] addr + * The I2C address of the sensor + * @param[in] mTScale + * The magnetic scale sensor + * @param[in] hysteresis + * The hysteresis value in mT. Hysteresis value available from 0.04 mT to 8.96 mT (for 20 mT scale) or 0.4 mT to 89.6 mT (for 200 mT scale) + **************************************************************************/ +drivers_si72xx_ret_e Si72xx_Set_Hysteresis (uint8_t addr, Si72xxFieldScale_t mTScale, float hysteresis) +{ + /* required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call */ + drivers_si72xx_ret_e res = __SI72XX_OK; + _I2C_Status i2c_st = __I2C_OK; + + /* Idle mode */ + SI72XX_INT_CALL(Si72xx_WakeUpAndIdle(addr)); + + /****************************************************/ + /* SET HYSTERESIS */ + /****************************************************/ + + /* Calculation of the hysteresis value and adapt his scale according to datasheet + * LSB = 0.005 mT */ + if (mTScale == SI7210_200MT) + { + /* x20 to adapt the range from 90 mT to 2000 */ + hysteresis *= 20.0; + } + else if (mTScale == SI7210_20MT) + { + /* x200 : to adapt the range from 9 mT to 2000 */ + hysteresis *= 200.0; + } + else + { + return __SI72XX_INVALID_ARG; + } + + /* Available range from 8 to 1792, + * from 0.04 mT to 8.96 mT (20 mT scale) or 0.4 mT to 89.6 mT (200 mT scale) */ + if (hysteresis < 8) + { + hysteresis = 8; + } + else if (hysteresis > 1792) + { + hysteresis = 1792; + } + + /* sw_hyst register to fill for hysteresis + * hysteresis = (8 + sw_hyst[2:0]) × 2^sw_hyst[5:3] */ + uint8_t div2_hys = 0; + + /* 3 bits max value : 7 */ + while (hysteresis >= 16) + { + hysteresis /= 2; + div2_hys++; + } + hysteresis -= 8; + + /* Build the register value + * sw_fieldpolsel = 0b00 => absolute value field to compare with threshold + * sw_hyst = 0b00 0000 */ + uint8_t ctrl2 = 0; /* reset sw_fieldpolsel to compare with absolute value */ + ctrl2 |= ((div2_hys & 0x07) << 3) | ((uint8_t)(roundf(hysteresis)) & 0x07); + + /* Write ctrl2 into SI72XX_CTRL2 register */ + SI72XX_WRITE_8B(SI72XX_CTRL2, ctrl2); + + RETURN: + return res; +} + + + + + +/************************************************************************** + * @brief + * Print some of the hall sensor registers. + * Command can only be issued if Si72xx is idle mode. + * @param[in] addr + * The I2C address of the sensor + **************************************************************************/ +drivers_si72xx_ret_e Debug_Si72xx_register (uint8_t addr) +{ + // required for SI72XX_READ/WRITE_8B / SI72XX_INT_CALL macro call + drivers_si72xx_ret_e res = __SI72XX_OK; + _I2C_Status i2c_st = __I2C_OK; + + /* To store read register value */ + uint8_t read = 0; + + /* Idle mode */ + SI72XX_INT_CALL(Si72xx_WakeUpAndIdle(addr)); + + log_info("\r(i) Debug SI72xx register :\r\n"); + /* Read every register and deplay their value on uart terminal */ + SI72XX_READ_8B(SI72XX_POWER_CTRL, &read); + log_info("\r\t(i) SI72XX_POWER_CTRL (0x%02x) : %02x\r\n", SI72XX_POWER_CTRL, read); + + SI72XX_READ_8B(SI72XX_CTRL1, &read); + log_info("\t(i) SI72XX_CTRL1 (0x%02x) : %02x\r\n", SI72XX_CTRL1, read); + + SI72XX_READ_8B(SI72XX_CTRL2, &read); + log_info("\t(i) SI72XX_CTRL2 (0x%02x) : %02x\r\n", SI72XX_CTRL2, read); + + RETURN: + return res; +} + + + +#endif + + + + + diff --git a/Src/it_sdk/eeprom/sdk_state.c b/Src/it_sdk/eeprom/sdk_state.c index 3d4545d..024b00c 100644 --- a/Src/it_sdk/eeprom/sdk_state.c +++ b/Src/it_sdk/eeprom/sdk_state.c @@ -32,6 +32,7 @@ #include #endif #include +#include itsdk_state_t itsdk_state;