diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..99ab74d --- /dev/null +++ b/LICENSE @@ -0,0 +1,56 @@ +Copyright (C) Bosch Sensortec GmbH. All Rights Reserved. Confidential. + +Disclaimer + +Common: +Bosch Sensortec products are developed for the consumer goods industry. They may only be used +within the parameters of the respective valid product data sheet. Bosch Sensortec products are +provided with the express understanding that there is no warranty of fitness for a particular purpose. +They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device +that may lead to bodily harm or property damage if the system or device malfunctions. In addition, +Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems. +The resale and/or use of products are at the purchaser's own risk and his own responsibility. The +examination of fitness for the intended use is the sole responsibility of the Purchaser. + +The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for +incidental, or consequential damages, arising from any product use not covered by the parameters of +the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch +Sensortec for all costs in connection with such claims. + +The purchaser must monitor the market for the purchased products, particularly with regard to +product safety and inform Bosch Sensortec without delay of all security relevant incidents. + +Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid +technical specifications of the product series. They are therefore not intended or fit for resale to third +parties or for use in end products. Their sole purpose is internal client testing. The testing of an +engineering sample may in no way replace the testing of a product series. Bosch Sensortec +assumes no liability for the use of engineering samples. By accepting the engineering samples, the +Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering +samples. + +Special: +This software module (hereinafter called "Software") and any information on application-sheets +(hereinafter called "Information") is provided free of charge for the sole purpose to support your +application work. The Software and Information is subject to the following terms and conditions: + +The Software is specifically designed for the exclusive use for Bosch Sensortec products by +personnel who have special experience and training. Do not use this Software if you do not have the +proper experience or training. + +This Software package is provided `` as is `` and without any expressed or implied warranties, +including without limitation, the implied warranties of merchantability and fitness for a particular +purpose. + +Bosch Sensortec and their representatives and agents deny any liability for the functional impairment +of this Software in terms of fitness, performance and safety. Bosch Sensortec and their +representatives and agents shall not be liable for any direct or indirect damages or injury, except as +otherwise stipulated in mandatory applicable law. + +The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no +responsibility for the consequences of use of such Information nor for any infringement of patents or +other rights of third parties which may result from its use. No license is granted by implication or +otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are +subject to change without notice. + +It is not allowed to deliver the source code of the Software to any third party without permission of +Bosch Sensortec. \ No newline at end of file diff --git a/bmm350.c b/bmm350.c new file mode 100644 index 0000000..ea2b9f6 --- /dev/null +++ b/bmm350.c @@ -0,0 +1,1786 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bmm350.c +* @date 2023-05-26 +* @version v1.4.0 +* +*/ + +/*************************** Header files *******************************/ +#include "bmm350.h" + +#ifdef __KERNEL__ +#include +#include +#else +#include +#include +#endif + +/********************** Static function declarations ************************/ + +/*! + * @brief This internal API is used to validate the device pointer for + * null conditions. + * + * @param[in] dev : Structure instance of bmm350_dev. + * + * @return Result of API execution status + * @retval = 0 -> Success + * @retval < 0 -> Error + */ +static int8_t null_ptr_check(const struct bmm350_dev *dev); + +/*! + * @brief This internal API is used to update magnetometer offset and sensitivity data. + * + * @param[in] dev : Structure instance of bmm350_dev. + * + * @return void + */ +static void update_mag_off_sens(struct bmm350_dev *dev); + +/*! + * @brief This internal API converts the raw data from the IC data registers to signed integer + * + * @param[in] inval : Unsigned data from data registers + * @param[in number_of_bits : Width of data register + * + * @return Conversion to signed integer + */ +static int32_t fix_sign(uint32_t inval, int8_t number_of_bits); + +/*! + * @brief This internal API is used to read OTP word + * + * @param[in] addr : Stores OTP address + * @param[in, out] lsb_msb : Pointer to store OTP word + * @param[in, out] dev : Structure instance of bmm350_dev. + * + * @return Result of API execution status + * @retval = 0 -> Success + * @retval < 0 -> Error + */ +static int8_t read_otp_word(uint8_t addr, uint16_t *lsb_msb, struct bmm350_dev *dev); + +/*! + * @brief This internal API is used to read raw magnetic x,y and z axis data along with temperature. + * + * @param[out] out_data : Pointer variable to store mag and temperature data. + * @param[in, out] dev : Structure instance of bmm350_dev. + * + * @return Result of API execution status + * @retval = 0 -> Success + * @retval < 0 -> Error + */ +static int8_t read_out_raw_data(float *out_data, struct bmm350_dev *dev); + +/*! + * @brief This internal API is used to convert raw mag lsb data to uT and raw temperature data to degC. + * + * @param[in,out] lsb_to_ut_degc : Float variable to store converted value of mag lsb in micro tesla(uT) and + * temperature data in degC. + * + * @return void + */ +static void update_default_coefiecents(float *lsb_to_ut_degc); + +/*! + * @brief This internal API is used to read OTP data after boot in user mode. + * + * @param[in, out] dev : Structure instance of bmm350_dev. + * + * @return Result of API execution status + * @retval = 0 -> Success + * @retval < 0 -> Error + */ +static int8_t otp_dump_after_boot(struct bmm350_dev *dev); + +/*! + * @brief This internal API is used for self-test entry configuration + * + * @param[in, out] dev : Structure instance of bmm350_dev. + * + * @return Result of API execution status + * @retval = 0 -> Success + * @retval < 0 -> Error + */ +static int8_t self_test_entry_config(struct bmm350_dev *dev); + +/*! + * @brief This internal API is used to test self-test for X and Y axis + * + * @param[in, out] out_data : Structure instance of bmm350_self_test. + * @param[in, out] dev : Structure instance of bmm350_dev. + * + * @return Result of API execution status + * @retval = 0 -> Success + * @retval < 0 -> Error + */ +static int8_t self_test_xy_axis(struct bmm350_self_test *out_data, struct bmm350_dev *dev); + +/*! + * @brief This internal API is used to set self-test configurations. + * + * @param[in] st_cmd : Variable to store self-test command. + * @param[in] pmu_cmd : Variable to store PMU command. + * @param[in, out] out_data : Structure instance of bmm350_self_test. + * @param[in, out] dev : Structure instance of bmm350_dev. + * + * @return Result of API execution status + * @retval = 0 -> Success + * @retval < 0 -> Error + */ +static int8_t self_test_config(uint8_t st_cmd, + uint8_t pmu_cmd, + struct bmm350_self_test *out_data, + struct bmm350_dev *dev); + +/*! + * @brief This internal API is used to set powermode. + * + * @param[in] powermode : Variable to set new powermode. + * @param[in, out] dev : Structure instance of bmm350_dev. + * + * @return Result of API execution status + * @retval = 0 -> Success + * @retval < 0 -> Error + */ +static int8_t set_powermode(enum bmm350_power_modes powermode, struct bmm350_dev *dev); + +/********************** Global function definitions ************************/ + +/*! + * @brief This API is the entry point. Call this API before using other APIs. + */ +int8_t bmm350_init(struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + /* Variable to get chip id */ + uint8_t chip_id = BMM350_DISABLE; + + /* Variable to store the command to power-off the OTP */ + uint8_t otp_cmd = BMM350_OTP_CMD_PWR_OFF_OTP; + + /* Variable to store soft-reset command */ + uint8_t soft_reset; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if (rslt == BMM350_OK) + { + dev->chip_id = 0; + + /* Assign axis_en with all axis enabled (BMM350_EN_XYZ_MSK) */ + dev->axis_en = BMM350_EN_XYZ_MSK; + + rslt = bmm350_delay_us(BMM350_START_UP_TIME_FROM_POR, dev); + + if (rslt == BMM350_OK) + { + /* Soft-reset */ + soft_reset = BMM350_CMD_SOFTRESET; + + /* Set the command in the command register */ + rslt = bmm350_set_regs(BMM350_REG_CMD, &soft_reset, 1, dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_delay_us(BMM350_SOFT_RESET_DELAY, dev); + } + } + + if (rslt == BMM350_OK) + { + /* Chip ID of the sensor is read */ + rslt = bmm350_get_regs(BMM350_REG_CHIP_ID, &chip_id, 1, dev); + + if (rslt == BMM350_OK) + { + /* Assign chip_id to dev->chip_id */ + dev->chip_id = chip_id; + } + } + + /* Check for chip id validity */ + if ((rslt == BMM350_OK) && (dev->chip_id == BMM350_CHIP_ID)) + { + /* Download OTP memory */ + rslt = otp_dump_after_boot(dev); + + if (rslt == BMM350_OK) + { + /* Power off OTP */ + rslt = bmm350_set_regs(BMM350_REG_OTP_CMD_REG, &otp_cmd, 1, dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_magnetic_reset_and_wait(dev); + } + } + } + else + { + rslt = BMM350_E_DEV_NOT_FOUND; + } + } + + return rslt; +} + +/*! + * @brief This API writes the given data to the register address + * of the sensor. + */ +int8_t bmm350_set_regs(uint8_t reg_addr, const uint8_t *reg_data, uint16_t len, struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if ((rslt == BMM350_OK) && (reg_data != NULL) && (len != 0)) + { + /* Write the data to the reg_addr */ + dev->intf_rslt = dev->write(reg_addr, reg_data, len, dev->intf_ptr); + + if (dev->intf_rslt != BMM350_INTF_RET_SUCCESS) + { + rslt = BMM350_E_COM_FAIL; + } + } + else + { + rslt = BMM350_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API reads the data from the given register address of sensor. + */ +int8_t bmm350_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint16_t len, struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + /* Variable to define temporary length */ + uint16_t temp_len = len + BMM350_DUMMY_BYTES; + + /* Variable to define temporary buffer */ + uint8_t temp_buf[BMM350_READ_BUFFER_LENGTH]; + + /* Variable to define loop */ + uint16_t index = 0; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if ((rslt == BMM350_OK) && (reg_data != NULL)) + { + /* Read the data from the reg_addr */ + dev->intf_rslt = dev->read(reg_addr, temp_buf, temp_len, dev->intf_ptr); + + if (dev->intf_rslt == BMM350_INTF_RET_SUCCESS) + { + /* Copy data after dummy byte indices */ + while (index < len) + { + reg_data[index] = temp_buf[index + BMM350_DUMMY_BYTES]; + index++; + } + } + else + { + rslt = BMM350_E_COM_FAIL; + } + } + else + { + rslt = BMM350_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This function provides the delay for required time (Microsecond) as per the input provided in some of the + * APIs. + */ +int8_t bmm350_delay_us(uint32_t period_us, const struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + if (rslt == BMM350_OK) + { + dev->delay_us(period_us, dev->intf_ptr); + } + + return rslt; +} + +/*! + * @brief This API is used to perform soft-reset of the sensor + * where all the registers are reset to their default values + */ +int8_t bmm350_soft_reset(struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + uint8_t reg_data; + + /* Variable to store the command to power-off the OTP */ + uint8_t otp_cmd = BMM350_OTP_CMD_PWR_OFF_OTP; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + if (rslt == BMM350_OK) + { + reg_data = BMM350_CMD_SOFTRESET; + + /* Set the command in the command register */ + rslt = bmm350_set_regs(BMM350_REG_CMD, ®_data, 1, dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_delay_us(BMM350_SOFT_RESET_DELAY, dev); + + if (rslt == BMM350_OK) + { + /* Power off OTP */ + rslt = bmm350_set_regs(BMM350_REG_OTP_CMD_REG, &otp_cmd, 1, dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_magnetic_reset_and_wait(dev); + } + } + } + } + + return rslt; +} + +/*! + * @brief This API is used to read the sensor time. + * It converts the sensor time register values to the representative time value. + * Returns the sensor time in ticks. + */ +int8_t bmm350_read_sensortime(uint32_t *seconds, uint32_t *nanoseconds, struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + uint64_t time; + + uint8_t reg_data[3]; + + if ((seconds != NULL) && (nanoseconds != NULL)) + { + /* Get sensor time raw data */ + rslt = bmm350_get_regs(BMM350_REG_SENSORTIME_XLSB, reg_data, 3, dev); + + if (rslt == BMM350_OK) + { + time = (uint32_t)(reg_data[0] + ((uint32_t)reg_data[1] << 8) + ((uint32_t)reg_data[2] << 16)); + + /* 1 LSB is 39.0625us. Converting to nanoseconds */ + time *= UINT64_C(390625); + time /= UINT64_C(10); + *seconds = (uint32_t)(time / UINT64_C(1000000000)); + *nanoseconds = (uint32_t)(time - ((*seconds) * UINT64_C(1000000000))); + } + } + else + { + rslt = BMM350_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API is used to get the status flags of all interrupt + * which is used to check for the assertion of interrupts + */ +int8_t bmm350_get_interrupt_status(uint8_t *drdy_status, struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + uint8_t int_status_reg; + + if (drdy_status != NULL) + { + /* Get the status of interrupt */ + rslt = bmm350_get_regs(BMM350_REG_INT_STATUS, &int_status_reg, 1, dev); + + if (rslt == BMM350_OK) + { + /* Read the interrupt status */ + (*drdy_status) = BMM350_GET_BITS(int_status_reg, BMM350_DRDY_DATA_REG); + } + } + else + { + rslt = BMM350_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API is used to set the power mode of the sensor + */ +int8_t bmm350_set_powermode(enum bmm350_power_modes powermode, struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + uint8_t last_pwr_mode; + uint8_t reg_data; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_get_regs(BMM350_REG_PMU_CMD, &last_pwr_mode, 1, dev); + + if (rslt == BMM350_OK) + { + if (last_pwr_mode > BMM350_PMU_CMD_NM_TC) + { + rslt = BMM350_E_INVALID_CONFIG; + } + + if ((rslt == BMM350_OK) && + ((last_pwr_mode == BMM350_PMU_CMD_NM) || (last_pwr_mode == BMM350_PMU_CMD_UPD_OAE))) + { + reg_data = BMM350_PMU_CMD_SUS; + + /* Set PMU command configuration */ + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD, ®_data, 1, dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_delay_us(BMM350_GOTO_SUSPEND_DELAY, dev); + } + } + + if (rslt == BMM350_OK) + { + rslt = set_powermode(powermode, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This API sets the ODR and averaging factor. + */ +int8_t bmm350_set_odr_performance(enum bmm350_data_rates odr, + enum bmm350_performance_parameters performance, + struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + /* Variable to get PMU command */ + uint8_t reg_data = 0; + + enum bmm350_performance_parameters performance_fix = performance; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + if (rslt == BMM350_OK) + { + /* Reduce the performance setting when too high for the chosen ODR */ + if ((odr == BMM350_DATA_RATE_400HZ) && (performance >= BMM350_AVERAGING_2)) + { + performance_fix = BMM350_NO_AVERAGING; + } + else if ((odr == BMM350_DATA_RATE_200HZ) && (performance >= BMM350_AVERAGING_4)) + { + performance_fix = BMM350_AVERAGING_2; + } + else if ((odr == BMM350_DATA_RATE_100HZ) && (performance >= BMM350_AVERAGING_8)) + { + performance_fix = BMM350_AVERAGING_4; + } + + /* ODR is an enum taking the generated constants from the register map */ + reg_data = ((uint8_t)odr & BMM350_ODR_MSK); + + /* AVG / performance is an enum taking the generated constants from the register map */ + reg_data = BMM350_SET_BITS(reg_data, BMM350_AVG, (uint8_t)performance_fix); + + /* Set PMU command configurations for ODR and performance */ + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD_AGGR_SET, ®_data, 1, dev); + + if (rslt == BMM350_OK) + { + /* Set PMU command configurations to update odr and average */ + reg_data = BMM350_PMU_CMD_UPD_OAE; + + /* Set PMU command configuration */ + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD, ®_data, 1, dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_delay_us(BMM350_UPD_OAE_DELAY, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This API is used to enable or disable the magnetic + * measurement of x,y,z axes + */ +int8_t bmm350_enable_axes(enum bmm350_x_axis_en_dis en_x, + enum bmm350_y_axis_en_dis en_y, + enum bmm350_z_axis_en_dis en_z, + struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + /* Variable to store axis data */ + uint8_t data; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + if (rslt == BMM350_OK) + { + if ((en_x == BMM350_X_DIS) && (en_y == BMM350_Y_DIS) && (en_z == BMM350_Z_DIS)) + { + rslt = BMM350_E_ALL_AXIS_DISABLED; + + /* Assign axis_en with all axis disabled status */ + dev->axis_en = BMM350_DISABLE; + } + else + { + data = (en_x & BMM350_EN_X_MSK); + data = BMM350_SET_BITS(data, BMM350_EN_Y, en_y); + data = BMM350_SET_BITS(data, BMM350_EN_Z, en_z); + + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD_AXIS_EN, &data, 1, dev); + + if (rslt == BMM350_OK) + { + /* Assign axis_en with the axis selection done */ + dev->axis_en = data; + } + } + } + + return rslt; +} + +/*! + * @brief This API is used to enable or disable the data ready interrupt + */ +int8_t bmm350_enable_interrupt(enum bmm350_interrupt_enable_disable enable_disable, struct bmm350_dev *dev) +{ + /* Variable to get interrupt control configuration */ + uint8_t reg_data = 0; + + /* Variable to store the function result */ + int8_t rslt; + + /* Get interrupt control configuration */ + rslt = bmm350_get_regs(BMM350_REG_INT_CTRL, ®_data, 1, dev); + + if (rslt == BMM350_OK) + { + reg_data = BMM350_SET_BITS(reg_data, BMM350_DRDY_DATA_REG_EN, (uint8_t)enable_disable); + + /* Finally transfer the interrupt configurations */ + rslt = bmm350_set_regs(BMM350_REG_INT_CTRL, ®_data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API is used to configure the interrupt control settings + */ +int8_t bmm350_configure_interrupt(enum bmm350_intr_latch latching, + enum bmm350_intr_polarity polarity, + enum bmm350_intr_drive drivertype, + enum bmm350_intr_map map_nomap, + struct bmm350_dev *dev) +{ + /* Variable to get interrupt control configuration */ + uint8_t reg_data = 0; + + /* Variable to store the function result */ + int8_t rslt; + + /* Get interrupt control configuration */ + rslt = bmm350_get_regs(BMM350_REG_INT_CTRL, ®_data, 1, dev); + + if (rslt == BMM350_OK) + { + reg_data = BMM350_SET_BITS_POS_0(reg_data, BMM350_INT_MODE, latching); + reg_data = BMM350_SET_BITS(reg_data, BMM350_INT_POL, polarity); + reg_data = BMM350_SET_BITS(reg_data, BMM350_INT_OD, drivertype); + reg_data = BMM350_SET_BITS(reg_data, BMM350_INT_OUTPUT_EN, map_nomap); + + /* Finally transfer the interrupt configurations */ + rslt = bmm350_set_regs(BMM350_REG_INT_CTRL, ®_data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API is used to read uncompensated mag and temperature data. + */ +int8_t bmm350_read_uncomp_mag_temp_data(struct bmm350_raw_mag_data *raw_data, struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + uint8_t mag_data[12] = { 0 }; + + uint32_t raw_mag_x, raw_mag_y, raw_mag_z, raw_temp; + + if (raw_data != NULL) + { + /* Get uncompensated mag data */ + rslt = bmm350_get_regs(BMM350_REG_MAG_X_XLSB, mag_data, BMM350_MAG_TEMP_DATA_LEN, dev); + + if (rslt == BMM350_OK) + { + raw_mag_x = mag_data[0] + ((uint32_t)mag_data[1] << 8) + ((uint32_t)mag_data[2] << 16); + raw_mag_y = mag_data[3] + ((uint32_t)mag_data[4] << 8) + ((uint32_t)mag_data[5] << 16); + raw_mag_z = mag_data[6] + ((uint32_t)mag_data[7] << 8) + ((uint32_t)mag_data[8] << 16); + raw_temp = mag_data[9] + ((uint32_t)mag_data[10] << 8) + ((uint32_t)mag_data[11] << 16); + + if ((dev->axis_en & BMM350_EN_X_MSK) == BMM350_DISABLE) + { + raw_data->raw_xdata = BMM350_DISABLE; + } + else + { + raw_data->raw_xdata = fix_sign(raw_mag_x, BMM350_SIGNED_24_BIT); + } + + if ((dev->axis_en & BMM350_EN_Y_MSK) == BMM350_DISABLE) + { + raw_data->raw_ydata = BMM350_DISABLE; + } + else + { + raw_data->raw_ydata = fix_sign(raw_mag_y, BMM350_SIGNED_24_BIT); + } + + if ((dev->axis_en & BMM350_EN_Z_MSK) == BMM350_DISABLE) + { + raw_data->raw_zdata = BMM350_DISABLE; + } + else + { + raw_data->raw_zdata = fix_sign(raw_mag_z, BMM350_SIGNED_24_BIT); + } + + raw_data->raw_data_t = fix_sign(raw_temp, BMM350_SIGNED_24_BIT); + } + } + else + { + rslt = BMM350_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API sets the interrupt control IBI configurations to the sensor. + */ +int8_t bmm350_set_int_ctrl_ibi(enum bmm350_drdy_int_map_to_ibi en_dis, + enum bmm350_clear_drdy_int_status_upon_ibi clear_on_ibi, + struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + /* Variable to get interrupt control configuration */ + uint8_t reg_data = 0; + + /* Get interrupt control configuration */ + rslt = bmm350_get_regs(BMM350_REG_INT_CTRL_IBI, ®_data, 1, dev); + + if (rslt == BMM350_OK) + { + reg_data = BMM350_SET_BITS_POS_0(reg_data, BMM350_DRDY_INT_MAP_TO_IBI, en_dis); + reg_data = BMM350_SET_BITS(reg_data, BMM350_CLEAR_DRDY_INT_STATUS_UPON_IBI, clear_on_ibi); + + /* Set the IBI control configuration */ + rslt = bmm350_set_regs(BMM350_REG_INT_CTRL_IBI, ®_data, 1, dev); + + if (en_dis == BMM350_IBI_ENABLE) + { + /* Enable data ready interrupt if IBI is enabled */ + rslt = bmm350_enable_interrupt(BMM350_ENABLE_INTERRUPT, dev); + } + } + + return rslt; +} + +/*! + * @brief This API is used to set the pad drive strength + */ +int8_t bmm350_set_pad_drive(uint8_t drive, struct bmm350_dev *dev) +{ + uint8_t reg_data; + + /* Variable to store the function result */ + int8_t rslt = BMM350_E_BAD_PAD_DRIVE; + + if (drive <= BMM350_PAD_DRIVE_STRONGEST) + { + reg_data = drive & BMM350_DRV_MSK; + + /* Set drive */ + rslt = bmm350_set_regs(BMM350_REG_PAD_CTRL, ®_data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API is used to perform the magnetic reset of the sensor + * which is necessary after a field shock (400mT field applied to sensor). + * It sends flux guide or bit reset to the device in suspend mode. + */ +int8_t bmm350_magnetic_reset_and_wait(struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + uint8_t pmu_cmd = 0; + struct bmm350_pmu_cmd_status_0 pmu_cmd_stat_0 = { 0 }; + uint8_t restore_normal = BMM350_DISABLE; + + rslt = null_ptr_check(dev); + + if ((rslt == BMM350_OK) && (dev->mraw_override) && (dev->var_id >= BMM350_MIN_VAR)) + { + rslt = dev->mraw_override(dev); + } + else + { + /* Read PMU CMD status */ + rslt = bmm350_get_pmu_cmd_status_0(&pmu_cmd_stat_0, dev); + + /* Check the powermode is normal before performing magnetic reset */ + if ((rslt == BMM350_OK) && (pmu_cmd_stat_0.pwr_mode_is_normal == BMM350_ENABLE)) + { + restore_normal = BMM350_ENABLE; + + /* Reset can only be triggered in suspend */ + rslt = bmm350_set_powermode(BMM350_SUSPEND_MODE, dev); + } + + if (rslt == BMM350_OK) + { + /* Set BR to PMU_CMD register */ + pmu_cmd = BMM350_PMU_CMD_BR; + + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD, &pmu_cmd, 1, dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_delay_us(BMM350_BR_DELAY, dev); + } + } + + if (rslt == BMM350_OK) + { + /* Verify if PMU_CMD_STATUS_0 register has BR set */ + rslt = bmm350_get_pmu_cmd_status_0(&pmu_cmd_stat_0, dev); + + if ((rslt == BMM350_OK) && (pmu_cmd_stat_0.pmu_cmd_value != BMM350_PMU_CMD_STATUS_0_BR)) + { + rslt = BMM350_E_PMU_CMD_VALUE; + } + } + + if (rslt == BMM350_OK) + { + /* Set FGR to PMU_CMD register */ + pmu_cmd = BMM350_PMU_CMD_FGR; + + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD, &pmu_cmd, 1, dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_delay_us(BMM350_FGR_DELAY, dev); + } + } + + if (rslt == BMM350_OK) + { + /* Verify if PMU_CMD_STATUS_0 register has FGR set */ + rslt = bmm350_get_pmu_cmd_status_0(&pmu_cmd_stat_0, dev); + + if ((rslt == BMM350_OK) && (pmu_cmd_stat_0.pmu_cmd_value != BMM350_PMU_CMD_STATUS_0_FGR)) + { + rslt = BMM350_E_PMU_CMD_VALUE; + } + } + + if ((rslt == BMM350_OK) && (restore_normal == BMM350_ENABLE)) + { + rslt = bmm350_set_powermode(BMM350_NORMAL_MODE, dev); + } + } + + return rslt; +} + +/*! + * @brief This API is used to perform compensation for raw magnetometer and temperature data. + */ +int8_t bmm350_get_compensated_mag_xyz_temp_data(struct bmm350_mag_temp_data *mag_temp_data, struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + uint8_t indx; + float out_data[4] = { 0.0f }; + float dut_offset_coef[3], dut_sensit_coef[3], dut_tco[3], dut_tcs[3]; + float cr_ax_comp_x, cr_ax_comp_y, cr_ax_comp_z; + + if (mag_temp_data != NULL) + { + /* Reads raw magnetic x,y and z axis along with temperature */ + rslt = read_out_raw_data(out_data, dev); + + if (rslt == BMM350_OK) + { + /* Apply compensation to temperature reading */ + out_data[3] = (1 + dev->mag_comp.dut_sensit_coef.t_sens) * out_data[3] + + dev->mag_comp.dut_offset_coef.t_offs; + + /* Store magnetic compensation structure to an array */ + dut_offset_coef[0] = dev->mag_comp.dut_offset_coef.offset_x; + dut_offset_coef[1] = dev->mag_comp.dut_offset_coef.offset_y; + dut_offset_coef[2] = dev->mag_comp.dut_offset_coef.offset_z; + + dut_sensit_coef[0] = dev->mag_comp.dut_sensit_coef.sens_x; + dut_sensit_coef[1] = dev->mag_comp.dut_sensit_coef.sens_y; + dut_sensit_coef[2] = dev->mag_comp.dut_sensit_coef.sens_z; + + dut_tco[0] = dev->mag_comp.dut_tco.tco_x; + dut_tco[1] = dev->mag_comp.dut_tco.tco_y; + dut_tco[2] = dev->mag_comp.dut_tco.tco_z; + + dut_tcs[0] = dev->mag_comp.dut_tcs.tcs_x; + dut_tcs[1] = dev->mag_comp.dut_tcs.tcs_y; + dut_tcs[2] = dev->mag_comp.dut_tcs.tcs_z; + + /* Compensate raw magnetic data */ + for (indx = 0; indx < 3; indx++) + { + out_data[indx] *= 1 + dut_sensit_coef[indx]; + out_data[indx] += dut_offset_coef[indx]; + out_data[indx] += dut_tco[indx] * (out_data[3] - dev->mag_comp.dut_t0); + out_data[indx] /= 1 + dut_tcs[indx] * (out_data[3] - dev->mag_comp.dut_t0); + } + + cr_ax_comp_x = (out_data[0] - dev->mag_comp.cross_axis.cross_x_y * out_data[1]) / + (1 - dev->mag_comp.cross_axis.cross_y_x * dev->mag_comp.cross_axis.cross_x_y); + cr_ax_comp_y = (out_data[1] - dev->mag_comp.cross_axis.cross_y_x * out_data[0]) / + (1 - dev->mag_comp.cross_axis.cross_y_x * dev->mag_comp.cross_axis.cross_x_y); + cr_ax_comp_z = + (out_data[2] + + (out_data[0] * + (dev->mag_comp.cross_axis.cross_y_x * dev->mag_comp.cross_axis.cross_z_y - + dev->mag_comp.cross_axis.cross_z_x) - out_data[1] * + (dev->mag_comp.cross_axis.cross_z_y - dev->mag_comp.cross_axis.cross_x_y * + dev->mag_comp.cross_axis.cross_z_x)) / + (1 - dev->mag_comp.cross_axis.cross_y_x * dev->mag_comp.cross_axis.cross_x_y)); + + out_data[0] = cr_ax_comp_x; + out_data[1] = cr_ax_comp_y; + out_data[2] = cr_ax_comp_z; + } + + if (rslt == BMM350_OK) + { + if ((dev->axis_en & BMM350_EN_X_MSK) == BMM350_DISABLE) + { + mag_temp_data->x = BMM350_DISABLE; + } + else + { + mag_temp_data->x = out_data[0]; + } + + if ((dev->axis_en & BMM350_EN_Y_MSK) == BMM350_DISABLE) + { + mag_temp_data->y = BMM350_DISABLE; + } + else + { + mag_temp_data->y = out_data[1]; + } + + if ((dev->axis_en & BMM350_EN_Z_MSK) == BMM350_DISABLE) + { + mag_temp_data->z = BMM350_DISABLE; + } + else + { + mag_temp_data->z = out_data[2]; + } + + mag_temp_data->temperature = out_data[3]; + } + } + else + { + rslt = BMM350_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This function executes FGR and BR sequences to initialize TMR sensor and performs the user self-test. + */ +int8_t bmm350_perform_self_test(struct bmm350_self_test *out_data, struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + /* Variable to store last powermode */ + uint8_t last_pwr_mode; + + if (out_data != NULL) + { + rslt = bmm350_get_regs(BMM350_REG_PMU_CMD, &last_pwr_mode, 1, dev); + + if (rslt == BMM350_OK) + { + /* Self-test entry configuration */ + rslt = self_test_entry_config(dev); + + if (rslt == BMM350_OK) + { + /* Updates self-test values to structure */ + rslt = self_test_xy_axis(out_data, dev); + } + } + + if (rslt == BMM350_OK) + { + /* Setup DUT: disable user self-test */ + rslt = bmm350_set_tmr_selftest_user(BMM350_ST_IGEN_DIS, + BMM350_ST_N_DIS, + BMM350_ST_P_DIS, + BMM350_IST_X_DIS, + BMM350_IST_Y_DIS, + dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_delay_us(1000, dev); + } + + if (last_pwr_mode == BMM350_PMU_CMD_NM) + { + rslt = bmm350_set_powermode(BMM350_NORMAL_MODE, dev); + } + } + } + else + { + rslt = BMM350_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API sets the I2C watchdog timer configurations to the sensor. + */ +int8_t bmm350_set_i2c_wdt(enum bmm350_i2c_wdt_en i2c_wdt_en_dis, + enum bmm350_i2c_wdt_sel i2c_wdt_sel, + struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + uint8_t reg_data; + + /* Get I2C WDT configuration */ + rslt = bmm350_get_regs(BMM350_REG_I2C_WDT_SET, ®_data, 1, dev); + + if (rslt == BMM350_OK) + { + reg_data = BMM350_SET_BITS_POS_0(reg_data, BMM350_I2C_WDT_EN, i2c_wdt_en_dis); + reg_data = BMM350_SET_BITS(reg_data, BMM350_I2C_WDT_SEL, i2c_wdt_sel); + + /* Set I2C WDT configuration */ + rslt = bmm350_set_regs(BMM350_REG_I2C_WDT_SET, ®_data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API sets the TMR user self-test register + */ +int8_t bmm350_set_tmr_selftest_user(enum bmm350_st_igen_en st_igen_en_dis, + enum bmm350_st_n st_n_en_dis, + enum bmm350_st_p st_p_en_dis, + enum bmm350_ist_en_x ist_x_en_dis, + enum bmm350_ist_en_y ist_y_en_dis, + struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + uint8_t reg_data; + + /* Get TMR self-test user configuration */ + rslt = bmm350_get_regs(BMM350_REG_TMR_SELFTEST_USER, ®_data, 1, dev); + + if (rslt == BMM350_OK) + { + reg_data = BMM350_SET_BITS_POS_0(reg_data, BMM350_ST_IGEN_EN, st_igen_en_dis); + reg_data = BMM350_SET_BITS(reg_data, BMM350_ST_N, st_n_en_dis); + reg_data = BMM350_SET_BITS(reg_data, BMM350_ST_P, st_p_en_dis); + reg_data = BMM350_SET_BITS(reg_data, BMM350_IST_EN_X, ist_x_en_dis); + reg_data = BMM350_SET_BITS(reg_data, BMM350_IST_EN_Y, ist_y_en_dis); + + /* Set TMR self-test user configuration */ + rslt = bmm350_set_regs(BMM350_REG_TMR_SELFTEST_USER, ®_data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API sets the control user configurations to the sensor which forces the sensor timer to be always + * running, even in suspend mode. + */ +int8_t bmm350_set_ctrl_user(enum bmm350_ctrl_user cfg_sens_tim_aon_en_dis, struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + uint8_t reg_data; + + /* Get control user configuration */ + rslt = bmm350_get_regs(BMM350_REG_CTRL_USER, ®_data, 1, dev); + + if (rslt == BMM350_OK) + { + reg_data = BMM350_SET_BITS_POS_0(reg_data, BMM350_CFG_SENS_TIM_AON, cfg_sens_tim_aon_en_dis); + + /* Set control user configuration */ + rslt = bmm350_set_regs(BMM350_REG_CTRL_USER, ®_data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API gets the PMU command status 0 value + */ +int8_t bmm350_get_pmu_cmd_status_0(struct bmm350_pmu_cmd_status_0 *pmu_cmd_stat_0, struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + uint8_t reg_data; + + if (pmu_cmd_stat_0 != NULL) + { + /* Get PMU command status 0 data */ + rslt = bmm350_get_regs(BMM350_REG_PMU_CMD_STATUS_0, ®_data, 1, dev); + + if (rslt == BMM350_OK) + { + pmu_cmd_stat_0->pmu_cmd_busy = BMM350_GET_BITS_POS_0(reg_data, BMM350_PMU_CMD_BUSY); + + pmu_cmd_stat_0->odr_ovwr = BMM350_GET_BITS(reg_data, BMM350_ODR_OVWR); + + pmu_cmd_stat_0->avr_ovwr = BMM350_GET_BITS(reg_data, BMM350_AVG_OVWR); + + pmu_cmd_stat_0->pwr_mode_is_normal = BMM350_GET_BITS(reg_data, BMM350_PWR_MODE_IS_NORMAL); + + pmu_cmd_stat_0->cmd_is_illegal = BMM350_GET_BITS(reg_data, BMM350_CMD_IS_ILLEGAL); + + pmu_cmd_stat_0->pmu_cmd_value = BMM350_GET_BITS(reg_data, BMM350_PMU_CMD_VALUE); + } + } + else + { + rslt = BMM350_E_NULL_PTR; + } + + return rslt; +} + +/****************************************************************************/ +/**\name INTERNAL APIs */ + +/*! + * @brief This internal API is used to validate the device structure pointer for + * null conditions. + */ +static int8_t null_ptr_check(const struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_us == NULL)) + { + /* Device structure pointer is not valid */ + rslt = BMM350_E_NULL_PTR; + } + else + { + /* Device structure is fine */ + rslt = BMM350_OK; + } + + return rslt; +} + +/*! + * @brief This internal API converts the raw data from the IC data registers to signed integer + */ +static int32_t fix_sign(uint32_t inval, int8_t number_of_bits) +{ + int32_t power = 0; + int32_t retval; + + switch (number_of_bits) + { + case BMM350_SIGNED_8_BIT: + power = 128; /* 2^7 */ + break; + + case BMM350_SIGNED_12_BIT: + power = 2048; /* 2^11 */ + break; + + case BMM350_SIGNED_16_BIT: + power = 32768; /* 2^15 */ + break; + + case BMM350_SIGNED_21_BIT: + power = 1048576; /* 2^20 */ + break; + + case BMM350_SIGNED_24_BIT: + power = 8388608; /* 2^23 */ + break; + + default: + power = 0; + break; + } + + retval = (int32_t)inval; + + if (retval >= power) + { + retval = retval - (power * 2); + } + + return retval; +} + +/*! + * @brief This internal API is used to read OTP word + */ +static int8_t read_otp_word(uint8_t addr, uint16_t *lsb_msb, struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + uint8_t otp_cmd, otp_status = 0, otp_err = BMM350_OTP_STATUS_NO_ERROR, lsb = 0, msb = 0; + + if (lsb_msb != NULL) + { + /* Set OTP command at specified address */ + otp_cmd = BMM350_OTP_CMD_DIR_READ | (addr & BMM350_OTP_WORD_ADDR_MSK); + rslt = bmm350_set_regs(BMM350_REG_OTP_CMD_REG, &otp_cmd, 1, dev); + if (rslt == BMM350_OK) + { + do + { + rslt = bmm350_delay_us(300, dev); + + if (rslt == BMM350_OK) + { + /* Get OTP status */ + rslt = bmm350_get_regs(BMM350_REG_OTP_STATUS_REG, &otp_status, 1, dev); + + otp_err = BMM350_OTP_STATUS_ERROR(otp_status); + if (otp_err != BMM350_OTP_STATUS_NO_ERROR) + { + break; + } + } + } while ((!(otp_status & BMM350_OTP_STATUS_CMD_DONE)) && (rslt == BMM350_OK)); + + if (otp_err != BMM350_OTP_STATUS_NO_ERROR) + { + switch (otp_err) + { + case BMM350_OTP_STATUS_BOOT_ERR: + rslt = BMM350_E_OTP_BOOT; + break; + case BMM350_OTP_STATUS_PAGE_RD_ERR: + rslt = BMM350_E_OTP_PAGE_RD; + break; + case BMM350_OTP_STATUS_PAGE_PRG_ERR: + rslt = BMM350_E_OTP_PAGE_PRG; + break; + case BMM350_OTP_STATUS_SIGN_ERR: + rslt = BMM350_E_OTP_SIGN; + break; + case BMM350_OTP_STATUS_INV_CMD_ERR: + rslt = BMM350_E_OTP_INV_CMD; + break; + default: + rslt = BMM350_E_OTP_UNDEFINED; + break; + } + } + } + + if (rslt == BMM350_OK) + { + /* Get OTP MSB data */ + rslt = bmm350_get_regs(BMM350_REG_OTP_DATA_MSB_REG, &msb, 1, dev); + if (rslt == BMM350_OK) + { + /* Get OTP LSB data */ + rslt = bmm350_get_regs(BMM350_REG_OTP_DATA_LSB_REG, &lsb, 1, dev); + *lsb_msb = ((uint16_t)(msb << 8) | lsb) & 0xFFFF; + } + } + } + else + { + rslt = BMM350_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to update magnetometer offset and sensitivity data. + */ +static void update_mag_off_sens(struct bmm350_dev *dev) +{ + uint16_t off_x_lsb_msb, off_y_lsb_msb, off_z_lsb_msb, t_off; + uint8_t sens_x, sens_y, sens_z, t_sens; + uint8_t tco_x, tco_y, tco_z; + uint8_t tcs_x, tcs_y, tcs_z; + uint8_t cross_x_y, cross_y_x, cross_z_x, cross_z_y; + + off_x_lsb_msb = dev->otp_data[BMM350_MAG_OFFSET_X] & 0x0FFF; + off_y_lsb_msb = ((dev->otp_data[BMM350_MAG_OFFSET_X] & 0xF000) >> 4) + + (dev->otp_data[BMM350_MAG_OFFSET_Y] & BMM350_LSB_MASK); + off_z_lsb_msb = (dev->otp_data[BMM350_MAG_OFFSET_Y] & 0x0F00) + + (dev->otp_data[BMM350_MAG_OFFSET_Z] & BMM350_LSB_MASK); + t_off = dev->otp_data[BMM350_TEMP_OFF_SENS] & BMM350_LSB_MASK; + + dev->mag_comp.dut_offset_coef.offset_x = fix_sign(off_x_lsb_msb, BMM350_SIGNED_12_BIT); + dev->mag_comp.dut_offset_coef.offset_y = fix_sign(off_y_lsb_msb, BMM350_SIGNED_12_BIT); + dev->mag_comp.dut_offset_coef.offset_z = fix_sign(off_z_lsb_msb, BMM350_SIGNED_12_BIT); + dev->mag_comp.dut_offset_coef.t_offs = fix_sign(t_off, BMM350_SIGNED_8_BIT) / 5.0f; + + sens_x = (dev->otp_data[BMM350_MAG_SENS_X] & BMM350_MSB_MASK) >> 8; + sens_y = (dev->otp_data[BMM350_MAG_SENS_Y] & BMM350_LSB_MASK); + sens_z = (dev->otp_data[BMM350_MAG_SENS_Z] & BMM350_MSB_MASK) >> 8; + t_sens = (dev->otp_data[BMM350_TEMP_OFF_SENS] & BMM350_MSB_MASK) >> 8; + + dev->mag_comp.dut_sensit_coef.sens_x = fix_sign(sens_x, BMM350_SIGNED_8_BIT) / 256.0f; + dev->mag_comp.dut_sensit_coef.sens_y = (fix_sign(sens_y, BMM350_SIGNED_8_BIT) / 256.0f) + BMM350_SENS_CORR_Y; + dev->mag_comp.dut_sensit_coef.sens_z = fix_sign(sens_z, BMM350_SIGNED_8_BIT) / 256.0f; + dev->mag_comp.dut_sensit_coef.t_sens = fix_sign(t_sens, BMM350_SIGNED_8_BIT) / 512.0f; + + tco_x = (dev->otp_data[BMM350_MAG_TCO_X] & BMM350_LSB_MASK); + tco_y = (dev->otp_data[BMM350_MAG_TCO_Y] & BMM350_LSB_MASK); + tco_z = (dev->otp_data[BMM350_MAG_TCO_Z] & BMM350_LSB_MASK); + + dev->mag_comp.dut_tco.tco_x = fix_sign(tco_x, BMM350_SIGNED_8_BIT) / 32.0f; + dev->mag_comp.dut_tco.tco_y = fix_sign(tco_y, BMM350_SIGNED_8_BIT) / 32.0f; + dev->mag_comp.dut_tco.tco_z = fix_sign(tco_z, BMM350_SIGNED_8_BIT) / 32.0f; + + tcs_x = (dev->otp_data[BMM350_MAG_TCS_X] & BMM350_MSB_MASK) >> 8; + tcs_y = (dev->otp_data[BMM350_MAG_TCS_Y] & BMM350_MSB_MASK) >> 8; + tcs_z = (dev->otp_data[BMM350_MAG_TCS_Z] & BMM350_MSB_MASK) >> 8; + + dev->mag_comp.dut_tcs.tcs_x = fix_sign(tcs_x, BMM350_SIGNED_8_BIT) / 16384.0f; + dev->mag_comp.dut_tcs.tcs_y = fix_sign(tcs_y, BMM350_SIGNED_8_BIT) / 16384.0f; + dev->mag_comp.dut_tcs.tcs_z = (fix_sign(tcs_z, BMM350_SIGNED_8_BIT) / 16384.0f) - BMM350_TCS_CORR_Z; + + dev->mag_comp.dut_t0 = (fix_sign(dev->otp_data[BMM350_MAG_DUT_T_0], BMM350_SIGNED_16_BIT) / 512.0f) + 23.0f; + + cross_x_y = (dev->otp_data[BMM350_CROSS_X_Y] & BMM350_LSB_MASK); + cross_y_x = (dev->otp_data[BMM350_CROSS_Y_X] & BMM350_MSB_MASK) >> 8; + cross_z_x = (dev->otp_data[BMM350_CROSS_Z_X] & BMM350_LSB_MASK); + cross_z_y = (dev->otp_data[BMM350_CROSS_Z_Y] & BMM350_MSB_MASK) >> 8; + + dev->mag_comp.cross_axis.cross_x_y = fix_sign(cross_x_y, BMM350_SIGNED_8_BIT) / 800.0f; + dev->mag_comp.cross_axis.cross_y_x = fix_sign(cross_y_x, BMM350_SIGNED_8_BIT) / 800.0f; + dev->mag_comp.cross_axis.cross_z_x = fix_sign(cross_z_x, BMM350_SIGNED_8_BIT) / 800.0f; + dev->mag_comp.cross_axis.cross_z_y = fix_sign(cross_z_y, BMM350_SIGNED_8_BIT) / 800.0f; +} + +/*! + * @brief This internal API is used to read raw magnetic x,y and z axis along with temperature + */ +static int8_t read_out_raw_data(float *out_data, struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + float temp = 0.0; + struct bmm350_raw_mag_data raw_data = { 0 }; + + /* Float variable to convert mag lsb to uT and temp lsb to degC */ + float lsb_to_ut_degc[4]; + + if (out_data != NULL) + { + rslt = bmm350_read_uncomp_mag_temp_data(&raw_data, dev); + + if (rslt == BMM350_OK) + { + /* Convert mag lsb to uT and temp lsb to degC */ + update_default_coefiecents(lsb_to_ut_degc); + + out_data[0] = (float)raw_data.raw_xdata * lsb_to_ut_degc[0]; + out_data[1] = (float)raw_data.raw_ydata * lsb_to_ut_degc[1]; + out_data[2] = (float)raw_data.raw_zdata * lsb_to_ut_degc[2]; + out_data[3] = (float)raw_data.raw_data_t * lsb_to_ut_degc[3]; + + if (out_data[3] > 0.0) + { + temp = (float)(out_data[3] - (1 * 25.49)); + } + else if (out_data[3] < 0.0) + { + temp = (float)(out_data[3] - (-1 * 25.49)); + } + else + { + temp = (float)(out_data[3]); + } + + out_data[3] = temp; + } + } + else + { + rslt = BMM350_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to convert lsb to uT and degC. + */ +static void update_default_coefiecents(float *lsb_to_ut_degc) +{ + float bxy_sens, bz_sens, temp_sens, ina_xy_gain_trgt, ina_z_gain_trgt, adc_gain, lut_gain; + float power; + + bxy_sens = 14.55f; + bz_sens = 9.0f; + temp_sens = 0.00204f; + + ina_xy_gain_trgt = 19.46f; + + ina_z_gain_trgt = 31.0; + + adc_gain = 1 / 1.5f; + lut_gain = 0.714607238769531f; + + power = (float)(1000000.0 / 1048576.0); + + lsb_to_ut_degc[0] = (power / (bxy_sens * ina_xy_gain_trgt * adc_gain * lut_gain)); + lsb_to_ut_degc[1] = (power / (bxy_sens * ina_xy_gain_trgt * adc_gain * lut_gain)); + lsb_to_ut_degc[2] = (power / (bz_sens * ina_z_gain_trgt * adc_gain * lut_gain)); + lsb_to_ut_degc[3] = 1 / (temp_sens * adc_gain * lut_gain * 1048576); +} + +/*! + * @brief This internal API is used to read OTP data after boot in user mode. + */ +static int8_t otp_dump_after_boot(struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + uint16_t otp_word = 0; + uint8_t indx; + + for (indx = 0; indx < BMM350_OTP_DATA_LENGTH; indx++) + { + rslt = read_otp_word(indx, &otp_word, dev); + dev->otp_data[indx] = otp_word; + } + + dev->var_id = (dev->otp_data[30] & 0x7f00) >> 9; + + /* Update magnetometer offset and sensitivity data. */ + update_mag_off_sens(dev); + + return rslt; +} + +/*! + * @brief This internal API is used for self-test entry configuration + */ +static int8_t self_test_entry_config(struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + /* Variable to store PMU command */ + uint8_t cmd; + + /* Structure instance of PMU command status 0 */ + struct bmm350_pmu_cmd_status_0 pmu_cmd_stat_0 = { 0 }; + + /* Set suspend mode */ + cmd = BMM350_PMU_CMD_SUS; + + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD, &cmd, 1, dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_delay_us(30000, dev); + } + + /* Read DUT outputs in FORCED mode */ + if (rslt == BMM350_OK) + { + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_100HZ, BMM350_AVERAGING_2, dev); + + if (rslt == BMM350_OK) + { + /* Enable all axis */ + rslt = bmm350_enable_axes(BMM350_X_EN, BMM350_Y_EN, BMM350_Z_EN, dev); + } + } + + /* Execute FGR with full CRST recharge */ + cmd = BMM350_PMU_CMD_FGR; + + if (rslt == BMM350_OK) + { + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD, &cmd, 1, dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_delay_us(30000, dev); + } + } + + if (rslt == BMM350_OK) + { + rslt = bmm350_get_pmu_cmd_status_0(&pmu_cmd_stat_0, dev); + + if ((rslt == BMM350_OK) && (pmu_cmd_stat_0.pmu_cmd_value == BMM350_PMU_CMD_STATUS_0_FGR)) + { + /* Execute BR with full CRST recharge */ + cmd = BMM350_PMU_CMD_BR_FAST; + + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD, &cmd, 1, dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_delay_us(4000, dev); + } + } + } + + if (rslt == BMM350_OK) + { + rslt = bmm350_get_pmu_cmd_status_0(&pmu_cmd_stat_0, dev); + } + + if ((rslt == BMM350_OK) && (pmu_cmd_stat_0.pmu_cmd_value == BMM350_PMU_CMD_STATUS_0_BR_FAST)) + { + cmd = BMM350_PMU_CMD_FM_FAST; + + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD, &cmd, 1, dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_delay_us(16000, dev); + } + + if (rslt == BMM350_OK) + { + rslt = bmm350_get_pmu_cmd_status_0(&pmu_cmd_stat_0, dev); + + if ((rslt == BMM350_OK) && (pmu_cmd_stat_0.pmu_cmd_value == BMM350_PMU_CMD_STATUS_0_FM_FAST)) + { + rslt = bmm350_delay_us(10, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This internal API is used to test self-test for X and Y axis + */ +static int8_t self_test_xy_axis(struct bmm350_self_test *out_data, struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + /* Set pmu command */ + uint8_t cmd = BMM350_PMU_CMD_FM_FAST; + + /* Setup DUT: enable positive user self-test on x-axis */ + rslt = self_test_config(BMM350_SELF_TEST_POS_X, cmd, out_data, dev); + + if (rslt == BMM350_OK) + { + /* Setup DUT: enable negative user self-test on x-axis */ + rslt = self_test_config(BMM350_SELF_TEST_NEG_X, cmd, out_data, dev); + + if (rslt == BMM350_OK) + { + /* Setup DUT: enable positive user self-test on y-axis */ + rslt = self_test_config(BMM350_SELF_TEST_POS_Y, cmd, out_data, dev); + + if (rslt == BMM350_OK) + { + /* Setup DUT: enable negative user self-test on y-axis */ + rslt = self_test_config(BMM350_SELF_TEST_NEG_Y, cmd, out_data, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This internal API is used to set self-test configurations. + */ +static int8_t self_test_config(uint8_t st_cmd, + uint8_t pmu_cmd, + struct bmm350_self_test *out_data, + struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + float out_ust[4]; + + struct bmm350_pmu_cmd_status_0 pmu_cmd_stat_0 = { 0 }; + + static float out_ustxh = 0.0, out_ustxl = 0.0, out_ustyh = 0.0, out_ustyl = 0.0; + + rslt = bmm350_set_regs(BMM350_REG_TMR_SELFTEST_USER, &st_cmd, 1, dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_delay_us(1000, dev); + } + + if (rslt == BMM350_OK) + { + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD, &pmu_cmd, 1, dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_delay_us(6000, dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_get_pmu_cmd_status_0(&pmu_cmd_stat_0, dev); + } + } + } + + if ((rslt == BMM350_OK) && (pmu_cmd_stat_0.pmu_cmd_value == BMM350_PMU_CMD_STATUS_0_FM_FAST)) + { + /* Reads raw magnetic x and y axis */ + rslt = read_out_raw_data(out_ust, dev); + + if (rslt == BMM350_OK) + { + /* Read DUT outputs in FORCED mode (XP_UST) */ + if (st_cmd == BMM350_SELF_TEST_POS_X) + { + out_ustxh = out_ust[0]; + } + /* Read DUT outputs in FORCED mode (XN_UST) */ + else if (st_cmd == BMM350_SELF_TEST_NEG_X) + { + out_ustxl = out_ust[0]; + } + /* Read DUT outputs in FORCED mode (YP_UST) */ + else if (st_cmd == BMM350_SELF_TEST_POS_Y) + { + out_ustyh = out_ust[1]; + } + /* Read DUT outputs in FORCED mode (YN_UST) */ + else if (st_cmd == BMM350_SELF_TEST_NEG_Y) + { + out_ustyl = out_ust[1]; + } + else + { + /* Returns error if self-test axis is wrong */ + rslt = BMM350_E_SELF_TEST_INVALID_AXIS; + } + + if (rslt == BMM350_OK) + { + out_data->out_ust_x = out_ustxh - out_ustxl; + out_data->out_ust_y = out_ustyh - out_ustyl; + } + } + } + + return rslt; +} + +/*! + * @brief This internal API is used to switch from suspend mode to normal mode or forced mode. + */ +static int8_t set_powermode(enum bmm350_power_modes powermode, struct bmm350_dev *dev) +{ + /* Variable to store the function result */ + int8_t rslt; + + uint8_t reg_data = powermode; + uint8_t get_avg; + + /* Array to store suspend to forced mode delay */ + uint32_t sus_to_forced_mode[4] = + { BMM350_SUS_TO_FORCEDMODE_NO_AVG_DELAY, BMM350_SUS_TO_FORCEDMODE_AVG_2_DELAY, BMM350_SUS_TO_FORCEDMODE_AVG_4_DELAY, + BMM350_SUS_TO_FORCEDMODE_AVG_8_DELAY }; + + /* Array to store suspend to forced mode fast delay */ + uint32_t sus_to_forced_mode_fast[4] = + { BMM350_SUS_TO_FORCEDMODE_FAST_NO_AVG_DELAY, BMM350_SUS_TO_FORCEDMODE_FAST_AVG_2_DELAY, + BMM350_SUS_TO_FORCEDMODE_FAST_AVG_4_DELAY, BMM350_SUS_TO_FORCEDMODE_FAST_AVG_8_DELAY }; + + uint8_t avg = 0; + uint32_t delay_us = 0; + + rslt = null_ptr_check(dev); + + if (rslt == BMM350_OK) + { + /* Set PMU command configuration to desired power mode */ + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD, ®_data, 1, dev); + + if (rslt == BMM350_OK) + { + /* Get average configuration */ + rslt = bmm350_get_regs(BMM350_REG_PMU_CMD_AGGR_SET, &get_avg, 1, dev); + + if (rslt == BMM350_OK) + { + /* Mask the average value */ + avg = ((get_avg & BMM350_AVG_MSK) >> BMM350_AVG_POS); + } + } + } + + if (rslt == BMM350_OK) + { + /* Check if desired power mode is normal mode */ + if (powermode == BMM350_NORMAL_MODE) + { + delay_us = BMM350_SUSPEND_TO_NORMAL_DELAY; + } + + /* Check if desired power mode is forced mode */ + if (powermode == BMM350_FORCED_MODE) + { + /* Store delay based on averaging mode */ + delay_us = sus_to_forced_mode[avg]; + } + + /* Check if desired power mode is forced mode fast */ + if (powermode == BMM350_FORCED_MODE_FAST) + { + /* Store delay based on averaging mode */ + delay_us = sus_to_forced_mode_fast[avg]; + } + + /* Perform delay based on power mode */ + rslt = bmm350_delay_us(delay_us, dev); + } + + return rslt; +} diff --git a/bmm350.h b/bmm350.h new file mode 100644 index 0000000..463d9a1 --- /dev/null +++ b/bmm350.h @@ -0,0 +1,595 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bmm350.h +* @date 2023-05-26 +* @version v1.4.0 +* +*/ + +/*! + * @defgroup bmm350 BMM350 + * @brief Sensor driver for BMM350 sensor + */ + +#ifndef _BMM350_H +#define _BMM350_H + +/*! CPP guard */ +#ifdef __cplusplus +extern "C" { +#endif + +/*************************** Header files *******************************/ + +#include "bmm350_defs.h" + +/******************* Function prototype declarations ********************/ + +/** + * \ingroup bmm350 + * \defgroup bmm350ApiInit Initialization + * @brief Initialize the sensor and device structure + */ + +/*! +* \ingroup bmm350ApiInit +* \page bmm350_api_bmm350_init bmm350_init +* \code +* int8_t bmm350_init(struct bmm350_dev *dev); +* \endcode +* @details This API is the entry point. Call this API before using other APIs. +* This API reads the chip-id of the sensor which is the first step to +* verify the sensor and also it configures the read mechanism of I2C and +* I3C interface. +* +* @param[in,out] dev : Structure instance of bmm350_dev +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_init(struct bmm350_dev *dev); + +/** + * \ingroup bmm350 + * \defgroup bmm350ApiReset Reset + * @brief Reset APIs + */ + +/*! +* \ingroup bmm350ApiReset +* \page bmm350_api_bmm350_soft_reset bmm350_soft_reset +* \code +* int8_t bmm350_soft_reset(struct bmm350_dev *dev); +* \endcode +* @details This API is used to perform soft-reset of the sensor +* where all the registers are reset to their default values. +* +* @param[in] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ + +int8_t bmm350_soft_reset(struct bmm350_dev *dev); + +/** + * \ingroup bmm350 + * \defgroup bmm350ApiSetGet Set-Get + * @brief Set and Get APIs + */ + +/*! +* \ingroup bmm350ApiSetGet +* \page bmm350_api_bmm350_set_regs bmm350_set_regs +* \code +* int8_t bmm350_set_regs(uint8_t reg_addr, const uint8_t *reg_data, uint16_t len, struct bmm350_dev *dev); +* \endcode +* @details This API writes the given data to the register address +* of the sensor. +* +* @param[in] reg_addr : Register address from where the data to be written. +* @param[in] reg_data : Pointer to data buffer which is to be written +* in the reg_addr of sensor. +* @param[in] len : No of bytes of data to write.. +* @param[in, out] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_set_regs(uint8_t reg_addr, const uint8_t *reg_data, uint16_t len, struct bmm350_dev *dev); + +/*! +* \ingroup bmm350ApiSetGet +* \page bmm350_api_bmm350_get_regs bmm350_get_regs +* \code +* int8_t bmm350_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint16_t len, struct bmm350_dev *dev); +* \endcode +* @details This API reads the data from the given register address of sensor. +* +* @param[in] reg_addr : Register address from where the data to be read +* @param[out] reg_data : Pointer to data buffer to store the read data. +* @param[in] len : No of bytes of data to be read. +* @param[in] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint16_t len, struct bmm350_dev *dev); + +/** + * \ingroup bmm350 + * \defgroup bmm350ApiDelay Delay + * @brief Delay function in microseconds + */ + +/*! +* \ingroup bmm350ApiDelay +* \page bmm350_api_bmm350_delay_us bmm350_delay_us +* \code +* int8_t bmm350_delay_us(uint32_t period_us, const struct bmm350_dev *dev); +* \endcode +* @details This function provides the delay for required time (Microsecond) as per the input provided in some of the +* APIs. +* +* @param[in] period_us : The required wait time in microsecond. +* @param[in] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_delay_us(uint32_t period_us, const struct bmm350_dev *dev); + +/*! +* \ingroup bmm350ApiSetGet +* \page bmm350_api_bmm350_get_interrupt_status bmm350_get_interrupt_status +* \code +* int8_t bmm350_get_interrupt_status(uint8_t *drdy_status, struct bmm350_dev *dev); +* \endcode +* @details This API obtains the status flags of all interrupt +* which is used to check for the assertion of interrupts +* +* @param[in,out] drdy_status : Variable to store data ready interrupt status. +* @param[in,out] dev : Structure instance of bmm350_dev. +* +* +* @return Result of API execution status and self test result. +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_get_interrupt_status(uint8_t *drdy_status, struct bmm350_dev *dev); + +/*! +* \ingroup bmm350ApiSetGet +* \page bmm350_api_bmm350_set_powermode bmm350_set_powermode +* \code +* int8_t bmm350_set_powermode(enum bmm350_power_modes powermode, struct bmm350_dev *dev); +* \endcode +* @details This API is used to set the power mode of the sensor +* +* @param[in] powermode : Set power mode +* @param[in] dev : Structure instance of bmm350_dev. +* +*@verbatim + powermode | Power mode + -------------------------|----------------------- + | BMM350_SUSPEND_MODE + | BMM350_NORMAL_MODE + | BMM350_FORCED_MODE + | BMM350_FORCED_MODE_FAST +*@endverbatim +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_set_powermode(enum bmm350_power_modes powermode, struct bmm350_dev *dev); + +/*! +* \ingroup bmm350ApiSetGet +* \page bmm350_api_bmm350_set_odr_performance bmm350_set_odr_performance +* \code +* int8_t bmm350_set_odr_performance(enum bmm350_data_rates odr, +* enum bmm350_performance_parameters avg, +* struct bmm350_dev *dev); +* +* \endcode +* @details This API sets the ODR and averaging factor. +* If ODR and performance is a combination which is not allowed, then +* the combination setting is corrected to the next lower possible setting +* +* @param[in] odr : enum bmm350_data_rates +* +*@verbatim + Data rate (ODR) | odr + -------------------------|----------------------- + 400Hz | BMM350_DATA_RATE_400HZ + 200Hz | BMM350_DATA_RATE_200HZ + 100Hz | BMM350_DATA_RATE_100HZ + 50Hz | BMM350_DATA_RATE_50HZ + 25Hz | BMM350_DATA_RATE_25HZ + 12.5Hz | BMM350_DATA_RATE_12_5HZ + 6.25Hz | BMM350_DATA_RATE_6_25HZ + 3.125Hz | BMM350_DATA_RATE_3_125HZ + 1.5625Hz | BMM350_DATA_RATE_1_5625HZ +*@endverbatim +* +* @param[in] avg : enum bmm350_performance_parameters +* +*@verbatim + avg | averaging factor alias + ---------------------------|------------------------------------------ + low power/highest noise | BMM350_NO_AVERAGING BMM350_LOWPOWER + lesser noise | BMM350_AVERAGING_2 BMM350_REGULARPOWER + even lesser noise | BMM350_AVERAGING_4 BMM350_LOWNOISE + lowest noise/highest power | BMM350_AVERAGING_8 BMM350_ULTRALOWNOISE +*@endverbatim +* +* @param[in,out] dev : Structure instance of bmm350_dev +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_set_odr_performance(enum bmm350_data_rates odr, + enum bmm350_performance_parameters avg, + struct bmm350_dev *dev); + +/*! +* \ingroup bmm350ApiSetGet +* \page bmm350_api_bmm350_enable_axes bmm350_enable_axes +* \code +* int8_t bmm350_enable_axes(enum bmm350_x_axis_en_dis en_x, enum bmm350_y_axis_en_dis en_y, enum bmm350_z_axis_en_dis en_z, struct bmm350_dev *dev); +* \endcode +* @details This API is used to enable or disable the magnetic +* measurement of x,y,z axes +* +* @param[in] en_x : Enable or disable X axis +* @param[in] en_y : Enable or disable Y axis +* @param[in] en_z : Enable or disable Z axis +* @param[in,out] dev : Structure instance of bmm350_dev. +* +*@verbatim + Value | Axis (en_x, en_y, en_z) + -------------------|----------------------- + BMM350_ENABLE | Enabled + BMM350_DISABLE | Disabled +*@endverbatim +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_enable_axes(enum bmm350_x_axis_en_dis en_x, + enum bmm350_y_axis_en_dis en_y, + enum bmm350_z_axis_en_dis en_z, + struct bmm350_dev *dev); + +/** + * \ingroup bmm350 + * \defgroup bmm350ApiRead Sensortime + * @brief Reads sensortime + */ + +/*! +* \ingroup bmm350ApiRead +* \page bmm350_api_bmm350_read_sensortime bmm350_read_sensortime +* \code +* int8_t bmm350_read_sensortime(uint32_t *seconds, uint32_t *nanoseconds, struct bmm350_dev *dev); +* \endcode +* @details This API is used to read the sensor time. +* It converts the sensor time register values to the representative time value. +* Returns the sensor time in ticks. +* +* @param[out] seconds : Variable to get sensor time in seconds. +* @param[out] nanoseconds : Variable to get sensor time in nanoseconds. +* @param[in] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_read_sensortime(uint32_t *seconds, uint32_t *nanoseconds, struct bmm350_dev *dev); + +/** + * \ingroup bmm350 + * \defgroup bmm350ApiInterrupt Enable Interrupt + * @brief Interrupt enable APIs + */ + +/*! +* \ingroup bmm350ApiInterrupt +* \page bmm350_api_bmm350_enable_interrupt bmm350_enable_interrupt +* \code +* int8_t bmm350_enable_interrupt(enum bmm350_interrupt_enable_disable enable_disable, struct bmm350_dev *dev); +* \endcode +* @details This API is used to enable or disable the data ready interrupt +* +* @param[in] enable_disable : Enable/ Disable data ready interrupt. +* @param[in] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_enable_interrupt(enum bmm350_interrupt_enable_disable enable_disable, struct bmm350_dev *dev); + +/*! +* \ingroup bmm350ApiInterrupt +* \page bmm350_api_bmm350_configure_interrupt bmm350_configure_interrupt +* \code +* int8_t bmm350_configure_interrupt(enum bmm350_intr_latch latching, +* enum bmm350_intr_polarity polarity, +* enum bmm350_intr_drive drivertype, +* enum bmm350_intr_map map_nomap, +* struct bmm350_dev *dev); +* \endcode +* @details This API is used to configure the interrupt control settings. +* +* @param[in] latching : Sets either latched or pulsed. +* @param[in] polarity : Sets either polarity high or low. +* @param[in] drivertype : Sets either open drain or push pull. +* @param[in] map_nomap : Sets either map or unmap the pins. +* @param[in] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_configure_interrupt(enum bmm350_intr_latch latching, + enum bmm350_intr_polarity polarity, + enum bmm350_intr_drive drivertype, + enum bmm350_intr_map map_nomap, + struct bmm350_dev *dev); + +/** + * \ingroup bmm350 + * \defgroup bmm350ApiUncompMag Uncompensated mag + * @brief Reads uncompensated mag and temperature data + */ + +/*! +* \ingroup bmm350ApiUncompMag +* \page bmm350_api_bmm350_read_uncomp_mag_temp_data bmm350_read_uncomp_mag_temp_data +* \code +* int8_t bmm350_read_uncomp_mag_temp_data(struct bmm350_raw_mag_data *raw_data, struct bmm350_dev *dev); +* \endcode +* @details This API is used to read uncompensated mag and temperature data +* +* @param[in, out] raw_data : Structure instance of bmm350_raw_mag_data. +* @param[in, out] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_read_uncomp_mag_temp_data(struct bmm350_raw_mag_data *raw_data, struct bmm350_dev *dev); + +/*! +* \ingroup bmm350ApiSetGet +* \page bmm350_api_bmm350_set_int_ctrl_ibi bmm350_set_int_ctrl_ibi +* \code +* int8_t bmm350_set_int_ctrl_ibi(enum bmm350_drdy_int_map_to_ibi en_dis, +* enum bmm350_clear_drdy_int_status_upon_ibi clear_on_ibi, struct bmm350_dev *dev); +* \endcode +* @details This API sets the interrupt control IBI configurations to the sensor. +* And enables conventional interrupt if IBI is enabled. +* +* @param[in] en_dis : Sets either enable or disable IBI. +* @param[in] clear_on_ibi : sets either clear or no clear on IBI. +* @param[in] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_set_int_ctrl_ibi(enum bmm350_drdy_int_map_to_ibi en_dis, + enum bmm350_clear_drdy_int_status_upon_ibi clear_on_ibi, + struct bmm350_dev *dev); + +/*! +* \ingroup bmm350ApiSetGet +* \page bmm350_api_bmm350_set_pad_drive bmm350_set_pad_drive +* \code +* int8_t bmm350_set_pad_drive(uint8_t drive, struct bmm350_dev *dev); +* \endcode +* @details This API is used to set the pad drive strength +* +* @param[in] drive : Drive settings, range 0 (weak) ..7(strong) +* @param[in] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_set_pad_drive(uint8_t drive, struct bmm350_dev *dev); + +/*! +* \ingroup bmm350ApiReset +* \page bmm350_api_bmm350_magnetic_reset_and_wait bmm350_magnetic_reset_and_wait +* \code +* int8_t bmm350_magnetic_reset_and_wait(struct bmm350_dev *dev) +* \endcode +* @details This API is used to perform the magnetic reset of the sensor +* which is necessary after a field shock (400mT field applied to sensor). +* It sends flux guide or bit reset to the device in suspend mode. +* +* @param[in] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_magnetic_reset_and_wait(struct bmm350_dev *dev); + +/** + * \ingroup bmm350 + * \defgroup bmm350ApiMagComp Compensation + * @brief Compensation for mag x,y,z axis and temperature API + */ + +/*! +* \ingroup bmm350ApiMagComp +* \page bmm350_api_bmm350_get_compensated_mag_xyz_temp_data bmm350_get_compensated_mag_xyz_temp_data +* \code +* int8_t bmm350_get_compensated_mag_xyz_temp_data(struct bmm350_mag_temp_data *mag_temp_data, struct bmm350_dev *dev); +* \endcode +* @details This API is used to perform compensation for raw magnetometer and temperature data. +* +* @param[out] mag_temp_data : Structure instance of bmm350_mag_temp_data. +* @param[in] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_get_compensated_mag_xyz_temp_data(struct bmm350_mag_temp_data *mag_temp_data, struct bmm350_dev *dev); + +/** + * \ingroup bmm350 + * \defgroup bmm350ApiSelftest Self-test + * @brief Perform self-test for x and y axis + */ + +/*! +* \ingroup bmm350ApiSelftest +* \page bmm350_api_bmm350_perform_self_test bmm350_perform_self_test +* \code +* int8_t bmm350_perform_self_test(struct bmm350_self_test *out_data, struct bmm350_dev *dev); +* \endcode +* @details This API executes FGR and BR sequences to initialize TMR sensor and performs self-test for x and y axis. +* +* @param[in, out] out_data : Structure instance of bmm350_self_test. +* @param[in] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_perform_self_test(struct bmm350_self_test *out_data, struct bmm350_dev *dev); + +/*! +* \ingroup bmm350ApiSetGet +* \page bmm350_api_bmm350_set_i2c_wdt bmm350_set_i2c_wdt +* \code +* int8_t bmm350_set_i2c_wdt(enum bmm350_i2c_wdt_en i2c_wdt_en_dis, enum bmm350_i2c_wdt_sel i2c_wdt_sel, +* struct bmm350_dev *dev); +* \endcode +* @details This API sets the I2C watchdog timer configurations to the sensor. +* +* @param[in] i2c_wdt_en_dis : Enable/ Disable I2C watchdog timer. +* @param[in] i2c_wdt_sel : I2C watchdog timer selection period. +* @param[in] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_set_i2c_wdt(enum bmm350_i2c_wdt_en i2c_wdt_en_dis, + enum bmm350_i2c_wdt_sel i2c_wdt_sel, + struct bmm350_dev *dev); + +/*! +* \ingroup bmm350ApiSetGet +* \page bmm350_api_bmm350_set_tmr_selftest_user bmm350_set_tmr_selftest_user +* \code +* int8_t bmm350_set_tmr_selftest_user(enum bmm350_st_igen_en st_igen_en_dis, +* enum bmm350_st_n st_n_en_dis, +* enum bmm350_st_p st_p_en_dis, +* enum bmm350_ist_en_x ist_x_en_dis, +* enum bmm350_ist_en_y ist_y_en_dis, +* struct bmm350_dev *dev); +* \endcode +* @details This API sets the TMR user self-test register +* +* @param[in] st_igen_en_dis : Enable/ Disable self-test internal current gen. +* @param[in] st_n_en_dis : Enable/ Disable dc_st_n signal. +* @param[in] st_p_en_dis : Enable/ Disable dc_st_p signal. +* @param[in] ist_x_en_dis : Enable/ Disable dc_ist_en_x signal. +* @param[in] ist_y_en_dis : Enable/ Disable dc_ist_en_y signal. +* @param[in] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_set_tmr_selftest_user(enum bmm350_st_igen_en st_igen_en_dis, + enum bmm350_st_n st_n_en_dis, + enum bmm350_st_p st_p_en_dis, + enum bmm350_ist_en_x ist_x_en_dis, + enum bmm350_ist_en_y ist_y_en_dis, + struct bmm350_dev *dev); + +/*! +* \ingroup bmm350ApiSetGet +* \page bmm350_api_bmm350_set_ctrl_user bmm350_set_ctrl_user +* \code +* int8_t bmm350_set_ctrl_user(enum bmm350_ctrl_user cfg_sens_tim_aon_en_dis, struct bmm350_dev *dev); +* \endcode +* @details This API sets the control user configurations to the sensor. +* +* @param[in] cfg_sens_tim_aon_en_dis : Enable/ Disable configuration of sensor time to run on suspend mode. +* @param[in] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_set_ctrl_user(enum bmm350_ctrl_user cfg_sens_tim_aon_en_dis, struct bmm350_dev *dev); + +/*! +* \ingroup bmm350ApiSetGet +* \page bmm350_api_bmm350_get_pmu_cmd_status_0 bmm350_get_pmu_cmd_status_0 +* \code +* int8_t bmm350_get_pmu_cmd_status_0(struct bmm350_pmu_cmd_status_0 *pmu_cmd_stat_0, struct bmm350_dev *dev); +* \endcode +* @details This API gets the PMU command status 0 value. +* +* @param[out] pmu_cmd_stat_0 : Structure instance of bmm350_pmu_cmd_status_0. +* @param[in] dev : Structure instance of bmm350_dev. +* +* @return Result of API execution status +* @retval = 0 -> Success +* @retval < 0 -> Error +*/ +int8_t bmm350_get_pmu_cmd_status_0(struct bmm350_pmu_cmd_status_0 *pmu_cmd_stat_0, struct bmm350_dev *dev); + +#ifdef __cplusplus +} +#endif /* End of CPP guard */ + +#endif /* _BMM350_H */ diff --git a/bmm350_defs.h b/bmm350_defs.h new file mode 100644 index 0000000..cb3d2f3 --- /dev/null +++ b/bmm350_defs.h @@ -0,0 +1,1166 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bmm350_defs.h +* @date 2023-05-26 +* @version v1.4.0 +* +*/ + +#ifndef _BMM350_DEFS_H +#define _BMM350_DEFS_H + +/*************************** Header files *******************************/ + +#ifdef __KERNEL__ +#include +#include +#else +#include +#include +#endif + +/***************************** Common Macros *****************************/ + +#ifdef __KERNEL__ +#if !defined(UINT8_C) && !defined(INT8_C) +#define INT8_C(x) S8_C(x) +#define UINT8_C(x) U8_C(x) +#endif + +#if !defined(UINT16_C) && !defined(INT16_C) +#define INT16_C(x) S16_C(x) +#define UINT16_C(x) U16_C(x) +#endif + +#if !defined(INT32_C) && !defined(UINT32_C) +#define INT32_C(x) S32_C(x) +#define UINT32_C(x) U32_C(x) +#endif + +#if !defined(INT64_C) && !defined(UINT64_C) +#define INT64_C(x) S64_C(x) +#define UINT64_C(x) U64_C(x) +#endif +#endif + +/*! C standard macros */ +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *) 0) +#endif +#endif + +/******************************************************************************/ +/*! @name Compiler switch macros Definitions */ +/******************************************************************************/ + +/************************* General Macro definitions ***************************/ + +/* Macro to SET and GET BITS of a register*/ +#define BMM350_SET_BITS(reg_data, bitname, data) \ + ((reg_data & ~(bitname##_MSK)) | \ + ((data << bitname##_POS) & bitname##_MSK)) + +#define BMM350_GET_BITS(reg_data, bitname) ((reg_data & (bitname##_MSK)) >> (bitname##_POS)) + +#define BMM350_GET_BITS_POS_0(reg_data, bitname) (reg_data & (bitname##_MSK)) + +#define BMM350_SET_BITS_POS_0(reg_data, bitname, data) \ + ((reg_data & ~(bitname##_MSK)) | \ + (data & bitname##_MSK)) + +#ifndef BMM350_INTF_RET_TYPE +#define BMM350_INTF_RET_TYPE int8_t +#endif + +/*! Chip id of BMM350 */ +#define BMM350_CHIP_ID UINT8_C(0x33) + +/*! Variant ID of BMM350 */ +#define BMM350_MIN_VAR UINT8_C(0x10) + +/************************* Sensor interface success code **************************/ +#define BMM350_INTF_RET_SUCCESS INT8_C(0) + +/************************* API success code **************************/ +#define BMM350_OK INT8_C(0) + +/* API error codes */ +#define BMM350_E_NULL_PTR INT8_C(-1) +#define BMM350_E_COM_FAIL INT8_C(-2) +#define BMM350_E_DEV_NOT_FOUND INT8_C(-3) +#define BMM350_E_INVALID_CONFIG INT8_C(-4) +#define BMM350_E_BAD_PAD_DRIVE INT8_C(-5) +#define BMM350_E_RESET_UNFINISHED INT8_C(-6) +#define BMM350_E_INVALID_INPUT INT8_C(-7) +#define BMM350_E_SELF_TEST_INVALID_AXIS INT8_C(-8) +#define BMM350_E_OTP_BOOT INT8_C(-9) +#define BMM350_E_OTP_PAGE_RD INT8_C(-10) +#define BMM350_E_OTP_PAGE_PRG INT8_C(-11) +#define BMM350_E_OTP_SIGN INT8_C(-12) +#define BMM350_E_OTP_INV_CMD INT8_C(-13) +#define BMM350_E_OTP_UNDEFINED INT8_C(-14) +#define BMM350_E_ALL_AXIS_DISABLED INT8_C(-15) +#define BMM350_E_PMU_CMD_VALUE INT8_C(-16) + +#define BMM350_NO_ERROR UINT8_C(0) + +/************************* Sensor delay time settings in microseconds **************************/ +#define BMM350_SOFT_RESET_DELAY UINT32_C(24000) +#define BMM350_MAGNETIC_RESET_DELAY UINT32_C(40000) +#define BMM350_START_UP_TIME_FROM_POR UINT32_C(3000) + +#define BMM350_GOTO_SUSPEND_DELAY UINT32_C(6000) +#define BMM350_SUSPEND_TO_NORMAL_DELAY UINT32_C(38000) + +#define BMM350_SUS_TO_FORCEDMODE_NO_AVG_DELAY UINT32_C(15000) +#define BMM350_SUS_TO_FORCEDMODE_AVG_2_DELAY UINT32_C(17000) +#define BMM350_SUS_TO_FORCEDMODE_AVG_4_DELAY UINT32_C(20000) +#define BMM350_SUS_TO_FORCEDMODE_AVG_8_DELAY UINT32_C(28000) + +#define BMM350_SUS_TO_FORCEDMODE_FAST_NO_AVG_DELAY UINT32_C(4000) +#define BMM350_SUS_TO_FORCEDMODE_FAST_AVG_2_DELAY UINT32_C(5000) +#define BMM350_SUS_TO_FORCEDMODE_FAST_AVG_4_DELAY UINT32_C(9000) +#define BMM350_SUS_TO_FORCEDMODE_FAST_AVG_8_DELAY UINT32_C(16000) + +#define BMM350_UPD_OAE_DELAY UINT16_C(1000) + +#define BMM350_BR_DELAY UINT16_C(14000) +#define BMM350_FGR_DELAY UINT16_C(18000) + +/************************ Length macros ************************/ +#define BMM350_OTP_DATA_LENGTH UINT8_C(32) +#define BMM350_READ_BUFFER_LENGTH UINT8_C(127) +#define BMM350_MAG_TEMP_DATA_LEN UINT8_C(12) + +/************************ Averaging macros **********************/ +#define BMM350_AVG_NO_AVG UINT8_C(0x0) +#define BMM350_AVG_2 UINT8_C(0x1) +#define BMM350_AVG_4 UINT8_C(0x2) +#define BMM350_AVG_8 UINT8_C(0x3) + +/******************************* ODR **************************/ +#define BMM350_ODR_400HZ UINT8_C(0x2) +#define BMM350_ODR_200HZ UINT8_C(0x3) +#define BMM350_ODR_100HZ UINT8_C(0x4) +#define BMM350_ODR_50HZ UINT8_C(0x5) +#define BMM350_ODR_25HZ UINT8_C(0x6) +#define BMM350_ODR_12_5HZ UINT8_C(0x7) +#define BMM350_ODR_6_25HZ UINT8_C(0x8) +#define BMM350_ODR_3_125HZ UINT8_C(0x9) +#define BMM350_ODR_1_5625HZ UINT8_C(0xA) + +/********************* Power modes *************************/ +#define BMM350_PMU_CMD_SUS UINT8_C(0x00) +#define BMM350_PMU_CMD_NM UINT8_C(0x01) +#define BMM350_PMU_CMD_UPD_OAE UINT8_C(0x02) +#define BMM350_PMU_CMD_FM UINT8_C(0x03) +#define BMM350_PMU_CMD_FM_FAST UINT8_C(0x04) +#define BMM350_PMU_CMD_FGR UINT8_C(0x05) +#define BMM350_PMU_CMD_FGR_FAST UINT8_C(0x06) +#define BMM350_PMU_CMD_BR UINT8_C(0x07) +#define BMM350_PMU_CMD_BR_FAST UINT8_C(0x08) +#define BMM350_PMU_CMD_NM_TC UINT8_C(0x09) + +#define BMM350_PMU_STATUS_0 UINT8_C(0x0) + +#define BMM350_DISABLE UINT8_C(0x0) +#define BMM350_ENABLE UINT8_C(0x1) + +#define BMM350_CMD_NOP UINT8_C(0x0) +#define BMM350_CMD_SOFTRESET UINT8_C(0xB6) + +#define BMM350_TARGET_PAGE_PAGE0 UINT8_C(0x0) +#define BMM350_TARGET_PAGE_PAGE1 UINT8_C(0x1) + +#define BMM350_INT_MODE_LATCHED UINT8_C(0x1) +#define BMM350_INT_MODE_PULSED UINT8_C(0x0) + +#define BMM350_INT_POL_ACTIVE_HIGH UINT8_C(0x1) +#define BMM350_INT_POL_ACTIVE_LOW UINT8_C(0x0) + +#define BMM350_INT_OD_PUSHPULL UINT8_C(0x1) +#define BMM350_INT_OD_OPENDRAIN UINT8_C(0x0) + +#define BMM350_INT_OUTPUT_EN_OFF UINT8_C(0x0) +#define BMM350_INT_OUTPUT_EN_ON UINT8_C(0x1) + +#define BMM350_INT_DRDY_EN UINT8_C(0x1) +#define BMM350_INT_DRDY_DIS UINT8_C(0x0) + +#define BMM350_MR_MR1K8 UINT8_C(0x0) +#define BMM350_MR_MR2K1 UINT8_C(0x1) +#define BMM350_MR_MR1K5 UINT8_C(0x2) +#define BMM350_MR_MR0K6 UINT8_C(0x3) + +#define BMM350_SEL_DTB1X_PAD_PAD_INT UINT8_C(0x0) +#define BMM350_SEL_DTB1X_PAD_PAD_BYP UINT8_C(0x1) + +#define BMM350_TMR_TST_HIZ_VTMR_VTMR_ON UINT8_C(0x0) +#define BMM350_TMR_TST_HIZ_VTMR_VTMR_HIZ UINT8_C(0x1) + +#define BMM350_LSB_MASK UINT16_C(0x00FF) +#define BMM350_MSB_MASK UINT16_C(0xFF00) + +/********************** Pad drive strength ************************/ +#define BMM350_PAD_DRIVE_WEAKEST UINT8_C(0) +#define BMM350_PAD_DRIVE_STRONGEST UINT8_C(7) + +/********************** I2C Register Addresses ************************/ + +/*! Register to set I2C address to LOW */ +#define BMM350_I2C_ADSEL_SET_LOW UINT8_C(0x14) + +/*! Register to set I2C address to HIGH */ +#define BMM350_I2C_ADSEL_SET_HIGH UINT8_C(0x15) + +#define BMM350_DUMMY_BYTES UINT8_C(2) + +/********************** Register Addresses ************************/ + +#define BMM350_REG_CHIP_ID UINT8_C(0x00) +#define BMM350_REG_REV_ID UINT8_C(0x01) +#define BMM350_REG_ERR_REG UINT8_C(0x02) +#define BMM350_REG_PAD_CTRL UINT8_C(0x03) +#define BMM350_REG_PMU_CMD_AGGR_SET UINT8_C(0x04) +#define BMM350_REG_PMU_CMD_AXIS_EN UINT8_C(0x05) +#define BMM350_REG_PMU_CMD UINT8_C(0x06) +#define BMM350_REG_PMU_CMD_STATUS_0 UINT8_C(0x07) +#define BMM350_REG_PMU_CMD_STATUS_1 UINT8_C(0x08) +#define BMM350_REG_I3C_ERR UINT8_C(0x09) +#define BMM350_REG_I2C_WDT_SET UINT8_C(0x0A) +#define BMM350_REG_TRSDCR_REV_ID UINT8_C(0x0D) +#define BMM350_REG_TC_SYNC_TU UINT8_C(0x21) +#define BMM350_REG_TC_SYNC_ODR UINT8_C(0x22) +#define BMM350_REG_TC_SYNC_TPH_1 UINT8_C(0x23) +#define BMM350_REG_TC_SYNC_TPH_2 UINT8_C(0x24) +#define BMM350_REG_TC_SYNC_DT UINT8_C(0x25) +#define BMM350_REG_TC_SYNC_ST_0 UINT8_C(0x26) +#define BMM350_REG_TC_SYNC_ST_1 UINT8_C(0x27) +#define BMM350_REG_TC_SYNC_ST_2 UINT8_C(0x28) +#define BMM350_REG_TC_SYNC_STATUS UINT8_C(0x29) +#define BMM350_REG_INT_CTRL UINT8_C(0x2E) +#define BMM350_REG_INT_CTRL_IBI UINT8_C(0x2F) +#define BMM350_REG_INT_STATUS UINT8_C(0x30) +#define BMM350_REG_MAG_X_XLSB UINT8_C(0x31) +#define BMM350_REG_MAG_X_LSB UINT8_C(0x32) +#define BMM350_REG_MAG_X_MSB UINT8_C(0x33) +#define BMM350_REG_MAG_Y_XLSB UINT8_C(0x34) +#define BMM350_REG_MAG_Y_LSB UINT8_C(0x35) +#define BMM350_REG_MAG_Y_MSB UINT8_C(0x36) +#define BMM350_REG_MAG_Z_XLSB UINT8_C(0x37) +#define BMM350_REG_MAG_Z_LSB UINT8_C(0x38) +#define BMM350_REG_MAG_Z_MSB UINT8_C(0x39) +#define BMM350_REG_TEMP_XLSB UINT8_C(0x3A) +#define BMM350_REG_TEMP_LSB UINT8_C(0x3B) +#define BMM350_REG_TEMP_MSB UINT8_C(0x3C) +#define BMM350_REG_SENSORTIME_XLSB UINT8_C(0x3D) +#define BMM350_REG_SENSORTIME_LSB UINT8_C(0x3E) +#define BMM350_REG_SENSORTIME_MSB UINT8_C(0x3F) +#define BMM350_REG_OTP_CMD_REG UINT8_C(0x50) +#define BMM350_REG_OTP_DATA_MSB_REG UINT8_C(0x52) +#define BMM350_REG_OTP_DATA_LSB_REG UINT8_C(0x53) +#define BMM350_REG_OTP_STATUS_REG UINT8_C(0x55) +#define BMM350_REG_TMR_SELFTEST_USER UINT8_C(0x60) +#define BMM350_REG_CTRL_USER UINT8_C(0x61) +#define BMM350_REG_CMD UINT8_C(0x7E) + +/*********************** Macros for OVWR ***************************/ +#define BMM350_REG_OVWR_VALUE_ANA_0 UINT8_C(0x3A) +#define BMM350_REG_OVWR_EN_ANA_0 UINT8_C(0x3B) + +/*********************** Macros for bit masking ***************************/ + +#define BMM350_CHIP_ID_OTP_MSK UINT8_C(0xf) +#define BMM350_CHIP_ID_OTP_POS UINT8_C(0x0) +#define BMM350_CHIP_ID_FIXED_MSK UINT8_C(0xf0) +#define BMM350_CHIP_ID_FIXED_POS UINT8_C(0x4) +#define BMM350_REV_ID_MAJOR_MSK UINT8_C(0xf0) +#define BMM350_REV_ID_MAJOR_POS UINT8_C(0x4) +#define BMM350_REV_ID_MINOR_MSK UINT8_C(0xf) +#define BMM350_REV_ID_MINOR_POS UINT8_C(0x0) +#define BMM350_PMU_CMD_ERROR_MSK UINT8_C(0x1) +#define BMM350_PMU_CMD_ERROR_POS UINT8_C(0x0) +#define BMM350_BOOT_UP_ERROR_MSK UINT8_C(0x2) +#define BMM350_BOOT_UP_ERROR_POS UINT8_C(0x1) +#define BMM350_DRV_MSK UINT8_C(0x7) +#define BMM350_DRV_POS UINT8_C(0x0) +#define BMM350_AVG_MSK UINT8_C(0x30) +#define BMM350_AVG_POS UINT8_C(0x4) +#define BMM350_ODR_MSK UINT8_C(0xf) +#define BMM350_ODR_POS UINT8_C(0x0) +#define BMM350_PMU_CMD_MSK UINT8_C(0xf) +#define BMM350_PMU_CMD_POS UINT8_C(0x0) +#define BMM350_EN_X_MSK UINT8_C(0x01) +#define BMM350_EN_X_POS UINT8_C(0x0) +#define BMM350_EN_Y_MSK UINT8_C(0x02) +#define BMM350_EN_Y_POS UINT8_C(0x1) +#define BMM350_EN_Z_MSK UINT8_C(0x04) +#define BMM350_EN_Z_POS UINT8_C(0x2) +#define BMM350_EN_XYZ_MSK UINT8_C(0x7) +#define BMM350_EN_XYZ_POS UINT8_C(0x0) +#define BMM350_PMU_CMD_BUSY_MSK UINT8_C(0x1) +#define BMM350_PMU_CMD_BUSY_POS UINT8_C(0x0) +#define BMM350_ODR_OVWR_MSK UINT8_C(0x2) +#define BMM350_ODR_OVWR_POS UINT8_C(0x1) +#define BMM350_AVG_OVWR_MSK UINT8_C(0x4) +#define BMM350_AVG_OVWR_POS UINT8_C(0x2) +#define BMM350_PWR_MODE_IS_NORMAL_MSK UINT8_C(0x8) +#define BMM350_PWR_MODE_IS_NORMAL_POS UINT8_C(0x3) +#define BMM350_CMD_IS_ILLEGAL_MSK UINT8_C(0x10) +#define BMM350_CMD_IS_ILLEGAL_POS UINT8_C(0x4) +#define BMM350_PMU_CMD_VALUE_MSK UINT8_C(0xE0) +#define BMM350_PMU_CMD_VALUE_POS UINT8_C(0x5) +#define BMM350_PMU_ODR_S_MSK UINT8_C(0xf) +#define BMM350_PMU_ODR_S_POS UINT8_C(0x0) +#define BMM350_PMU_AVG_S_MSK UINT8_C(0x30) +#define BMM350_PMU_AVG_S_POS UINT8_C(0x4) +#define BMM350_I3C_ERROR_0_MSK UINT8_C(0x1) +#define BMM350_I3C_ERROR_0_POS UINT8_C(0x0) +#define BMM350_I3C_ERROR_3_MSK UINT8_C(0x8) +#define BMM350_I3C_ERROR_3_POS UINT8_C(0x3) +#define BMM350_I2C_WDT_EN_MSK UINT8_C(0x1) +#define BMM350_I2C_WDT_EN_POS UINT8_C(0x0) +#define BMM350_I2C_WDT_SEL_MSK UINT8_C(0x2) +#define BMM350_I2C_WDT_SEL_POS UINT8_C(0x1) +#define BMM350_TRSDCR_REV_ID_OTP_MSK UINT8_C(0x3) +#define BMM350_TRSDCR_REV_ID_OTP_POS UINT8_C(0x0) +#define BMM350_TRSDCR_REV_ID_FIXED_MSK UINT8_C(0xfc) +#define BMM350_TRSDCR_REV_ID_FIXED_POS UINT8_C(0x2) +#define BMM350_PAGING_EN_MSK UINT8_C(0x80) +#define BMM350_PAGING_EN_POS UINT8_C(0x7) +#define BMM350_DRDY_DATA_REG_MSK UINT8_C(0x4) +#define BMM350_DRDY_DATA_REG_POS UINT8_C(0x2) +#define BMM350_INT_MODE_MSK UINT8_C(0x1) +#define BMM350_INT_MODE_POS UINT8_C(0x0) +#define BMM350_INT_POL_MSK UINT8_C(0x2) +#define BMM350_INT_POL_POS UINT8_C(0x1) +#define BMM350_INT_OD_MSK UINT8_C(0x4) +#define BMM350_INT_OD_POS UINT8_C(0x2) +#define BMM350_INT_OUTPUT_EN_MSK UINT8_C(0x8) +#define BMM350_INT_OUTPUT_EN_POS UINT8_C(0x3) +#define BMM350_DRDY_DATA_REG_EN_MSK UINT8_C(0x80) +#define BMM350_DRDY_DATA_REG_EN_POS UINT8_C(0x7) +#define BMM350_DRDY_INT_MAP_TO_IBI_MSK UINT8_C(0x1) +#define BMM350_DRDY_INT_MAP_TO_IBI_POS UINT8_C(0x0) +#define BMM350_CLEAR_DRDY_INT_STATUS_UPON_IBI_MSK UINT8_C(0x10) +#define BMM350_CLEAR_DRDY_INT_STATUS_UPON_IBI_POS UINT8_C(0x4) +#define BMM350_TC_SYNC_TU_MSK UINT8_C(0xff) +#define BMM350_TC_SYNC_ODR_MSK UINT8_C(0xff) +#define BMM350_TC_SYNC_TPH_1_MSK UINT8_C(0xff) +#define BMM350_TC_SYNC_TPH_2_MSK UINT8_C(0xff) +#define BMM350_TC_SYNC_DT_MSK UINT8_C(0xff) +#define BMM350_TC_SYNC_ST_0_MSK UINT8_C(0xff) +#define BMM350_TC_SYNC_ST_1_MSK UINT8_C(0xff) +#define BMM350_TC_SYNC_ST_2_MSK UINT8_C(0xff) +#define BMM350_CFG_FORCE_SOSC_EN_MSK UINT8_C(0x4) +#define BMM350_CFG_FORCE_SOSC_EN_POS UINT8_C(0x2) +#define BMM350_ST_IGEN_EN_MSK UINT8_C(0x1) +#define BMM350_ST_IGEN_EN_POS UINT8_C(0x0) +#define BMM350_ST_N_MSK UINT8_C(0x2) +#define BMM350_ST_N_POS UINT8_C(0x1) +#define BMM350_ST_P_MSK UINT8_C(0x4) +#define BMM350_ST_P_POS UINT8_C(0x2) +#define BMM350_IST_EN_X_MSK UINT8_C(0x8) +#define BMM350_IST_EN_X_POS UINT8_C(0x3) +#define BMM350_IST_EN_Y_MSK UINT8_C(0x10) +#define BMM350_IST_EN_Y_POS UINT8_C(0x4) +#define BMM350_CFG_SENS_TIM_AON_MSK UINT8_C(0x1) +#define BMM350_CFG_SENS_TIM_AON_POS UINT8_C(0x0) +#define BMM350_DATA_X_7_0_MSK UINT8_C(0xff) +#define BMM350_DATA_X_7_0_POS UINT8_C(0x0) +#define BMM350_DATA_X_15_8_MSK UINT8_C(0xff) +#define BMM350_DATA_X_15_8_POS UINT8_C(0x0) +#define BMM350_DATA_X_23_16_MSK UINT8_C(0xff) +#define BMM350_DATA_X_23_16_POS UINT8_C(0x0) +#define BMM350_DATA_Y_7_0_MSK UINT8_C(0xff) +#define BMM350_DATA_Y_7_0_POS UINT8_C(0x0) +#define BMM350_DATA_Y_15_8_MSK UINT8_C(0xff) +#define BMM350_DATA_Y_15_8_POS UINT8_C(0x0) +#define BMM350_DATA_Y_23_16_MSK UINT8_C(0xff) +#define BMM350_DATA_Y_23_16_POS UINT8_C(0x0) +#define BMM350_DATA_Z_7_0_MSK UINT8_C(0xff) +#define BMM350_DATA_Z_7_0_POS UINT8_C(0x0) +#define BMM350_DATA_Z_15_8_MSK UINT8_C(0xff) +#define BMM350_DATA_Z_15_8_POS UINT8_C(0x0) +#define BMM350_DATA_Z_23_16_MSK UINT8_C(0xff) +#define BMM350_DATA_Z_23_16_POS UINT8_C(0x0) +#define BMM350_DATA_T_7_0_MSK UINT8_C(0xff) +#define BMM350_DATA_T_7_0_POS UINT8_C(0x0) +#define BMM350_DATA_T_15_8_MSK UINT8_C(0xff) +#define BMM350_DATA_T_15_8_POS UINT8_C(0x0) +#define BMM350_DATA_T_23_16_MSK UINT8_C(0xff) +#define BMM350_DATA_T_23_16_POS UINT8_C(0x0) +#define BMM350_DATA_ST_7_0_MSK UINT8_C(0xff) +#define BMM350_DATA_ST_7_0_POS UINT8_C(0x0) +#define BMM350_DATA_ST_15_8_MSK UINT8_C(0xff) +#define BMM350_DATA_ST_15_8_POS UINT8_C(0x0) +#define BMM350_DATA_ST_23_16_MSK UINT8_C(0xff) +#define BMM350_DATA_ST_23_16_POS UINT8_C(0x0) +#define BMM350_SIGN_INVERT_T_MSK UINT8_C(0x10) +#define BMM350_SIGN_INVERT_T_POS UINT8_C(0x4) +#define BMM350_SIGN_INVERT_X_MSK UINT8_C(0x20) +#define BMM350_SIGN_INVERT_X_POS UINT8_C(0x5) +#define BMM350_SIGN_INVERT_Y_MSK UINT8_C(0x40) +#define BMM350_SIGN_INVERT_Y_POS UINT8_C(0x6) +#define BMM350_SIGN_INVERT_Z_MSK UINT8_C(0x80) +#define BMM350_SIGN_INVERT_Z_POS UINT8_C(0x7) +#define BMM350_DIS_BR_NM_MSK UINT8_C(0x1) +#define BMM350_DIS_BR_NM_POS UINT8_C(0x0) +#define BMM350_DIS_FGR_NM_MSK UINT8_C(0x2) +#define BMM350_DIS_FGR_NM_POS UINT8_C(0x1) +#define BMM350_DIS_CRST_AT_ALL_MSK UINT8_C(0x4) +#define BMM350_DIS_CRST_AT_ALL_POS UINT8_C(0x2) +#define BMM350_DIS_BR_FM_MSK UINT8_C(0x8) +#define BMM350_DIS_BR_FM_POS UINT8_C(0x3) +#define BMM350_FRC_EN_BUFF_MSK UINT8_C(0x1) +#define BMM350_FRC_EN_BUFF_POS UINT8_C(0x0) +#define BMM350_FRC_INA_EN1_MSK UINT8_C(0x2) +#define BMM350_FRC_INA_EN1_POS UINT8_C(0x1) +#define BMM350_FRC_INA_EN2_MSK UINT8_C(0x4) +#define BMM350_FRC_INA_EN2_POS UINT8_C(0x2) +#define BMM350_FRC_ADC_EN_MSK UINT8_C(0x8) +#define BMM350_FRC_ADC_EN_POS UINT8_C(0x3) +#define BMM350_FRC_INA_RST_MSK UINT8_C(0x10) +#define BMM350_FRC_INA_RST_POS UINT8_C(0x4) +#define BMM350_FRC_ADC_RST_MSK UINT8_C(0x20) +#define BMM350_FRC_ADC_RST_POS UINT8_C(0x5) +#define BMM350_FRC_INA_XSEL_MSK UINT8_C(0x1) +#define BMM350_FRC_INA_XSEL_POS UINT8_C(0x0) +#define BMM350_FRC_INA_YSEL_MSK UINT8_C(0x2) +#define BMM350_FRC_INA_YSEL_POS UINT8_C(0x1) +#define BMM350_FRC_INA_ZSEL_MSK UINT8_C(0x4) +#define BMM350_FRC_INA_ZSEL_POS UINT8_C(0x2) +#define BMM350_FRC_ADC_TEMP_EN_MSK UINT8_C(0x8) +#define BMM350_FRC_ADC_TEMP_EN_POS UINT8_C(0x3) +#define BMM350_FRC_TSENS_EN_MSK UINT8_C(0x10) +#define BMM350_FRC_TSENS_EN_POS UINT8_C(0x4) +#define BMM350_DSENS_FM_MSK UINT8_C(0x20) +#define BMM350_DSENS_FM_POS UINT8_C(0x5) +#define BMM350_DSENS_SEL_MSK UINT8_C(0x40) +#define BMM350_DSENS_SEL_POS UINT8_C(0x6) +#define BMM350_DSENS_SHORT_MSK UINT8_C(0x80) +#define BMM350_DSENS_SHORT_POS UINT8_C(0x7) +#define BMM350_ERR_MISS_BR_DONE_MSK UINT8_C(0x1) +#define BMM350_ERR_MISS_BR_DONE_POS UINT8_C(0x0) +#define BMM350_ERR_MISS_FGR_DONE_MSK UINT8_C(0x2) +#define BMM350_ERR_MISS_FGR_DONE_POS UINT8_C(0x1) +#define BMM350_TST_CHAIN_LN_MODE_MSK UINT8_C(0x1) +#define BMM350_TST_CHAIN_LN_MODE_POS UINT8_C(0x0) +#define BMM350_TST_CHAIN_LP_MODE_MSK UINT8_C(0x2) +#define BMM350_TST_CHAIN_LP_MODE_POS UINT8_C(0x1) +#define BMM350_EN_OVWR_TMR_IF_MSK UINT8_C(0x1) +#define BMM350_EN_OVWR_TMR_IF_POS UINT8_C(0x0) +#define BMM350_TMR_CKTRIGB_MSK UINT8_C(0x2) +#define BMM350_TMR_CKTRIGB_POS UINT8_C(0x1) +#define BMM350_TMR_DO_BR_MSK UINT8_C(0x4) +#define BMM350_TMR_DO_BR_POS UINT8_C(0x2) +#define BMM350_TMR_DO_FGR_MSK UINT8_C(0x18) +#define BMM350_TMR_DO_FGR_POS UINT8_C(0x3) +#define BMM350_TMR_EN_OSC_MSK UINT8_C(0x80) +#define BMM350_TMR_EN_OSC_POS UINT8_C(0x7) +#define BMM350_VCM_TRIM_X_MSK UINT8_C(0x1f) +#define BMM350_VCM_TRIM_X_POS UINT8_C(0x0) +#define BMM350_VCM_TRIM_Y_MSK UINT8_C(0x1f) +#define BMM350_VCM_TRIM_Y_POS UINT8_C(0x0) +#define BMM350_VCM_TRIM_Z_MSK UINT8_C(0x1f) +#define BMM350_VCM_TRIM_Z_POS UINT8_C(0x0) +#define BMM350_VCM_TRIM_DSENS_MSK UINT8_C(0x1f) +#define BMM350_VCM_TRIM_DSENS_POS UINT8_C(0x0) +#define BMM350_TWLB_MSK UINT8_C(0x30) +#define BMM350_TWLB_POS UINT8_C(0x4) +#define BMM350_PRG_PLS_TIM_MSK UINT8_C(0x30) +#define BMM350_PRG_PLS_TIM_POS UINT8_C(0x4) +#define BMM350_OTP_OVWR_EN_MSK UINT8_C(0x1) +#define BMM350_OTP_OVWR_EN_POS UINT8_C(0x0) +#define BMM350_OTP_MEM_CLK_MSK UINT8_C(0x2) +#define BMM350_OTP_MEM_CLK_POS UINT8_C(0x1) +#define BMM350_OTP_MEM_CS_MSK UINT8_C(0x4) +#define BMM350_OTP_MEM_CS_POS UINT8_C(0x2) +#define BMM350_OTP_MEM_PGM_MSK UINT8_C(0x8) +#define BMM350_OTP_MEM_PGM_POS UINT8_C(0x3) +#define BMM350_OTP_MEM_RE_MSK UINT8_C(0x10) +#define BMM350_OTP_MEM_RE_POS UINT8_C(0x4) +#define BMM350_SAMPLE_RDATA_PLS_MSK UINT8_C(0x80) +#define BMM350_SAMPLE_RDATA_PLS_POS UINT8_C(0x7) +#define BMM350_CFG_FW_MSK UINT8_C(0x1) +#define BMM350_CFG_FW_POS UINT8_C(0x0) +#define BMM350_EN_BR_X_MSK UINT8_C(0x2) +#define BMM350_EN_BR_X_POS UINT8_C(0x1) +#define BMM350_EN_BR_Y_MSK UINT8_C(0x4) +#define BMM350_EN_BR_Y_POS UINT8_C(0x2) +#define BMM350_EN_BR_Z_MSK UINT8_C(0x8) +#define BMM350_EN_BR_Z_POS UINT8_C(0x3) +#define BMM350_CFG_PAUSE_TIME_MSK UINT8_C(0x30) +#define BMM350_CFG_PAUSE_TIME_POS UINT8_C(0x4) +#define BMM350_CFG_FGR_PLS_DUR_MSK UINT8_C(0xf) +#define BMM350_CFG_FGR_PLS_DUR_POS UINT8_C(0x0) +#define BMM350_CFG_BR_Z_ORDER_MSK UINT8_C(0x10) +#define BMM350_CFG_BR_Z_ORDER_POS UINT8_C(0x4) +#define BMM350_CFG_BR_XY_CHOP_MSK UINT8_C(0x20) +#define BMM350_CFG_BR_XY_CHOP_POS UINT8_C(0x5) +#define BMM350_CFG_BR_PLS_DUR_MSK UINT8_C(0xc0) +#define BMM350_CFG_BR_PLS_DUR_POS UINT8_C(0x6) +#define BMM350_ENABLE_BR_FGR_TEST_MSK UINT8_C(0x1) +#define BMM350_ENABLE_BR_FGR_TEST_POS UINT8_C(0x0) +#define BMM350_SEL_AXIS_MSK UINT8_C(0xe) +#define BMM350_SEL_AXIS_POS UINT8_C(0x1) +#define BMM350_TMR_CFG_TEST_CLK_EN_MSK UINT8_C(0x10) +#define BMM350_TMR_CFG_TEST_CLK_EN_POS UINT8_C(0x4) +#define BMM350_TEST_VAL_BITS_7DOWNTO0_MSK UINT8_C(0xff) +#define BMM350_TEST_VAL_BITS_7DOWNTO0_POS UINT8_C(0x0) +#define BMM350_TEST_VAL_BITS_8_MSK UINT8_C(0x1) +#define BMM350_TEST_VAL_BITS_8_POS UINT8_C(0x0) +#define BMM350_TEST_P_SAMPLE_MSK UINT8_C(0x2) +#define BMM350_TEST_P_SAMPLE_POS UINT8_C(0x1) +#define BMM350_TEST_N_SAMPLE_MSK UINT8_C(0x4) +#define BMM350_TEST_N_SAMPLE_POS UINT8_C(0x2) +#define BMM350_TEST_APPLY_TO_REM_MSK UINT8_C(0x10) +#define BMM350_TEST_APPLY_TO_REM_POS UINT8_C(0x4) +#define BMM350_UFO_TRM_OSC_RANGE_MSK UINT8_C(0xf) +#define BMM350_UFO_TRM_OSC_RANGE_POS UINT8_C(0x0) +#define BMM350_ISO_CHIP_ID_MSK UINT8_C(0x78) +#define BMM350_ISO_CHIP_ID_POS UINT8_C(0x3) +#define BMM350_ISO_I2C_DEV_ID_MSK UINT8_C(0x80) +#define BMM350_ISO_I2C_DEV_ID_POS UINT8_C(0x7) +#define BMM350_I3C_FREQ_BITS_1DOWNTO0_MSK UINT8_C(0xc) +#define BMM350_I3C_FREQ_BITS_1DOWNTO0_POS UINT8_C(0x2) +#define BMM350_I3C_IBI_MDB_SEL_MSK UINT8_C(0x10) +#define BMM350_I3C_IBI_MDB_SEL_POS UINT8_C(0x4) +#define BMM350_TC_ASYNC_EN_MSK UINT8_C(0x20) +#define BMM350_TC_ASYNC_EN_POS UINT8_C(0x5) +#define BMM350_TC_SYNC_EN_MSK UINT8_C(0x40) +#define BMM350_TC_SYNC_EN_POS UINT8_C(0x6) +#define BMM350_I3C_SCL_GATING_EN_MSK UINT8_C(0x80) +#define BMM350_I3C_SCL_GATING_EN_POS UINT8_C(0x7) +#define BMM350_I3C_INACCURACY_BITS_6DOWNTO0_MSK UINT8_C(0x7f) +#define BMM350_I3C_INACCURACY_BITS_6DOWNTO0_POS UINT8_C(0x0) +#define BMM350_EST_EN_X_MSK UINT8_C(0x1) +#define BMM350_EST_EN_X_POS UINT8_C(0x0) +#define BMM350_EST_EN_Y_MSK UINT8_C(0x2) +#define BMM350_EST_EN_Y_POS UINT8_C(0x1) +#define BMM350_CRST_DIS_MSK UINT8_C(0x4) +#define BMM350_CRST_DIS_POS UINT8_C(0x2) +#define BMM350_BR_TFALL_MSK UINT8_C(0x7) +#define BMM350_BR_TFALL_POS UINT8_C(0x0) +#define BMM350_BR_TRISE_MSK UINT8_C(0x70) +#define BMM350_BR_TRISE_POS UINT8_C(0x4) +#define BMM350_TMR_SOFT_START_DIS_MSK UINT8_C(0x80) +#define BMM350_TMR_SOFT_START_DIS_POS UINT8_C(0x7) +#define BMM350_FOSC_LOW_RANGE_MSK UINT8_C(0x80) +#define BMM350_FOSC_LOW_RANGE_POS UINT8_C(0x7) +#define BMM350_VCRST_TRIM_FG_MSK UINT8_C(0x3f) +#define BMM350_VCRST_TRIM_FG_POS UINT8_C(0x0) +#define BMM350_VCRST_TRIM_BR_MSK UINT8_C(0x3f) +#define BMM350_VCRST_TRIM_BR_POS UINT8_C(0x0) +#define BMM350_BG_TRIM_VRP_MSK UINT8_C(0xc0) +#define BMM350_BG_TRIM_VRP_POS UINT8_C(0x6) +#define BMM350_BG_TRIM_TC_MSK UINT8_C(0xf) +#define BMM350_BG_TRIM_TC_POS UINT8_C(0x0) +#define BMM350_BG_TRIM_VRA_MSK UINT8_C(0xf0) +#define BMM350_BG_TRIM_VRA_POS UINT8_C(0x4) +#define BMM350_BG_TRIM_VRD_MSK UINT8_C(0xf) +#define BMM350_BG_TRIM_VRD_POS UINT8_C(0x0) +#define BMM350_OVWR_REF_IB_EN_MSK UINT8_C(0x10) +#define BMM350_OVWR_REF_IB_EN_POS UINT8_C(0x4) +#define BMM350_OVWR_VDDA_EN_MSK UINT8_C(0x20) +#define BMM350_OVWR_VDDA_EN_POS UINT8_C(0x5) +#define BMM350_OVWR_VDDP_EN_MSK UINT8_C(0x40) +#define BMM350_OVWR_VDDP_EN_POS UINT8_C(0x6) +#define BMM350_OVWR_VDDS_EN_MSK UINT8_C(0x80) +#define BMM350_OVWR_VDDS_EN_POS UINT8_C(0x7) +#define BMM350_REF_IB_EN_MSK UINT8_C(0x10) +#define BMM350_REF_IB_EN_POS UINT8_C(0x4) +#define BMM350_VDDA_EN_MSK UINT8_C(0x20) +#define BMM350_VDDA_EN_POS UINT8_C(0x5) +#define BMM350_VDDP_EN_MSK UINT8_C(0x40) +#define BMM350_VDDP_EN_POS UINT8_C(0x6) +#define BMM350_VDDS_EN_MSK UINT8_C(0x80) +#define BMM350_VDDS_EN_POS UINT8_C(0x7) +#define BMM350_OVWR_OTP_PROG_VDD_SW_EN_MSK UINT8_C(0x8) +#define BMM350_OVWR_OTP_PROG_VDD_SW_EN_POS UINT8_C(0x3) +#define BMM350_OVWR_EN_MFE_BG_FILT_BYPASS_MSK UINT8_C(0x10) +#define BMM350_OVWR_EN_MFE_BG_FILT_BYPASS_POS UINT8_C(0x4) +#define BMM350_OTP_PROG_VDD_SW_EN_MSK UINT8_C(0x8) +#define BMM350_OTP_PROG_VDD_SW_EN_POS UINT8_C(0x3) +#define BMM350_CP_COMP_CRST_EN_TM_MSK UINT8_C(0x10) +#define BMM350_CP_COMP_CRST_EN_TM_POS UINT8_C(0x4) +#define BMM350_CP_COMP_VDD_EN_TM_MSK UINT8_C(0x20) +#define BMM350_CP_COMP_VDD_EN_TM_POS UINT8_C(0x5) +#define BMM350_CP_INTREFS_EN_TM_MSK UINT8_C(0x40) +#define BMM350_CP_INTREFS_EN_TM_POS UINT8_C(0x6) +#define BMM350_ADC_LOCAL_CHOP_EN_MSK UINT8_C(0x20) +#define BMM350_ADC_LOCAL_CHOP_EN_POS UINT8_C(0x5) +#define BMM350_INA_MODE_MSK UINT8_C(0x40) +#define BMM350_INA_MODE_POS UINT8_C(0x6) +#define BMM350_VDDD_EXT_EN_MSK UINT8_C(0x20) +#define BMM350_VDDD_EXT_EN_POS UINT8_C(0x5) +#define BMM350_VDDP_EXT_EN_MSK UINT8_C(0x80) +#define BMM350_VDDP_EXT_EN_POS UINT8_C(0x7) +#define BMM350_ADC_DSENS_EN_MSK UINT8_C(0x10) +#define BMM350_ADC_DSENS_EN_POS UINT8_C(0x4) +#define BMM350_DSENS_EN_MSK UINT8_C(0x20) +#define BMM350_DSENS_EN_POS UINT8_C(0x5) +#define BMM350_OTP_TM_CLVWR_EN_MSK UINT8_C(0x40) +#define BMM350_OTP_TM_CLVWR_EN_POS UINT8_C(0x6) +#define BMM350_OTP_VDDP_DIS_MSK UINT8_C(0x80) +#define BMM350_OTP_VDDP_DIS_POS UINT8_C(0x7) +#define BMM350_FORCE_HIGH_VREF_IREF_OK_MSK UINT8_C(0x10) +#define BMM350_FORCE_HIGH_VREF_IREF_OK_POS UINT8_C(0x4) +#define BMM350_FORCE_HIGH_FOSC_OK_MSK UINT8_C(0x20) +#define BMM350_FORCE_HIGH_FOSC_OK_POS UINT8_C(0x5) +#define BMM350_FORCE_HIGH_MFE_BG_RDY_MSK UINT8_C(0x40) +#define BMM350_FORCE_HIGH_MFE_BG_RDY_POS UINT8_C(0x6) +#define BMM350_FORCE_HIGH_MFE_VTMR_RDY_MSK UINT8_C(0x80) +#define BMM350_FORCE_HIGH_MFE_VTMR_RDY_POS UINT8_C(0x7) +#define BMM350_ERR_END_OF_RECHARGE_MSK UINT8_C(0x1) +#define BMM350_ERR_END_OF_RECHARGE_POS UINT8_C(0x0) +#define BMM350_ERR_END_OF_DISCHARGE_MSK UINT8_C(0x2) +#define BMM350_ERR_END_OF_DISCHARGE_POS UINT8_C(0x1) +#define BMM350_CP_TMX_DIGTP_SEL_MSK UINT8_C(0x7) +#define BMM350_CP_TMX_DIGTP_SEL_POS UINT8_C(0x0) +#define BMM350_CP_CPOSC_EN_TM_MSK UINT8_C(0x80) +#define BMM350_CP_CPOSC_EN_TM_POS UINT8_C(0x7) +#define BMM350_TST_ATM1_CFG_MSK UINT8_C(0x3f) +#define BMM350_TST_ATM1_CFG_POS UINT8_C(0x0) +#define BMM350_TST_TB1_EN_MSK UINT8_C(0x80) +#define BMM350_TST_TB1_EN_POS UINT8_C(0x7) +#define BMM350_TST_ATM2_CFG_MSK UINT8_C(0x1f) +#define BMM350_TST_ATM2_CFG_POS UINT8_C(0x0) +#define BMM350_TST_TB2_EN_MSK UINT8_C(0x80) +#define BMM350_TST_TB2_EN_POS UINT8_C(0x7) +#define BMM350_REG_DTB1X_SEL_MSK UINT8_C(0x7f) +#define BMM350_REG_DTB1X_SEL_POS UINT8_C(0x0) +#define BMM350_SEL_DTB1X_PAD_MSK UINT8_C(0x80) +#define BMM350_SEL_DTB1X_PAD_POS UINT8_C(0x7) +#define BMM350_REG_DTB2X_SEL_MSK UINT8_C(0x7f) +#define BMM350_REG_DTB2X_SEL_POS UINT8_C(0x0) +#define BMM350_TMR_TST_CFG_MSK UINT8_C(0x7f) +#define BMM350_TMR_TST_CFG_POS UINT8_C(0x0) +#define BMM350_TMR_TST_HIZ_VTMR_MSK UINT8_C(0x80) +#define BMM350_TMR_TST_HIZ_VTMR_POS UINT8_C(0x7) + +/****************************** OTP MACROS ***************************/ +#define BMM350_OTP_CMD_DIR_READ UINT8_C(0x20) +#define BMM350_OTP_CMD_DIR_PRGM_1B UINT8_C(0x40) +#define BMM350_OTP_CMD_DIR_PRGM UINT8_C(0x60) +#define BMM350_OTP_CMD_PWR_OFF_OTP UINT8_C(0x80) +#define BMM350_OTP_CMD_EXT_READ UINT8_C(0xA0) +#define BMM350_OTP_CMD_EXT_PRGM UINT8_C(0xE0) +#define BMM350_OTP_CMD_MSK UINT8_C(0xE0) +#define BMM350_OTP_WORD_ADDR_MSK UINT8_C(0x1F) + +#define BMM350_OTP_STATUS_ERROR_MSK UINT8_C(0xE0) +#define BMM350_OTP_STATUS_ERROR(val) (val & BMM350_OTP_STATUS_ERROR_MSK) +#define BMM350_OTP_STATUS_NO_ERROR UINT8_C(0x00) +#define BMM350_OTP_STATUS_BOOT_ERR UINT8_C(0x20) +#define BMM350_OTP_STATUS_PAGE_RD_ERR UINT8_C(0x40) +#define BMM350_OTP_STATUS_PAGE_PRG_ERR UINT8_C(0x60) +#define BMM350_OTP_STATUS_SIGN_ERR UINT8_C(0x80) +#define BMM350_OTP_STATUS_INV_CMD_ERR UINT8_C(0xA0) +#define BMM350_OTP_STATUS_CMD_DONE UINT8_C(0x01) + +/****************************** OTP indices ***************************/ +#define BMM350_TEMP_OFF_SENS UINT8_C(0x0D) + +#define BMM350_MAG_OFFSET_X UINT8_C(0x0E) +#define BMM350_MAG_OFFSET_Y UINT8_C(0x0F) +#define BMM350_MAG_OFFSET_Z UINT8_C(0x10) + +#define BMM350_MAG_SENS_X UINT8_C(0x10) +#define BMM350_MAG_SENS_Y UINT8_C(0x11) +#define BMM350_MAG_SENS_Z UINT8_C(0x11) + +#define BMM350_MAG_TCO_X UINT8_C(0x12) +#define BMM350_MAG_TCO_Y UINT8_C(0x13) +#define BMM350_MAG_TCO_Z UINT8_C(0x14) + +#define BMM350_MAG_TCS_X UINT8_C(0x12) +#define BMM350_MAG_TCS_Y UINT8_C(0x13) +#define BMM350_MAG_TCS_Z UINT8_C(0x14) + +#define BMM350_MAG_DUT_T_0 UINT8_C(0x18) + +#define BMM350_CROSS_X_Y UINT8_C(0x15) +#define BMM350_CROSS_Y_X UINT8_C(0x15) +#define BMM350_CROSS_Z_X UINT8_C(0x16) +#define BMM350_CROSS_Z_Y UINT8_C(0x16) + +#define BMM350_SENS_CORR_Y (0.01f) +#define BMM350_TCS_CORR_Z (0.0001f) + +/**************************** Signed bit macros **********************/ +#define BMM350_SIGNED_8_BIT UINT8_C(8) +#define BMM350_SIGNED_12_BIT UINT8_C(12) +#define BMM350_SIGNED_16_BIT UINT8_C(16) +#define BMM350_SIGNED_21_BIT UINT8_C(21) +#define BMM350_SIGNED_24_BIT UINT8_C(24) + +/**************************** Self-test macros **********************/ +#define BMM350_SELF_TEST_DISABLE UINT8_C(0x00) +#define BMM350_SELF_TEST_POS_X UINT8_C(0x0D) +#define BMM350_SELF_TEST_NEG_X UINT8_C(0x0B) +#define BMM350_SELF_TEST_POS_Y UINT8_C(0x15) +#define BMM350_SELF_TEST_NEG_Y UINT8_C(0x13) + +#define BMM350_X_FM_XP_UST_MAX_LIMIT INT16_C(150) +#define BMM350_X_FM_XP_UST_MIN_LIMIT INT16_C(50) + +#define BMM350_X_FM_XN_UST_MAX_LIMIT INT16_C(-50) +#define BMM350_X_FM_XN_UST_MIN_LIMIT INT16_C(-150) + +#define BMM350_Y_FM_YP_UST_MAX_LIMIT INT16_C(150) +#define BMM350_Y_FM_YP_UST_MIN_LIMIT INT16_C(50) + +#define BMM350_Y_FM_YN_UST_MAX_LIMIT INT16_C(-50) +#define BMM350_Y_FM_YN_UST_MIN_LIMIT INT16_C(-150) + +/**************************** PMU command status 0 macros **********************/ +#define BMM350_PMU_CMD_STATUS_0_SUS UINT8_C(0x00) +#define BMM350_PMU_CMD_STATUS_0_NM UINT8_C(0x01) +#define BMM350_PMU_CMD_STATUS_0_UPD_OAE UINT8_C(0x02) +#define BMM350_PMU_CMD_STATUS_0_FM UINT8_C(0x03) +#define BMM350_PMU_CMD_STATUS_0_FM_FAST UINT8_C(0x04) +#define BMM350_PMU_CMD_STATUS_0_FGR UINT8_C(0x05) +#define BMM350_PMU_CMD_STATUS_0_FGR_FAST UINT8_C(0x06) +#define BMM350_PMU_CMD_STATUS_0_BR UINT8_C(0x07) +#define BMM350_PMU_CMD_STATUS_0_BR_FAST UINT8_C(0x07) + +/****************************** Enumerators ***************************/ +enum bmm350_interrupt_enable_disable { + BMM350_DISABLE_INTERRUPT = BMM350_DISABLE, + BMM350_ENABLE_INTERRUPT = BMM350_ENABLE +}; + +enum bmm350_power_modes { + BMM350_SUSPEND_MODE = BMM350_PMU_CMD_SUS, + BMM350_NORMAL_MODE = BMM350_PMU_CMD_NM, + BMM350_FORCED_MODE = BMM350_PMU_CMD_FM, + BMM350_FORCED_MODE_FAST = BMM350_PMU_CMD_FM_FAST +}; + +enum bmm350_data_rates { + BMM350_DATA_RATE_400HZ = BMM350_ODR_400HZ, + BMM350_DATA_RATE_200HZ = BMM350_ODR_200HZ, + BMM350_DATA_RATE_100HZ = BMM350_ODR_100HZ, + BMM350_DATA_RATE_50HZ = BMM350_ODR_50HZ, + BMM350_DATA_RATE_25HZ = BMM350_ODR_25HZ, + BMM350_DATA_RATE_12_5HZ = BMM350_ODR_12_5HZ, + BMM350_DATA_RATE_6_25HZ = BMM350_ODR_6_25HZ, + BMM350_DATA_RATE_3_125HZ = BMM350_ODR_3_125HZ, + BMM350_DATA_RATE_1_5625HZ = BMM350_ODR_1_5625HZ +}; + +enum bmm350_magreset_type { + BMM350_FLUXGUIDE_9MS = BMM350_PMU_CMD_FGR, + BMM350_FLUXGUIDE_FAST = BMM350_PMU_CMD_FGR_FAST, + BMM350_BITRESET_9MS = BMM350_PMU_CMD_BR, + BMM350_BITRESET_FAST = BMM350_PMU_CMD_BR_FAST, + BMM350_NOMAGRESET = UINT8_C(127) +}; + +enum bmm350_intr_en_dis { + BMM350_INTR_DISABLE = BMM350_DISABLE, + BMM350_INTR_ENABLE = BMM350_ENABLE +}; + +enum bmm350_intr_map { + BMM350_UNMAP_FROM_PIN = BMM350_DISABLE, + BMM350_MAP_TO_PIN = BMM350_ENABLE +}; +enum bmm350_intr_latch { + BMM350_PULSED = BMM350_INT_MODE_PULSED, + BMM350_LATCHED = BMM350_INT_MODE_LATCHED +}; + +enum bmm350_intr_polarity { + BMM350_ACTIVE_LOW = BMM350_INT_POL_ACTIVE_LOW, + BMM350_ACTIVE_HIGH = BMM350_INT_POL_ACTIVE_HIGH +}; + +enum bmm350_intr_drive { + BMM350_INTR_OPEN_DRAIN = BMM350_INT_OD_OPENDRAIN, + BMM350_INTR_PUSH_PULL = BMM350_INT_OD_PUSHPULL +}; + +enum bmm350_drdy_int_map_to_ibi { + BMM350_IBI_DISABLE = BMM350_DISABLE, + BMM350_IBI_ENABLE = BMM350_ENABLE +}; + +enum bmm350_clear_drdy_int_status_upon_ibi { + BMM350_NOCLEAR_ON_IBI = BMM350_DISABLE, + BMM350_CLEAR_ON_IBI = BMM350_ENABLE +}; + +enum bmm350_i2c_wdt_en { + BMM350_I2C_WDT_DIS = BMM350_DISABLE, + BMM350_I2C_WDT_EN = BMM350_ENABLE +}; + +enum bmm350_i2c_wdt_sel { + BMM350_I2C_WDT_SEL_SHORT = BMM350_DISABLE, + BMM350_I2C_WDT_SEL_LONG = BMM350_ENABLE +}; + +enum bmm350_performance_parameters { + BMM350_NO_AVERAGING = BMM350_AVG_NO_AVG, + BMM350_AVERAGING_2 = BMM350_AVG_2, + BMM350_AVERAGING_4 = BMM350_AVG_4, + BMM350_AVERAGING_8 = BMM350_AVG_8, + /*lint -e849*/ + BMM350_ULTRALOWNOISE = BMM350_AVG_8, + BMM350_LOWNOISE = BMM350_AVG_4, + BMM350_REGULARPOWER = BMM350_AVG_2, + BMM350_LOWPOWER = BMM350_AVG_NO_AVG +}; + +enum bmm350_st_igen_en { + BMM350_ST_IGEN_DIS = BMM350_DISABLE, + BMM350_ST_IGEN_EN = BMM350_ENABLE +}; + +enum bmm350_st_n { + BMM350_ST_N_DIS = BMM350_DISABLE, + BMM350_ST_N_EN = BMM350_ENABLE +}; + +enum bmm350_st_p { + BMM350_ST_P_DIS = BMM350_DISABLE, + BMM350_ST_P_EN = BMM350_ENABLE +}; + +enum bmm350_ist_en_x { + BMM350_IST_X_DIS = BMM350_DISABLE, + BMM350_IST_X_EN = BMM350_ENABLE +}; + +enum bmm350_ist_en_y { + BMM350_IST_Y_DIS = BMM350_DISABLE, + BMM350_IST_Y_EN = BMM350_ENABLE +}; + +enum bmm350_ctrl_user { + BMM350_CFG_SENS_TIM_AON_DIS = BMM350_DISABLE, + BMM350_CFG_SENS_TIM_AON_EN = BMM350_ENABLE +}; + +enum bmm350_x_axis_en_dis { + BMM350_X_DIS = BMM350_DISABLE, + BMM350_X_EN = BMM350_ENABLE +}; + +enum bmm350_y_axis_en_dis { + BMM350_Y_DIS = BMM350_DISABLE, + BMM350_Y_EN = BMM350_ENABLE +}; + +enum bmm350_z_axis_en_dis { + BMM350_Z_DIS = BMM350_DISABLE, + BMM350_Z_EN = BMM350_ENABLE +}; + +/******************************************************************************/ +/*! @name Function Pointers */ +/******************************************************************************/ + +/*! + * @brief Bus communication function pointer which should be mapped to + * the platform specific read functions of the user + * + * @param[in] reg_addr : Register address from which data is read. + * @param[out] reg_data : Pointer to data buffer where read data is stored. + * @param[in] len : Number of bytes of data to be read. + * @param[in, out] intf_ptr : Void pointer that can enable the linking of descriptors + * for interface related call backs. + * + * retval = 0 -> Success + * retval < 0 -> Failure + * + */ +typedef BMM350_INTF_RET_TYPE (*bmm350_read_fptr_t)(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, void *intf_ptr); + +/*! + * @brief Bus communication function pointer which should be mapped to + * the platform specific write functions of the user + * + * @param[in] reg_addr : Register address to which the data is written. + * @param[in] reg_data : Pointer to data buffer in which data to be written + * is stored. + * @param[in] len : Number of bytes of data to be written. + * @param[in, out] intf_ptr : Void pointer that can enable the linking of descriptors + * for interface related call backs + * + * retval = 0 -> Success + * retval < 0 -> Failure + * + */ +typedef BMM350_INTF_RET_TYPE (*bmm350_write_fptr_t)(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, + void *intf_ptr); + +/*! + * @brief Delay function pointer which should be mapped to + * delay function of the user + * + * @param[in] period : Delay in microseconds. + * @param[in, out] intf_ptr : Void pointer that can enable the linking of descriptors + * for interface related call backs + * + */ +typedef void (*bmm350_delay_us_fptr_t)(uint32_t period, void *intf_ptr); + +/* Pre-declaration */ +struct bmm350_dev; + +/*! + * @brief Function pointer for the magnetic reset and wait override + * + * @param[in] dev : Structure instance of bmm350_dev. + * @return Result of API execution status + * @retval = 0 -> Success + * @retval < 0 -> Error + */ +typedef int8_t (*bmm350_mraw_override_t)(struct bmm350_dev *dev); + +/************************* STRUCTURE DEFINITIONS *************************/ + +/*! + * @brief bmm350 un-compensated (raw) magnetometer data, signed integer + */ +struct bmm350_raw_mag_data +{ + /*! Raw mag X data */ + int32_t raw_xdata; + + /*! Raw mag Y data */ + int32_t raw_ydata; + + /*! Raw mag Z data */ + int32_t raw_zdata; + + /*! Raw mag temperature value */ + int32_t raw_data_t; +}; + +/*! + * @brief bmm350 compensated magnetometer data and temperature data + */ +struct bmm350_mag_temp_data +{ + /*! Compensated mag X data */ + float x; + + /*! Compensated mag Y data */ + float y; + + /*! Compensated mag Z data */ + float z; + + /*! Temperature */ + float temperature; +}; + +/*! + * @brief bmm350 magnetometer dut offset coefficient structure + */ +struct bmm350_dut_offset_coef +{ + /*! Temperature offset */ + float t_offs; + + /*! Offset x-axis */ + float offset_x; + + /*! Offset y-axis */ + float offset_y; + + /*! Offset z-axis */ + float offset_z; +}; + +/*! + * @brief bmm350 magnetometer dut sensitivity coefficient structure + */ +struct bmm350_dut_sensit_coef +{ + /*! Temperature sensitivity */ + float t_sens; + + /*! Sensitivity x-axis */ + float sens_x; + + /*! Sensitivity y-axis */ + float sens_y; + + /*! Sensitivity z-axis */ + float sens_z; +}; + +/*! + * @brief bmm350 magnetometer dut tco structure + */ +struct bmm350_dut_tco +{ + float tco_x; + float tco_y; + float tco_z; +}; + +/*! + * @brief bmm350 magnetometer dut tcs structure + */ +struct bmm350_dut_tcs +{ + float tcs_x; + float tcs_y; + float tcs_z; +}; + +/*! + * @brief bmm350 magnetometer cross axis compensation structure + */ +struct bmm350_cross_axis +{ + float cross_x_y; + float cross_y_x; + float cross_z_x; + float cross_z_y; +}; + +/*! + * @brief bmm350 magnetometer compensate structure + */ +struct bmm350_mag_compensate +{ + /*! Structure to store dut offset coefficient */ + struct bmm350_dut_offset_coef dut_offset_coef; + + /*! Structure to store dut sensitivity coefficient */ + struct bmm350_dut_sensit_coef dut_sensit_coef; + + /*! Structure to store dut tco */ + struct bmm350_dut_tco dut_tco; + + /*! Structure to store dut tcs */ + struct bmm350_dut_tcs dut_tcs; + + /*! Initialize T0_reading parameter */ + float dut_t0; + + /*! Structure to define cross axis compensation */ + struct bmm350_cross_axis cross_axis; +}; + +/*! + * @brief bmm350 device structure + */ +struct bmm350_dev +{ + /*! + * The interface pointer is used to enable the user + * to link their interface descriptors for reference during the + * implementation of the read and write interfaces to the + * hardware. + */ + void* intf_ptr; + + /*! Chip Id of BMM350 */ + uint8_t chip_id; + + /*! Bus read function pointer */ + bmm350_read_fptr_t read; + + /*! Bus write function pointer */ + bmm350_write_fptr_t write; + + /*! delay(in us) function pointer */ + bmm350_delay_us_fptr_t delay_us; + + /*! To store interface pointer error */ + BMM350_INTF_RET_TYPE intf_rslt; + + /*! Variable to store status of axes enabled */ + uint8_t axis_en; + + /*! Structure for mag compensate */ + struct bmm350_mag_compensate mag_comp; + + /*! Array to store OTP data */ + uint16_t otp_data[BMM350_OTP_DATA_LENGTH]; + + /*! Variant ID */ + uint8_t var_id; + + /*! Magnetic reset and wait override */ + bmm350_mraw_override_t mraw_override; +}; + +/*! + * @brief bmm350 self-test structure + */ +struct bmm350_self_test +{ + /* Variable to store self-test data on x-axis */ + float out_ust_x; + + /* Variable to store self-test data on y-axis */ + float out_ust_y; +}; + +/*! + * @brief bmm350 PMU command status 0 structure + */ +struct bmm350_pmu_cmd_status_0 +{ + /*! The previous PMU CMD is still in processing */ + uint8_t pmu_cmd_busy; + + /*! The previous PMU_CMD_AGGR_SET.odr has been overwritten */ + uint8_t odr_ovwr; + + /*! The previous PMU_CMD_AGGR_SET.avg has been overwritten */ + uint8_t avr_ovwr; + + /*! The chip is in normal power mode */ + uint8_t pwr_mode_is_normal; + + /*! CMD value is not allowed */ + uint8_t cmd_is_illegal; + + /*! Stores the latest PMU_CMD code processed */ + uint8_t pmu_cmd_value; +}; + +#endif /* _BMM350_DEFS_H */ diff --git a/bmm350_oor.c b/bmm350_oor.c new file mode 100644 index 0000000..47248e3 --- /dev/null +++ b/bmm350_oor.c @@ -0,0 +1,329 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bmm350_oor.c +* @date 2023-05-26 +* @version v1.4.0 +* +*/ + +#include "bmm350_oor.h" + +#ifdef BMM350_OOR_HALF_SELF_TEST + +/*! + * @brief This internal API is used to trigger half self-test + */ +static int8_t trigger_half_selftest(struct bmm350_oor_params *oor, struct bmm350_dev *dev) +{ + int8_t rslt = BMM350_OK; + + oor->st_cmd = BMM350_SELF_TEST_DISABLE; + + /* Trigger a self-test on every alternate measurement if needed */ + if (oor->enable_selftest) + { + oor->st_counter++; + + switch (oor->st_counter) + { + case 1: + oor->st_cmd = BMM350_SELF_TEST_POS_X; + break; + case 2: + oor->st_cmd = BMM350_SELF_TEST_DISABLE; + break; + case 3: + oor->st_cmd = BMM350_SELF_TEST_POS_Y; + break; + case 4: + oor->st_cmd = BMM350_SELF_TEST_DISABLE; + break; + + default: + oor->st_counter = 0; + oor->st_cmd = BMM350_SELF_TEST_DISABLE; + break; + } + + rslt = bmm350_set_regs(BMM350_REG_TMR_SELFTEST_USER, &(oor->st_cmd), 1, dev); + } + else + { + if (oor->last_st_cmd != BMM350_SELF_TEST_DISABLE) + { + rslt = bmm350_set_regs(BMM350_REG_TMR_SELFTEST_USER, &(oor->st_cmd), 1, dev); + oor->st_counter = 0; + } + } + + return rslt; +} + +/*! + * @brief This internal API is used to validate half self-test + */ +static void validate_half_selftest(const struct bmm350_mag_temp_data *data, struct bmm350_oor_params *oor) +{ + switch (oor->last_st_cmd) + { + case BMM350_SELF_TEST_DISABLE: + oor->mag_xn = data->x; + oor->mag_yn = data->y; + break; + + case BMM350_SELF_TEST_POS_X: + oor->mag_xp = data->x; + oor->x_failed = (oor->mag_xp - oor->mag_xn) < BMM350_HALF_ST_THRESHOLD ? true : false; + break; + + case BMM350_SELF_TEST_POS_Y: + oor->mag_yp = data->y; + oor->y_failed = (oor->mag_yp - oor->mag_yn) < BMM350_HALF_ST_THRESHOLD ? true : false; + break; + + default: + break; + } +} +#else + +/*! + * @brief This internal API is used to trigger full self-test + */ +static int8_t trigger_full_selftest(struct bmm350_oor_params *oor, struct bmm350_dev *dev) +{ + int8_t rslt = BMM350_OK; + + oor->st_cmd = BMM350_SELF_TEST_DISABLE; + + /* Trigger a self-test on every alternate measurement if needed */ + if (oor->enable_selftest) + { + oor->st_counter++; + + switch (oor->st_counter) + { + case 1: + oor->st_cmd = BMM350_SELF_TEST_POS_X; + break; + case 2: + oor->st_cmd = BMM350_SELF_TEST_NEG_X; + break; + case 3: + oor->st_cmd = BMM350_SELF_TEST_POS_Y; + break; + case 4: + oor->st_cmd = BMM350_SELF_TEST_NEG_Y; + break; + + default: + oor->st_counter = 0; + oor->st_cmd = BMM350_SELF_TEST_DISABLE; + break; + } + + rslt = bmm350_set_regs(BMM350_REG_TMR_SELFTEST_USER, &(oor->st_cmd), 1, dev); + } + else + { + if (oor->last_st_cmd != BMM350_SELF_TEST_DISABLE) + { + rslt = bmm350_set_regs(BMM350_REG_TMR_SELFTEST_USER, &(oor->st_cmd), 1, dev); + oor->st_counter = 0; + } + } + + return rslt; +} + +/*! + * @brief This internal API is used to validate full self-test + */ +static void validate_full_selftest(const struct bmm350_mag_temp_data *data, struct bmm350_oor_params *oor) +{ + switch (oor->last_st_cmd) + { + case BMM350_SELF_TEST_POS_X: + oor->mag_xp = data->x; + break; + + case BMM350_SELF_TEST_NEG_X: + oor->mag_xn = data->x; + oor->x_failed = (oor->mag_xp - oor->mag_xn) < BMM350_FULL_ST_THRESHOLD ? true : false; + break; + + case BMM350_SELF_TEST_POS_Y: + oor->mag_yp = data->y; + break; + + case BMM350_SELF_TEST_NEG_Y: + oor->mag_yn = data->y; + oor->y_failed = (oor->mag_yp - oor->mag_yn) < BMM350_FULL_ST_THRESHOLD ? true : false; + break; + + default: + break; + } +} +#endif + +/*! + * @brief This internal API is used to validate out of range. + */ +static void validate_out_of_range(bool *out_of_range, + const struct bmm350_mag_temp_data *data, + struct bmm350_oor_params *oor) +{ + float field_str = 0.0f; + + /* Threshold to start out of range detection */ + float threshold = BMM350_OUT_OF_RANGE_THRESHOLD; + + /* Threshold to start self-tests */ + float st_threshold = BMM350_SELF_TEST_THRESHOLD; + + /* If either self-test failed, alert that the sensor is out of range and continue self-tests */ + if (oor->x_failed || oor->y_failed) + { + *out_of_range = true; + oor->enable_selftest = true; + } + else + { + field_str = sqrtf((data->x * data->x) + (data->y * data->y) + (data->z * data->z)); + + /* Check for the self-test threshold and perform self-tests to catch if the sensor is out of range */ + if ((fabsf(data->x) >= st_threshold) || (fabsf(data->y) >= st_threshold) || (fabsf(data->z) >= st_threshold) || + (field_str >= st_threshold)) + { + oor->enable_selftest = true; + } + else if (oor->st_counter == 0) /* If a self-test procedure has started, wait for it to complete */ + { + oor->enable_selftest = false; + } + + /* If out of range was previously detected, reduce the threshold to get back in range, + * effectively preventing hysteresis. Selecting 400uT */ + if (*out_of_range) + { + threshold = BMM350_IN_RANGE_THRESHOLD; + } + + /* Check if X or Y or Z > the threshold or the magnitude of all 3 is greater */ + if ((fabsf(data->x) >= threshold) || (fabsf(data->y) >= threshold) || (fabsf(data->z) >= threshold) || + (field_str >= threshold)) + { + *out_of_range = true; + } + else if (oor->st_counter == 0) /* If a self-test procedure has started, wait for it to complete */ + { + *out_of_range = false; + } + } +} + +/*! + * @brief This API is used to perform reset sequence in forced mode. + */ +int8_t bmm350_oor_perform_reset_sequence_forced(struct bmm350_oor_params *oor, struct bmm350_dev *dev) +{ + int8_t rslt = 0; + uint8_t pmu_cmd = 0; + + oor->reset_counter++; + + switch (oor->reset_counter) + { + case 1: /* Trigger the Bit reset fast */ + pmu_cmd = BMM350_PMU_CMD_BR_FAST; + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD, &pmu_cmd, 1, dev); + break; + + case 2: /* Trigger Flux Guide reset */ + pmu_cmd = BMM350_PMU_CMD_FGR; + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD, &pmu_cmd, 1, dev); + break; + + case 3: /* Flux Guide dummy */ + break; + + default: /* Default acts like the Flux guide reset dummy */ + oor->reset_counter = 0; + oor->trigger_reset = false; + break; + } + + return rslt; +} + +/*! + * @brief This API is used to read out of range in half or full self-test. + */ +int8_t bmm350_oor_read(bool *out_of_range, + struct bmm350_mag_temp_data *data, + struct bmm350_oor_params *oor, + struct bmm350_dev *dev) +{ + int8_t rslt = 0; + uint8_t pmu_cmd = BMM350_PMU_CMD_SUS; + +#ifdef BMM350_OOR_HALF_SELF_TEST + rslt = trigger_half_selftest(oor, dev); +#else + rslt = trigger_full_selftest(oor, dev); +#endif + + if (rslt == BMM350_OK) + { + pmu_cmd = BMM350_PMU_CMD_FM_FAST; + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD, &pmu_cmd, 1, dev); + + if (rslt == BMM350_OK) + { + rslt = bmm350_get_compensated_mag_xyz_temp_data(data, dev); + } + } + +#ifdef BMM350_OOR_HALF_SELF_TEST + validate_half_selftest(data, oor); +#else + validate_full_selftest(data, oor); +#endif + + validate_out_of_range(out_of_range, data, oor); + + oor->last_st_cmd = oor->st_cmd; + + return rslt; +} diff --git a/bmm350_oor.h b/bmm350_oor.h new file mode 100644 index 0000000..275c953 --- /dev/null +++ b/bmm350_oor.h @@ -0,0 +1,136 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bmm350_oor.h +* @date 2023-05-26 +* @version v1.4.0 +* +*/ + +#ifndef _BMM350_OOR_H +#define _BMM350_OOR_H + +#include +#include + +#include "bmm350.h" + +/*! CPP guard */ +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************/ +/*! @name General Macro Definitions */ +/******************************************************************************/ + +/*! Macro to define half self-test for out of range + * NOTE: Comment this to use both positive and negative self tests */ +#define BMM350_OOR_HALF_SELF_TEST + +/*! Macro to define mag data minimum and maximum range in uT */ +#define BMM350_HALF_ST_THRESHOLD (130.0f) +#define BMM350_FULL_ST_THRESHOLD (300.0f) + +/*! Macro to define threshold values of in range, out of range and self-test */ +#define BMM350_IN_RANGE_THRESHOLD (2000.0f) +#define BMM350_OUT_OF_RANGE_THRESHOLD (2400.0f) +#define BMM350_SELF_TEST_THRESHOLD (2600.0f) + +/************************* Structure definitions *************************/ + +/*! + * @brief Structure to define bmm350 out of range parameters + */ +struct bmm350_oor_params +{ + /*! Counter to track what self test to trigger */ + uint8_t st_counter; + + /*! Current self-test command */ + uint8_t st_cmd; + + /*! Stores the last applied self test configuration */ + uint8_t last_st_cmd; + + /*! Store the last measurements for comparing against the self-test */ + float mag_xp, mag_xn, mag_yp, mag_yn; + + /*! Flags to track if the test failed to redo it */ + bool x_failed, y_failed; + + /*! Flags to enable self-test */ + bool enable_selftest; + + /*! Flags to trigger reset */ + bool trigger_reset; + + /*! Variable to store reset counter value */ + uint8_t reset_counter; +}; + +/******************* Function prototype declarations ********************/ + +/*! + * @brief Function to read data and validate if the sensor is out of range + * + * @param[in,out] out_of_range : Flag that indicates that the sensor is out of range + * @param[out] data : Sensor data + * @param[out] oor : Structure that stores the state of the out of range detector + * @param[in,out] dev : Device structure of the BMM350 + * + * @return Result of API execution status + * @retval = 0 -> Success + * @retval < 0 -> Error + */ +int8_t bmm350_oor_read(bool *out_of_range, + struct bmm350_mag_temp_data *data, + struct bmm350_oor_params *oor, + struct bmm350_dev *dev); + +/*! + * @brief Function to perform reset sequence in forced mode. + * + * @param[in,out] oor : Structure that stores the state of the out of range detector + * @param[in,out] dev : Structure instance of bmm350_dev. + * + * @return Result of API execution status + * @retval = 0 -> Success + * @retval < 0 -> Error + */ +int8_t bmm350_oor_perform_reset_sequence_forced(struct bmm350_oor_params *oor, struct bmm350_dev *dev); + +#ifdef __cplusplus +} +#endif /* End of CPP guard */ + +#endif /* _BMM350_OOR_H */ diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..2173617 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,295 @@ +# BMM350 Examples + +Commands to run tests on MCU: + +To run in Command line : +--------------------------- +1. mingw32-make clean +2. mingw32-make TARGET=MCU_APP30 all +3. mingw32-make TARGET=MCU_APP30 download + +Commands to run tests on PC: + +To run in Command line : +--------------------------- +1. mingw32-make clean +2. mingw32-make all + +### Example 1 : bmm3530 config changes: + + This example is to test the change in configurations like powermode, ODR and AVG, axis enabling/disabling etc. + +#### Procedure: + +1. Check chip_id +2. Set normal mode +3. Read data and print +4. Calculate mean and noise for 100 samples +5. Reconfigure ODR and AVG( 50,8x / 400,1x / 25,4x ) in normal mode +6. Set suspend mode +7. Read data and print (10x loop) -> no change +8. Disable x and y axis alone +9. Set normal mode +10. Read 20x and print + +#### Usecase: + +1. To test the behaviour of sensor in normal mode and suspend mode + +### Example 2 : bmm350 forced mode: + + This example is to read the mag data in forced mode under various configurations + +#### Procedure: + +For combination 1, + + Set forced mode fast and read data with averaging between 4 samples + + Usecase: No change is data so the customer understands that forced mode just does 1 conversion. + +For combination 2, + + Set forced mode fast and read data with averaging between 4 samples in a loop + + Usecase: The value changes for every read + +For combination 3, + + Set forced mode and read data with no averaging between samples in a loop + + Usecase: Customer understands how AVG setting affects forced mode + +For combination 4, + + Set forced mode fast and read data with averaging between 4 samples in a loop + + Usecase: The value changes for every read + +For combination 5, + + Set forced mode and read data with no averaging between samples in a loop + + Usecase: Customer understands how AVG setting affects forced mode + +For combination 6, + + Set forced mode fast and read data with averaging between 2 samples in a loop + + Usecase: The value changes for every read. Also customer understands that a small AVG setting requires less time for a conversion. + +### Example 3 : bmm350 illegal command: + + This example is to read the flag bit PMU_CMD_STATUS_0.cmd_is_illegal. When PMU_CMD register is set to illegal values, then the flag bit is set. + +#### Procedure: + +1. Read chip id +2. Set legal PMU_CMD (0 to 8) +3. Read PMU_CMD_STATUS_0.cmd_is_illegal +4. Set illegal PMU_CMD (10 to 15) +5. Read PMU_CMD_STATUS_0.cmd_is_illegal + +#### Usecase: + +1. Customer understands bmm350 is robust against bad commands sent to PMU_CMD + +### Example 4 : bmm350 interrupt: + + This example is to test the interrupts by changing the interrupt pin configurations. + +#### Procedure: + +1. Check Chip id +2. Configure interrupt( active HIGH, pulsed, mapped to INT pin, push-pull) +3. Wait for 10 seconds +4. Change different ODR +5. Wait for 10 seconds +6. Configure interrupt( active LOW, pulsed, mapped to INT pin, push-pull) +7. Wait for 10 seconds +8. Configure interrupt( active LOW, latched, mapped to INT pin, push-pull) +9. Wait for 10 seconds +10. Configure interrupt( active HIGH, pulsed, mapped to INT pin, push-pull) + +#### Usecase: + +1. Customer should use oscilloscope to watch INT pin pulsing +2. Customer will see INT going LOW (active LOW) and stay there + +##### Scenario 1: + + Read magnetic and temperature data with 100ms delay for 20 times + +##### Usecase: + + Customer will understand that clearing interrupt status requires reading data + +##### Scenario 2: + + Read magnetic and temperature data with hardware interrupt by reading INT_STATUS register for 20 times + +##### Usecase: + + Customer will understand that clearing interrupt status can also be done by reading INT_STATUS + +### Example 5 : bmm350 magnetic reset: + + This example is to understand what to do to trigger magnetic reset , e.g. after magnetic shock or longer idle times in suspend + +#### Procedure: + +1. Set normal mode +2. Read magnetic and temperature data for 20 times and print +3. Set suspend mode +4. Send magnetic reset +5. Set normal mode +6. Read magnetic and temperature data for 20 times and print +7. Send magnetic reset +8. Read magnetic and temperature data for 20 times and print + +#### Usecase: + +1. Customer understands that API function checks for power mode. It automatically switches to suspend and restores normal mode if this was the mode selected + +### Example 6 : bmm350 polling: + + This example is to read the magnetic and temperature data by polling machanism. + +#### Procedure: + +##### Scenario 1: + + 1. Set normal mode + 2. Set ODR = 25Hz, AVG = 8x + 3. Loop = 20 + 4. Wait for 36ms (1 ODR period - 10% margin) + 5. Read the magnetic and temperature data and print + +##### Usecase: + + Customer understands that too fast reading leads to double reads. too slow reading thus leads to loss of data. + +##### Scenario 2: + + 1. Set normal mode + 2. Set ODR = 25Hz, AVG = 8x + 3. Loop = 22 + 4. Read the magnetic and temperature data by reading INT_STATUS register and print + +##### Usecase: + + Customer understands data loss can be prevented by reading data ready flag before reading data. + + +### Example 7 : bmm350 self test: + + This example is to test the selftest on various power modes + +#### Procedure: + +##### Scenario 1: + +1. Set normal mode +2. Loop = 10 +3. Read magnetometer and temperature data +4. Provide 100ms delay +5. Print magnetometer and temperature data + +##### Scenario 2: + +1. Set suspend mode +2. Loop = 20 +3. Call bmm350_ perform_ self_test API +4. Print selftest data +5. Loop 20 times and print magnetic and temperature data + +##### Usecase: + + Customer understands selftest is called from suspend mode + +### Example 8 : bmm350 sensor time: + + This example is to test sensortime under various power mode configurations. + +#### Procedure: + +##### Scenario 1: + + 1. Set suspend mode + 2. Read sensortime and print for 20 loop + +##### Usecase: + + Customer understands : no change in suspend mode. + +##### Scenario 2: + + 1. Set CTRL_USER to 0x01 + 2. Loop = 20 + 3. Set forced mode + 4. Wait for 40ms + 5. Read sensortime (Change in data) + 6. Read sensortime (No change in data) + 7. Read sensortime (No change in data) + +##### Usecase: + + Customer understands: sensortime is only updated when a conversion happens. +sensortime indicates the SENSOR time at which the last conversion happened + +##### Scenario 3: + + 1. Set normal mode + 2. Set ODR = 100hz, AVG = 2x + 3. Read sensortime and print for 20 loop (change in data everytime) + +##### Usecase: + + Customer understands : at every conversion sensortime is updated +this program requires compilation on the ARM since the wait time is short + +### Example 9 : bmm350 normal mode: + + This example is to read the uncompensated and compensated magnetic and temperature data in normal mode. + +#### Procedure: + +1. Read chip id +2. Configure interrupt(active HIGH, pulsed, unmap from pin, push-pull) +3. Enable data ready interrupt +4. Set ODR and AVG +5. Enable all axes +6. Set normal mode +7. Read uncompensated magnetometer and temperature data for 20 times by reading INT_STATUS register +8. Read compensated magnetometer and temperature data for 50 times by reading INT_STATUS register + +#### Usecase: + + To find the difference between uncompensated and compensated magnetic and temperature data read in normal mode. + +### Example 10 : bmm350 out of range detect: + + This example is to measure the data from the sensor and detects when sensor goes out of range i.e greater than +/- 2400uT +with half self-test threshold and full self-test threshold + +#### Procedure: + +1. Read chip id +2. Perform self-test +3. Set ODR and AVG +4. Enable all axes +5. Set forced mode fast +6. Measure data such as + a. Magnetometer x, y and z axis + b. Field strength + c. Out of range + d. X failed and Y failed + e. Difference in magnetometer positive x and negative x and difference in magnetometer positive y and negative y + f. Reset value and Reset counter + g. Self-test active + h. Self-test counter +7. Trigger magnetic reset + +#### Usecase: + + To find the sensor state when magnetometer value goes out of range detection diff --git a/examples/bmm350_config_changes/Makefile b/examples/bmm350_config_changes/Makefile new file mode 100644 index 0000000..85d3779 --- /dev/null +++ b/examples/bmm350_config_changes/Makefile @@ -0,0 +1,17 @@ +COINES_INSTALL_PATH ?= ../../../.. + +EXAMPLE_FILE ?= bmm350_config_changes.c + +API_LOCATION ?= ../.. + +C_SRCS += \ +$(API_LOCATION)/bmm350.c \ +../common/common.c + +INCLUDEPATHS += \ +$(API_LOCATION) \ +../common + +COINES_BACKEND=COINES_BRIDGE + +include $(COINES_INSTALL_PATH)/coines.mk diff --git a/examples/bmm350_config_changes/bmm350_config_changes.c b/examples/bmm350_config_changes/bmm350_config_changes.c new file mode 100644 index 0000000..b59238f --- /dev/null +++ b/examples/bmm350_config_changes/bmm350_config_changes.c @@ -0,0 +1,327 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bmm350_config_changes.c +* +* @brief This file contains the configuration changes of magnetometer like enable disable axes and power mode. +* +*/ + +#include +#include +#include +#include + +#include "bmm350.h" +#include "common.h" +#include "coines.h" + +/******************************************************************************/ +/*! Macro Definitions */ + +#define MAG_SAMPLE_COUNT UINT8_C(100) + +/******************************************************************************/ +/*! Static Structure Definitions */ + +/*! + * @brief bmm350 compensated magnetometer data structure + */ +struct bmm350_mag_data +{ + /*! Compensated mag X data */ + double x; + + /*! Compensated mag Y data */ + double y; + + /*! Compensated mag Z data */ + double z; +}; + +/******************************************************************************/ +/*! Static Function Declaration */ + +/*! + * @brief This internal API is to calculate noise level for mag data + * + * @param[in] mag_temp_data : Structure instance of bmm350_mag_temp_data. + * @param[in] avg_mag_data : Structure to store average mag data. + * + * @return void. + */ +static void calculate_noise(const struct bmm350_mag_temp_data *mag_temp_data, struct bmm350_mag_data avg_mag_data); + +/******************************************************************************/ +/*! Functions */ + +/* This function starts the execution of program */ +int main(void) +{ + /* Status of api are returned to this variable */ + int8_t rslt; + + /* Sensor initialization configuration */ + struct bmm350_dev dev = { 0 }; + + uint8_t int_status, int_ctrl, err_reg_data = 0; + uint8_t loop = 0, set_int_ctrl; + uint32_t time_ms = 0; + + struct bmm350_mag_temp_data mag_temp_data = { 0 }; + struct bmm350_mag_temp_data get_mag_temp_data[MAG_SAMPLE_COUNT] = { { 0 } }; + struct bmm350_pmu_cmd_status_0 pmu_cmd_stat_0 = { 0 }; + struct bmm350_mag_data mean_mag_data = { 0 }; + struct bmm350_mag_data avg_mag_data = { 0 }; + + /* Update device structure */ + rslt = bmm350_interface_init(&dev); + bmm350_error_codes_print_result("bmm350_interface_selection", rslt); + + /* Initialize BMM350 */ + rslt = bmm350_init(&dev); + bmm350_error_codes_print_result("bmm350_init", rslt); + + printf("Read : 0x00 : BMM350 Chip ID : 0x%X\n", dev.chip_id); + + /* Check PMU busy */ + rslt = bmm350_get_pmu_cmd_status_0(&pmu_cmd_stat_0, &dev); + bmm350_error_codes_print_result("bmm350_get_pmu_cmd_status_0", rslt); + + printf("Expected : 0x07 : PMU cmd busy : 0x0\n"); + printf("Read : 0x07 : PMU cmd busy : 0x%X\n", pmu_cmd_stat_0.pmu_cmd_busy); + + /* Get error data */ + rslt = bmm350_get_regs(BMM350_REG_ERR_REG, &err_reg_data, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_error_reg_data", rslt); + + printf("Expected : 0x02 : Error Register : 0x0\n"); + printf("Read : 0x02 : Error Register : 0x%X\n", err_reg_data); + + /* Configure interrupt settings */ + rslt = bmm350_configure_interrupt(BMM350_PULSED, + BMM350_ACTIVE_HIGH, + BMM350_INTR_PUSH_PULL, + BMM350_UNMAP_FROM_PIN, + &dev); + bmm350_error_codes_print_result("bmm350_configure_interrupt", rslt); + + /* Enable data ready interrupt */ + rslt = bmm350_enable_interrupt(BMM350_ENABLE_INTERRUPT, &dev); + bmm350_error_codes_print_result("bmm350_enable_interrupt", rslt); + + /* Get interrupt settings */ + rslt = bmm350_get_regs(BMM350_REG_INT_CTRL, &int_ctrl, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_regs", rslt); + + set_int_ctrl = ((BMM350_INT_POL_ACTIVE_HIGH << 1) | (BMM350_INT_OD_PUSHPULL << 2) | BMM350_ENABLE << 7); + + printf("Expected : 0x2E : Interrupt control : 0x%X\n", set_int_ctrl); + printf("Read : 0x2E : Interrupt control : 0x%X\n", int_ctrl); + + if (int_ctrl & BMM350_DRDY_DATA_REG_EN_MSK) + { + printf("Data ready enabled\r\n"); + } + + /* Set ODR and performance */ + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_100HZ, BMM350_AVERAGING_4, &dev); + bmm350_error_codes_print_result("bmm350_set_odr_performance", rslt); + + /* Enable all axis */ + rslt = bmm350_enable_axes(BMM350_X_EN, BMM350_Y_EN, BMM350_Z_EN, &dev); + bmm350_error_codes_print_result("bmm350_enable_axes", rslt); + + if (rslt == BMM350_OK) + { + rslt = bmm350_set_powermode(BMM350_NORMAL_MODE, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + printf("\nCompensated Magnetometer and temperature data in NORMAL MODE\n"); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + for (loop = 0; loop < MAG_SAMPLE_COUNT;) + { + int_status = 0; + + /* Get data ready interrupt status */ + rslt = bmm350_get_regs(BMM350_REG_INT_STATUS, &int_status, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_regs", rslt); + + /* Check if data ready interrupt occurred */ + if ((rslt == BMM350_OK) && (int_status & BMM350_DRDY_DATA_REG_MSK)) + { + rslt = bmm350_get_compensated_mag_xyz_temp_data(&get_mag_temp_data[loop], &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + get_mag_temp_data[loop].x, + get_mag_temp_data[loop].y, + get_mag_temp_data[loop].z, + get_mag_temp_data[loop].temperature); + + mean_mag_data.x += get_mag_temp_data[loop].x; + mean_mag_data.y += get_mag_temp_data[loop].y; + mean_mag_data.z += get_mag_temp_data[loop].z; + + loop++; + } + } + + /* Taking average values to calculate percentage deviation */ + avg_mag_data.x = (double)(mean_mag_data.x / MAG_SAMPLE_COUNT); + avg_mag_data.y = (double)(mean_mag_data.y / MAG_SAMPLE_COUNT); + avg_mag_data.z = (double)(mean_mag_data.z / MAG_SAMPLE_COUNT); + + printf("\n***** AVERAGE MAG VALUE *****\n"); + printf("Average_Mag_X(uT), Average_Mag_Y(uT), Average_Mag_Z(uT)\n"); + + printf("%lf, %lf, %lf\n", avg_mag_data.x, avg_mag_data.y, avg_mag_data.z); + + calculate_noise(get_mag_temp_data, avg_mag_data); + + /* Set ODR and performance */ + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_50HZ, BMM350_AVERAGING_8, &dev); + bmm350_error_codes_print_result("bmm350_set_odr_performance", rslt); + + rslt = bmm350_set_powermode(BMM350_SUSPEND_MODE, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + printf("\nCompensated Magnetometer and temperature data in SUSPEND MODE\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + loop = 10; + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + while (loop--) + { + rslt = bmm350_get_compensated_mag_xyz_temp_data(&mag_temp_data, &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + mag_temp_data.temperature); + } + } + + /* Disable x and y axis, enable z axis */ + rslt = bmm350_enable_axes(BMM350_X_DIS, BMM350_Y_DIS, BMM350_Z_EN, &dev); + bmm350_error_codes_print_result("bmm350_enable_axes", rslt); + + if (rslt == BMM350_OK) + { + rslt = bmm350_set_powermode(BMM350_NORMAL_MODE, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + printf("\nCompensated Magnetometer and temperature data in NORMAL MODE\n"); + printf("Disable x and y axis, enable z axis\n\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + loop = 20; + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + while (loop) + { + int_status = 0; + + /* Get data ready interrupt status */ + rslt = bmm350_get_regs(BMM350_REG_INT_STATUS, &int_status, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_regs", rslt); + + /* Check if data ready interrupt occurred */ + if (int_status & BMM350_DRDY_DATA_REG_MSK) + { + rslt = bmm350_get_compensated_mag_xyz_temp_data(&mag_temp_data, &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + mag_temp_data.temperature); + + loop--; + } + } + } + + bmm350_coines_deinit(); + + return rslt; +} + +/*! + * @brief This internal API is to calculate noise level for mag data. + */ +static void calculate_noise(const struct bmm350_mag_temp_data *mag_temp_data, struct bmm350_mag_data avg_mag_data) +{ + double variance_x = 0, variance_y = 0, variance_z = 0; + double noise_level_x, noise_level_y, noise_level_z; + uint8_t index = 0; + + for (index = 0; index < MAG_SAMPLE_COUNT; index++) + { + variance_x += ((mag_temp_data[index].x - avg_mag_data.x) * (mag_temp_data[index].x - avg_mag_data.x)); + + variance_y += ((mag_temp_data[index].y - avg_mag_data.y) * (mag_temp_data[index].y - avg_mag_data.y)); + + variance_z += ((mag_temp_data[index].z - avg_mag_data.z) * (mag_temp_data[index].z - avg_mag_data.z)); + } + + variance_x /= MAG_SAMPLE_COUNT; + noise_level_x = sqrt(variance_x); + + variance_y /= MAG_SAMPLE_COUNT; + noise_level_y = sqrt(variance_y); + + variance_z /= MAG_SAMPLE_COUNT; + noise_level_z = sqrt(variance_z); + + printf("\nNoise level x, Noise level y, Noise level z\n"); + + printf("%lf, %lf, %lf\n", noise_level_x, noise_level_y, noise_level_z); +} diff --git a/examples/bmm350_forced_mode/Makefile b/examples/bmm350_forced_mode/Makefile new file mode 100644 index 0000000..88cafd0 --- /dev/null +++ b/examples/bmm350_forced_mode/Makefile @@ -0,0 +1,17 @@ +COINES_INSTALL_PATH ?= ../../../.. + +EXAMPLE_FILE ?= bmm350_forced_mode.c + +API_LOCATION ?= ../.. + +C_SRCS += \ +$(API_LOCATION)/bmm350.c \ +../common/common.c + +INCLUDEPATHS += \ +$(API_LOCATION) \ +../common + +COINES_BACKEND=COINES_BRIDGE + +include $(COINES_INSTALL_PATH)/coines.mk diff --git a/examples/bmm350_forced_mode/bmm350_forced_mode.c b/examples/bmm350_forced_mode/bmm350_forced_mode.c new file mode 100644 index 0000000..a11fa3f --- /dev/null +++ b/examples/bmm350_forced_mode/bmm350_forced_mode.c @@ -0,0 +1,431 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bmm350_forced_mode.c +* +* @brief This file contains reading of magnetometer data in forced mode +* with various combinations of ODR, average and delay. +* +*/ + +#include +#include +#include +#include + +#include "bmm350.h" +#include "common.h" +#include "coines.h" + +/******************************************************************************/ +/*! Macro Definitions */ + +#define MAG_SAMPLE_COUNT UINT8_C(100) + +/******************************************************************************/ +/*! Static Structure Definitions */ + +/*! + * @brief bmm350 compensated magnetometer data structure + */ +struct bmm350_mag_data +{ + /*! Compensated mag X data */ + double x; + + /*! Compensated mag Y data */ + double y; + + /*! Compensated mag Z data */ + double z; +}; + +/******************************************************************************/ +/*! Static Function Declaration */ + +/*! + * @brief This internal API is to calculate noise level for mag data + * + * @param[in] mag_temp_data : Structure instance of bmm350_mag_temp_data. + * @param[in] avg_mag_data : Structure to store average mag data. + * + * @return void. + */ +static void calculate_noise(const struct bmm350_mag_temp_data *mag_temp_data, struct bmm350_mag_data avg_mag_data); + +/******************************************************************************/ +/*! Functions */ + +/* This function starts the execution of program */ +int main(void) +{ + /* Status of api are returned to this variable */ + int8_t rslt; + + /* Sensor initialization configuration */ + struct bmm350_dev dev = { 0 }; + + uint8_t int_ctrl, err_reg_data = 0; + uint8_t loop = 10, set_int_ctrl; + uint32_t time_ms = 0; + + struct bmm350_mag_temp_data mag_temp_data = { 0 }; + struct bmm350_pmu_cmd_status_0 pmu_cmd_stat_0 = { 0 }; + struct bmm350_mag_temp_data get_mag_temp_data[MAG_SAMPLE_COUNT] = { { 0 } }; + struct bmm350_mag_data mean_mag_data_1 = { 0 }; + struct bmm350_mag_data mean_mag_data_2 = { 0 }; + struct bmm350_mag_data mean_mag_data_3 = { 0 }; + struct bmm350_mag_data avg_mag_data = { 0 }; + + /* Update device structure */ + rslt = bmm350_interface_init(&dev); + bmm350_error_codes_print_result("bmm350_interface_selection", rslt); + + /* Initialize BMM350 */ + rslt = bmm350_init(&dev); + bmm350_error_codes_print_result("bmm350_init", rslt); + + printf("Read : 0x00 : BMM350 Chip ID : 0x%X\n", dev.chip_id); + + /* Check PMU busy */ + rslt = bmm350_get_pmu_cmd_status_0(&pmu_cmd_stat_0, &dev); + bmm350_error_codes_print_result("bmm350_get_pmu_cmd_status_0", rslt); + + printf("Expected : 0x07 : PMU cmd busy : 0x0\n"); + printf("Read : 0x07 : PMU cmd busy : 0x%X\n", pmu_cmd_stat_0.pmu_cmd_busy); + + /* Get error data */ + rslt = bmm350_get_regs(BMM350_REG_ERR_REG, &err_reg_data, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_error_reg_data", rslt); + + printf("Expected : 0x02 : Error Register : 0x0\n"); + printf("Read : 0x02 : Error Register : 0x%X\n", err_reg_data); + + /* Configure interrupt settings */ + rslt = bmm350_configure_interrupt(BMM350_PULSED, + BMM350_ACTIVE_HIGH, + BMM350_INTR_PUSH_PULL, + BMM350_UNMAP_FROM_PIN, + &dev); + bmm350_error_codes_print_result("bmm350_configure_interrupt", rslt); + + /* Enable data ready interrupt */ + rslt = bmm350_enable_interrupt(BMM350_ENABLE_INTERRUPT, &dev); + bmm350_error_codes_print_result("bmm350_enable_interrupt", rslt); + + /* Get interrupt settings */ + rslt = bmm350_get_regs(BMM350_REG_INT_CTRL, &int_ctrl, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_regs", rslt); + + set_int_ctrl = ((BMM350_INT_POL_ACTIVE_HIGH << 1) | (BMM350_INT_OD_PUSHPULL << 2) | BMM350_ENABLE << 7); + + printf("Expected : 0x2E : Interrupt control : 0x%X\n", set_int_ctrl); + printf("Read : 0x2E : Interrupt control : 0x%X\n", int_ctrl); + + if (int_ctrl & BMM350_DRDY_DATA_REG_EN_MSK) + { + printf("Data ready enabled\r\n"); + } + + printf("Compensated Magnetometer and Temperature data in forced mode and forced mode fast\n"); + + printf("\nCOMBINATION 1 :\n"); + printf("Set forced mode fast and read data with averaging between 4 samples\n"); + + /* Set ODR and performance */ + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_100HZ, BMM350_AVERAGING_4, &dev); + bmm350_error_codes_print_result("bmm350_set_odr_performance", rslt); + + /* Enable all axis */ + rslt = bmm350_enable_axes(BMM350_X_EN, BMM350_Y_EN, BMM350_Z_EN, &dev); + bmm350_error_codes_print_result("bmm350_enable_axes", rslt); + + if (rslt == BMM350_OK) + { + rslt = bmm350_set_powermode(BMM350_FORCED_MODE_FAST, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + while (loop) + { + rslt = bmm350_get_compensated_mag_xyz_temp_data(&mag_temp_data, &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + mag_temp_data.temperature); + + loop--; + } + + loop = 10; + + printf("\nCOMBINATION 2 :\n"); + printf("Set forced mode fast and read data with averaging between 4 samples in a loop\n"); + + /* Set ODR and performance */ + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_100HZ, BMM350_AVERAGING_4, &dev); + bmm350_error_codes_print_result("bmm350_set_odr_performance", rslt); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + while (loop--) + { + rslt = bmm350_set_powermode(BMM350_FORCED_MODE_FAST, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + rslt = bmm350_get_compensated_mag_xyz_temp_data(&mag_temp_data, &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + mag_temp_data.temperature); + } + + loop = 10; + + printf("\nCOMBINATION 3 :\n"); + printf("Set forced mode and read data with no averaging between samples in a loop\n"); + + /* Set ODR and performance */ + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_100HZ, BMM350_NO_AVERAGING, &dev); + bmm350_error_codes_print_result("bmm350_set_odr_performance", rslt); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + while (loop--) + { + rslt = bmm350_set_powermode(BMM350_FORCED_MODE, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + rslt = bmm350_get_compensated_mag_xyz_temp_data(&mag_temp_data, &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + mag_temp_data.temperature); + } + + printf("\nCOMBINATION 4 :\n"); + printf("Set forced mode fast and read data with averaging between 4 samples in a loop\n"); + + /* Set ODR and performance */ + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_100HZ, BMM350_AVERAGING_4, &dev); + bmm350_error_codes_print_result("bmm350_set_odr_performance", rslt); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + for (loop = 0; loop < MAG_SAMPLE_COUNT;) + { + rslt = bmm350_set_powermode(BMM350_FORCED_MODE_FAST, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + rslt = bmm350_get_compensated_mag_xyz_temp_data(&get_mag_temp_data[loop], &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + get_mag_temp_data[loop].x, + get_mag_temp_data[loop].y, + get_mag_temp_data[loop].z, + get_mag_temp_data[loop].temperature); + + mean_mag_data_1.x += get_mag_temp_data[loop].x; + mean_mag_data_1.y += get_mag_temp_data[loop].y; + mean_mag_data_1.z += get_mag_temp_data[loop].z; + + loop++; + } + + /* Taking average values to calculate percentage deviation */ + avg_mag_data.x = (double)(mean_mag_data_1.x / MAG_SAMPLE_COUNT); + avg_mag_data.y = (double)(mean_mag_data_1.y / MAG_SAMPLE_COUNT); + avg_mag_data.z = (double)(mean_mag_data_1.z / MAG_SAMPLE_COUNT); + + printf("***** AVERAGE MAG VALUE *****\n"); + printf("Average_Mag_X(uT), Average_Mag_Y(uT), Average_Mag_Z(uT)\n"); + + printf("%lf, %lf, %lf\n", avg_mag_data.x, avg_mag_data.y, avg_mag_data.z); + + calculate_noise(get_mag_temp_data, avg_mag_data); + + printf("\nCOMBINATION 5 :\n"); + printf("Set forced mode and read data with no averaging between samples in a loop\n"); + + /* Set ODR and performance */ + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_100HZ, BMM350_NO_AVERAGING, &dev); + bmm350_error_codes_print_result("bmm350_set_odr_performance", rslt); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + for (loop = 0; loop < MAG_SAMPLE_COUNT;) + { + rslt = bmm350_set_powermode(BMM350_FORCED_MODE, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + rslt = bmm350_get_compensated_mag_xyz_temp_data(&get_mag_temp_data[loop], &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + get_mag_temp_data[loop].x, + get_mag_temp_data[loop].y, + get_mag_temp_data[loop].z, + get_mag_temp_data[loop].temperature); + + mean_mag_data_2.x += get_mag_temp_data[loop].x; + mean_mag_data_2.y += get_mag_temp_data[loop].y; + mean_mag_data_2.z += get_mag_temp_data[loop].z; + + loop++; + } + + /* Taking average values to calculate percentage deviation */ + avg_mag_data.x = (double)(mean_mag_data_2.x / MAG_SAMPLE_COUNT); + avg_mag_data.y = (double)(mean_mag_data_2.y / MAG_SAMPLE_COUNT); + avg_mag_data.z = (double)(mean_mag_data_2.z / MAG_SAMPLE_COUNT); + + printf("***** AVERAGE MAG VALUE *****\n"); + printf("Average_Mag_X(uT), Average_Mag_Y(uT), Average_Mag_Z(uT)\n"); + + printf("%lf, %lf, %lf\n", avg_mag_data.x, avg_mag_data.y, avg_mag_data.z); + + calculate_noise(get_mag_temp_data, avg_mag_data); + + printf("\nCOMBINATION 6 :\n"); + printf("Set forced mode fast and read data with averaging between 2 samples in a loop\n"); + + /* Set ODR and performance */ + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_100HZ, BMM350_AVERAGING_2, &dev); + bmm350_error_codes_print_result("bmm350_set_odr_performance", rslt); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + for (loop = 0; loop < MAG_SAMPLE_COUNT;) + { + rslt = bmm350_set_powermode(BMM350_FORCED_MODE_FAST, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + rslt = bmm350_get_compensated_mag_xyz_temp_data(&get_mag_temp_data[loop], &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + get_mag_temp_data[loop].x, + get_mag_temp_data[loop].y, + get_mag_temp_data[loop].z, + get_mag_temp_data[loop].temperature); + + mean_mag_data_3.x += get_mag_temp_data[loop].x; + mean_mag_data_3.y += get_mag_temp_data[loop].y; + mean_mag_data_3.z += get_mag_temp_data[loop].z; + + loop++; + } + + /* Taking average values to calculate percentage deviation */ + avg_mag_data.x = (double)(mean_mag_data_3.x / MAG_SAMPLE_COUNT); + avg_mag_data.y = (double)(mean_mag_data_3.y / MAG_SAMPLE_COUNT); + avg_mag_data.z = (double)(mean_mag_data_3.z / MAG_SAMPLE_COUNT); + + printf("***** AVERAGE MAG VALUE *****\n"); + printf("Average_Mag_X(uT), Average_Mag_Y(uT), Average_Mag_Z(uT)\n"); + + printf("%lf, %lf, %lf\n", avg_mag_data.x, avg_mag_data.y, avg_mag_data.z); + + calculate_noise(get_mag_temp_data, avg_mag_data); + } + + bmm350_coines_deinit(); + + return rslt; +} + +/*! + * @brief This internal API is to calculate noise level for mag data. + */ +static void calculate_noise(const struct bmm350_mag_temp_data *mag_temp_data, struct bmm350_mag_data avg_mag_data) +{ + double variance_x = 0, variance_y = 0, variance_z = 0; + double noise_level_x, noise_level_y, noise_level_z; + uint8_t index = 0; + + for (index = 0; index < MAG_SAMPLE_COUNT; index++) + { + variance_x += ((mag_temp_data[index].x - avg_mag_data.x) * (mag_temp_data[index].x - avg_mag_data.x)); + + variance_y += ((mag_temp_data[index].y - avg_mag_data.y) * (mag_temp_data[index].y - avg_mag_data.y)); + + variance_z += ((mag_temp_data[index].z - avg_mag_data.z) * (mag_temp_data[index].z - avg_mag_data.z)); + } + + variance_x /= MAG_SAMPLE_COUNT; + noise_level_x = sqrt(variance_x) * 1000; + + variance_y /= MAG_SAMPLE_COUNT; + noise_level_y = sqrt(variance_y) * 1000; + + variance_z /= MAG_SAMPLE_COUNT; + noise_level_z = sqrt(variance_z) * 1000; + + printf("\nNoise level x (nTrms), Noise level y (nTrms), Noise level z (nTrms)\n"); + + printf("%lf, %lf, %lf\n", noise_level_x, noise_level_y, noise_level_z); +} diff --git a/examples/bmm350_illegal_command/Makefile b/examples/bmm350_illegal_command/Makefile new file mode 100644 index 0000000..b753cff --- /dev/null +++ b/examples/bmm350_illegal_command/Makefile @@ -0,0 +1,17 @@ +COINES_INSTALL_PATH ?= ../../../.. + +EXAMPLE_FILE ?= bmm350_illegal_command.c + +API_LOCATION ?= ../.. + +C_SRCS += \ +$(API_LOCATION)/bmm350.c \ +../common/common.c + +INCLUDEPATHS += \ +$(API_LOCATION) \ +../common + +COINES_BACKEND=COINES_BRIDGE + +include $(COINES_INSTALL_PATH)/coines.mk diff --git a/examples/bmm350_illegal_command/bmm350_illegal_command.c b/examples/bmm350_illegal_command/bmm350_illegal_command.c new file mode 100644 index 0000000..d262e88 --- /dev/null +++ b/examples/bmm350_illegal_command/bmm350_illegal_command.c @@ -0,0 +1,108 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bmm350_illegal_command.c +* +* @brief This file contains set get operations of illegal commands. +* +*/ + +#include +#include "bmm350.h" +#include "common.h" +#include "coines.h" + +/******************************************************************************/ +/*! Functions */ + +/* This function starts the execution of program */ +int main(void) +{ + /* Status of api are returned to this variable */ + int8_t rslt; + + /* Sensor initialization configuration */ + struct bmm350_dev dev = { 0 }; + + uint8_t pmu_cmd; + struct bmm350_pmu_cmd_status_0 pmu_cmd_stat_0; + + /* Update device structure */ + rslt = bmm350_interface_init(&dev); + bmm350_error_codes_print_result("bmm350_interface_selection", rslt); + + /* Initialize BMM350 */ + rslt = bmm350_init(&dev); + bmm350_error_codes_print_result("bmm350_init", rslt); + + printf("Read : 0x00 : BMM350 Chip ID : 0x%X\n", dev.chip_id); + + rslt = bmm350_set_powermode(BMM350_NORMAL_MODE, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + printf("Set legal PMU command to the register \n"); + + pmu_cmd = 2; + + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD, &pmu_cmd, 1, &dev); + bmm350_error_codes_print_result("bmm350_set_regs", rslt); + + printf("Write : 0x06 : PMU CMD : 0x%X\n", pmu_cmd); + + /* Check PMU cmd illegal */ + rslt = bmm350_get_pmu_cmd_status_0(&pmu_cmd_stat_0, &dev); + bmm350_error_codes_print_result("bmm350_get_pmu_cmd_status_0", rslt); + + printf("Read : 0x00 : PMU command illegal status : 0x%X\n", pmu_cmd_stat_0.cmd_is_illegal); + + rslt = bmm350_delay_us(40000, &dev); + bmm350_error_codes_print_result("bmm350_delay_us", rslt); + + printf("Set illegal PMU command to the register \n"); + + pmu_cmd = 12; + + rslt = bmm350_set_regs(BMM350_REG_PMU_CMD, &pmu_cmd, 1, &dev); + bmm350_error_codes_print_result("bmm350_set_regs", rslt); + + printf("Write : 0x06 : PMU CMD : 0x%X\n", pmu_cmd); + + /* Check PMU cmd illegal */ + rslt = bmm350_get_pmu_cmd_status_0(&pmu_cmd_stat_0, &dev); + bmm350_error_codes_print_result("bmm350_get_pmu_cmd_status_0", rslt); + + printf("Read : 0x00 : PMU command illegal status : 0x%X\n", pmu_cmd_stat_0.cmd_is_illegal); + + bmm350_coines_deinit(); + + return rslt; +} diff --git a/examples/bmm350_interrupt/Makefile b/examples/bmm350_interrupt/Makefile new file mode 100644 index 0000000..4abb5d0 --- /dev/null +++ b/examples/bmm350_interrupt/Makefile @@ -0,0 +1,17 @@ +COINES_INSTALL_PATH ?= ../../../.. + +EXAMPLE_FILE ?= bmm350_interrupt.c + +API_LOCATION ?= ../.. + +C_SRCS += \ +$(API_LOCATION)/bmm350.c \ +../common/common.c + +INCLUDEPATHS += \ +$(API_LOCATION) \ +../common + +TARGET = MCU_APP30 + +include $(COINES_INSTALL_PATH)/coines.mk diff --git a/examples/bmm350_interrupt/bmm350_interrupt.c b/examples/bmm350_interrupt/bmm350_interrupt.c new file mode 100644 index 0000000..9a34617 --- /dev/null +++ b/examples/bmm350_interrupt/bmm350_interrupt.c @@ -0,0 +1,256 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bmm350_interrupt.c +* +* @brief This file contains reading of magnetometer data in normal mode by hardware interrupt. +* +*/ + +#include +#include + +#include "bmm350.h" +#include "common.h" +#include "coines.h" + +/******************************************************************************/ +/*! Global variable Declaration */ + +volatile bool bmm3_int_recvd = false; + +/******************************************************************************/ +/*! Static Function Declaration */ + +/*! + * @brief This internal API is used to set the data ready interrupt status + * + * @return void + */ +static void bmm3_int_callback(uint32_t val1, uint32_t val2); + +/******************************************************************************/ +/*! Functions */ + +/*! + * @brief This internal API is used to set the data ready interrupt status + */ +static void bmm3_int_callback(uint32_t val1, uint32_t val2) +{ + (void)val1; + (void)val2; + bmm3_int_recvd = 1; +} + +/* This function starts the execution of program */ +int main(void) +{ + /* Status of api are returned to this variable */ + int8_t rslt; + + /* Sensor initialization configuration */ + struct bmm350_dev dev = { 0 }; + + uint8_t int_status, int_ctrl, err_reg_data = 0; + uint8_t loop = 20, set_int_ctrl; + uint32_t time_ms = 0; + + struct bmm350_mag_temp_data mag_temp_data; + struct bmm350_pmu_cmd_status_0 pmu_cmd_stat_0; + + /* Update device structure */ + rslt = bmm350_interface_init(&dev); + bmm350_error_codes_print_result("bmm350_interface_selection", rslt); + + /* Initialize BMM350 */ + rslt = bmm350_init(&dev); + bmm350_error_codes_print_result("bmm350_init", rslt); + + printf("Read : 0x00 : BMM350 Chip ID : 0x%X\n", dev.chip_id); + + /* Check PMU busy */ + rslt = bmm350_get_pmu_cmd_status_0(&pmu_cmd_stat_0, &dev); + bmm350_error_codes_print_result("bmm350_get_pmu_cmd_status_0", rslt); + + printf("Expected : 0x07 : PMU cmd busy : 0x0\n"); + printf("Read : 0x07 : PMU cmd busy : 0x%X\n", pmu_cmd_stat_0.pmu_cmd_busy); + + /* Get error data */ + rslt = bmm350_get_regs(BMM350_REG_ERR_REG, &err_reg_data, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_error_reg_data", rslt); + + printf("Expected : 0x02 : Error Register : 0x0\n"); + printf("Read : 0x02 : Error Register : 0x%X\n", err_reg_data); + + /* Configure interrupt settings */ + rslt = + bmm350_configure_interrupt(BMM350_PULSED, BMM350_ACTIVE_HIGH, BMM350_INTR_PUSH_PULL, BMM350_MAP_TO_PIN, &dev); + bmm350_error_codes_print_result("bmm350_configure_interrupt", rslt); + + /* Enable data ready interrupt */ + rslt = bmm350_enable_interrupt(BMM350_ENABLE_INTERRUPT, &dev); + bmm350_error_codes_print_result("bmm350_enable_interrupt", rslt); + + /* Get interrupt settings */ + rslt = bmm350_get_regs(BMM350_REG_INT_CTRL, &int_ctrl, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_regs", rslt); + + set_int_ctrl = + ((BMM350_INT_POL_ACTIVE_HIGH << 1) | (BMM350_INT_OD_PUSHPULL << 2) | (BMM350_ENABLE << 3) | BMM350_ENABLE << 7); + + printf("Expected : 0x2E : Interrupt control : 0x%X\n", set_int_ctrl); + printf("Read : 0x2E : Interrupt control : 0x%X\n", int_ctrl); + + if (int_ctrl & BMM350_DRDY_DATA_REG_EN_MSK) + { + printf("Data ready enabled\r\n"); + } + + /* Set ODR and performance */ + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_100HZ, BMM350_AVERAGING_4, &dev); + bmm350_error_codes_print_result("bmm350_set_odr_performance", rslt); + + rslt = bmm350_delay_us(10000, &dev); + bmm350_error_codes_print_result("bmm350_delay_us", rslt); + + /* Configure interrupt settings */ + rslt = bmm350_configure_interrupt(BMM350_PULSED, BMM350_ACTIVE_LOW, BMM350_INTR_PUSH_PULL, BMM350_MAP_TO_PIN, &dev); + bmm350_error_codes_print_result("bmm350_configure_interrupt", rslt); + + rslt = bmm350_delay_us(10000, &dev); + bmm350_error_codes_print_result("bmm350_delay_us", rslt); + + /* Configure interrupt settings */ + rslt = + bmm350_configure_interrupt(BMM350_LATCHED, BMM350_ACTIVE_LOW, BMM350_INTR_PUSH_PULL, BMM350_MAP_TO_PIN, &dev); + bmm350_error_codes_print_result("bmm350_configure_interrupt", rslt); + + rslt = bmm350_delay_us(10000, &dev); + bmm350_error_codes_print_result("bmm350_delay_us", rslt); + + /* Configure interrupt settings */ + rslt = + bmm350_configure_interrupt(BMM350_PULSED, BMM350_ACTIVE_HIGH, BMM350_INTR_PUSH_PULL, BMM350_MAP_TO_PIN, &dev); + bmm350_error_codes_print_result("bmm350_configure_interrupt", rslt); + + rslt = bmm350_delay_us(10000, &dev); + bmm350_error_codes_print_result("bmm350_delay_us", rslt); + + /* Enable all axis */ + rslt = bmm350_enable_axes(BMM350_X_EN, BMM350_Y_EN, BMM350_Z_EN, &dev); + bmm350_error_codes_print_result("bmm350_enable_axes", rslt); + + if (rslt == BMM350_OK) + { + rslt = bmm350_set_pad_drive(BMM350_PAD_DRIVE_STRONGEST, &dev); + bmm350_error_codes_print_result("bmm350_set_pad_drive", rslt); + + rslt = bmm350_set_powermode(BMM350_NORMAL_MODE, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + printf("\nPower mode is set to normal mode\n"); + printf("Compensated Magnetometer and temperature data with delay\n"); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + while (loop) + { + rslt = bmm350_delay_us(100000, &dev); + bmm350_error_codes_print_result("bmm350_delay_us", rslt); + + rslt = bmm350_get_compensated_mag_xyz_temp_data(&mag_temp_data, &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + mag_temp_data.temperature); + + loop--; + } + + /* Hardware interrupt configuration */ + coines_attach_interrupt(COINES_MINI_SHUTTLE_PIN_1_6, bmm3_int_callback, COINES_PIN_INTERRUPT_RISING_EDGE); + + printf("\nPower mode is set to normal mode\n"); + printf("Compensated Magnetometer and temperature data with hardware interrupt\n"); + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + loop = 0; + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + for (;;) + { + if (bmm3_int_recvd) + { + bmm3_int_recvd = 0; + int_status = 0; + + /* Get data ready interrupt status */ + rslt = bmm350_get_regs(BMM350_REG_INT_STATUS, &int_status, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_regs", rslt); + + /* Check if data ready interrupt occurred */ + if (int_status & BMM350_DRDY_DATA_REG_MSK) + { + rslt = bmm350_get_compensated_mag_xyz_temp_data(&mag_temp_data, &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + mag_temp_data.temperature); + + loop++; + + if (loop == 20) + { + break; + } + } + } + } + } + + bmm350_coines_deinit(); + + return rslt; +} diff --git a/examples/bmm350_magnetic_reset/Makefile b/examples/bmm350_magnetic_reset/Makefile new file mode 100644 index 0000000..0f2bea0 --- /dev/null +++ b/examples/bmm350_magnetic_reset/Makefile @@ -0,0 +1,17 @@ +COINES_INSTALL_PATH ?= ../../../.. + +EXAMPLE_FILE ?= bmm350_magnetic_reset.c + +API_LOCATION ?= ../.. + +C_SRCS += \ +$(API_LOCATION)/bmm350.c \ +../common/common.c + +INCLUDEPATHS += \ +$(API_LOCATION) \ +../common + +COINES_BACKEND=COINES_BRIDGE + +include $(COINES_INSTALL_PATH)/coines.mk diff --git a/examples/bmm350_magnetic_reset/bmm350_magnetic_reset.c b/examples/bmm350_magnetic_reset/bmm350_magnetic_reset.c new file mode 100644 index 0000000..108322e --- /dev/null +++ b/examples/bmm350_magnetic_reset/bmm350_magnetic_reset.c @@ -0,0 +1,258 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* +* @file bmm350_magnetic_reset.c +* +* @brief This file contains reading of magnetometer data before and after magnetic reset. +* +*/ + +#include +#include + +#include "bmm350.h" +#include "common.h" +#include "coines.h" + +/******************************************************************************/ +/*! Functions */ + +/* This function starts the execution of program */ +int main(void) +{ + /* Status of api are returned to this variable */ + int8_t rslt; + + /* Sensor initialization configuration */ + struct bmm350_dev dev = { 0 }; + + uint8_t int_status, int_ctrl, err_reg_data = 0; + uint8_t loop = 20, set_int_ctrl; + uint32_t time_ms = 0; + float magnitude = 0.0f; + + struct bmm350_mag_temp_data mag_temp_data = { 0 }; + struct bmm350_pmu_cmd_status_0 pmu_cmd_stat_0; + + /* Update device structure */ + rslt = bmm350_interface_init(&dev); + bmm350_error_codes_print_result("bmm350_interface_selection", rslt); + + /* Initialize BMM350 */ + rslt = bmm350_init(&dev); + bmm350_error_codes_print_result("bmm350_init", rslt); + + printf("Read : 0x00 : BMM350 Chip ID : 0x%X\n", dev.chip_id); + + /* Check PMU busy */ + rslt = bmm350_get_pmu_cmd_status_0(&pmu_cmd_stat_0, &dev); + bmm350_error_codes_print_result("bmm350_get_pmu_cmd_status_0", rslt); + + printf("Expected : 0x07 : PMU cmd busy : 0x0\n"); + printf("Read : 0x07 : PMU cmd busy : 0x%X\n", pmu_cmd_stat_0.pmu_cmd_busy); + + /* Get error data */ + rslt = bmm350_get_regs(BMM350_REG_ERR_REG, &err_reg_data, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_error_reg_data", rslt); + + printf("Expected : 0x02 : Error Register : 0x0\n"); + printf("Read : 0x02 : Error Register : 0x%X\n", err_reg_data); + + /* Configure interrupt settings */ + rslt = bmm350_configure_interrupt(BMM350_PULSED, + BMM350_ACTIVE_HIGH, + BMM350_INTR_PUSH_PULL, + BMM350_UNMAP_FROM_PIN, + &dev); + bmm350_error_codes_print_result("bmm350_configure_interrupt", rslt); + + /* Enable data ready interrupt */ + rslt = bmm350_enable_interrupt(BMM350_ENABLE_INTERRUPT, &dev); + bmm350_error_codes_print_result("bmm350_enable_interrupt", rslt); + + /* Get interrupt settings */ + rslt = bmm350_get_regs(BMM350_REG_INT_CTRL, &int_ctrl, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_regs", rslt); + + set_int_ctrl = ((BMM350_INT_POL_ACTIVE_HIGH << 1) | (BMM350_INT_OD_PUSHPULL << 2) | BMM350_ENABLE << 7); + + printf("Expected : 0x2E : Interrupt control : 0x%X\n", set_int_ctrl); + printf("Read : 0x2E : Interrupt control : 0x%X\n", int_ctrl); + + if (int_ctrl & BMM350_DRDY_DATA_REG_EN_MSK) + { + printf("Data ready enabled\r\n"); + } + + /* Set ODR and performance */ + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_100HZ, BMM350_AVERAGING_4, &dev); + bmm350_error_codes_print_result("bmm350_set_odr_performance", rslt); + + /* Enable all axis */ + rslt = bmm350_enable_axes(BMM350_X_EN, BMM350_Y_EN, BMM350_Z_EN, &dev); + bmm350_error_codes_print_result("bmm350_enable_axes", rslt); + + if (rslt == BMM350_OK) + { + rslt = bmm350_set_powermode(BMM350_NORMAL_MODE, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + printf("\nCompensated Magnetometer and temperature data in NORMAL MODE\n"); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + while (loop) + { + int_status = 0; + + /* Get data ready interrupt status */ + rslt = bmm350_get_regs(BMM350_REG_INT_STATUS, &int_status, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_regs", rslt); + + /* Check if data ready interrupt occurred */ + if (int_status & BMM350_DRDY_DATA_REG_MSK) + { + rslt = bmm350_get_compensated_mag_xyz_temp_data(&mag_temp_data, &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + mag_temp_data.temperature); + + loop--; + } + } + + rslt = bmm350_set_powermode(BMM350_SUSPEND_MODE, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + rslt = bmm350_magnetic_reset_and_wait(&dev); + bmm350_error_codes_print_result("bmm350_magnetic_reset_and_wait", rslt); + + rslt = bmm350_set_powermode(BMM350_NORMAL_MODE, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + printf("\nCompensated Magnetometer and temperature data\n"); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + loop = 20; + + while (loop) + { + int_status = 0; + + /* Get data ready interrupt status */ + rslt = bmm350_get_regs(BMM350_REG_INT_STATUS, &int_status, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_regs", rslt); + + /* Check if data ready interrupt occurred */ + if (int_status & BMM350_DRDY_DATA_REG_MSK) + { + rslt = bmm350_get_compensated_mag_xyz_temp_data(&mag_temp_data, &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + mag_temp_data.temperature); + + loop--; + } + } + + magnitude = + sqrtf((mag_temp_data.x * mag_temp_data.x) + (mag_temp_data.y * mag_temp_data.y) + + (mag_temp_data.z * mag_temp_data.z)); + + printf("\nMagnitude before applying magnetic reset: %.2f\n\n", magnitude); + + rslt = bmm350_magnetic_reset_and_wait(&dev); + bmm350_error_codes_print_result("bmm350_magnetic_reset_and_wait", rslt); + + printf("\nCompensated Magnetometer and temperature data after mag reset\n"); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + loop = 20; + + while (loop) + { + int_status = 0; + + /* Get data ready interrupt status */ + rslt = bmm350_get_regs(BMM350_REG_INT_STATUS, &int_status, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_regs", rslt); + + /* Check if data ready interrupt occurred */ + if (int_status & BMM350_DRDY_DATA_REG_MSK) + { + rslt = bmm350_get_compensated_mag_xyz_temp_data(&mag_temp_data, &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + mag_temp_data.temperature); + + loop--; + } + } + + magnitude = + sqrtf((mag_temp_data.x * mag_temp_data.x) + (mag_temp_data.y * mag_temp_data.y) + + (mag_temp_data.z * mag_temp_data.z)); + + printf("\nMagnitude after applying magnetic reset: %.2f\n\n", magnitude); + } + + bmm350_coines_deinit(); + + return rslt; +} diff --git a/examples/bmm350_normal_mode/Makefile b/examples/bmm350_normal_mode/Makefile new file mode 100644 index 0000000..1babf21 --- /dev/null +++ b/examples/bmm350_normal_mode/Makefile @@ -0,0 +1,17 @@ +COINES_INSTALL_PATH ?= ../../../.. + +EXAMPLE_FILE ?= bmm350_normal_mode.c + +API_LOCATION ?= ../.. + +C_SRCS += \ +$(API_LOCATION)/bmm350.c \ +../common/common.c + +INCLUDEPATHS += \ +$(API_LOCATION) \ +../common + +COINES_BACKEND=COINES_BRIDGE + +include $(COINES_INSTALL_PATH)/coines.mk diff --git a/examples/bmm350_normal_mode/bmm350_normal_mode.c b/examples/bmm350_normal_mode/bmm350_normal_mode.c new file mode 100644 index 0000000..bcf7b83 --- /dev/null +++ b/examples/bmm350_normal_mode/bmm350_normal_mode.c @@ -0,0 +1,225 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bmm350_normal_mode.c +* +* @brief This file contains reading of magnetometer data in normal mode. +* +*/ + +#include +#include "bmm350.h" +#include "common.h" +#include "coines.h" + +/******************************************************************************/ +/*! Functions */ + +/* This function starts the execution of program */ +int main(void) +{ + /* Status of api are returned to this variable */ + int8_t rslt; + + /* Sensor initialization configuration */ + struct bmm350_dev dev = { 0 }; + + uint8_t int_status, int_ctrl, err_reg_data = 0; + uint8_t loop = 10, set_int_ctrl; + uint32_t secs, nano_secs = 0; + uint32_t time_ms = 0; + + struct bmm350_mag_temp_data mag_temp_data; + struct bmm350_raw_mag_data raw_data; + struct bmm350_pmu_cmd_status_0 pmu_cmd_stat_0; + + /* Update device structure */ + rslt = bmm350_interface_init(&dev); + bmm350_error_codes_print_result("bmm350_interface_selection", rslt); + + /* Initialize BMM350 */ + rslt = bmm350_init(&dev); + bmm350_error_codes_print_result("bmm350_init", rslt); + + printf("Read : 0x00 : BMM350 Chip ID : 0x%X\n", dev.chip_id); + + printf("-------------\nCoefficients\n-------------\n"); + printf("Magnetometer Offset:: X: %.2f, Y: %.2f, Z: %.2f\n", + dev.mag_comp.dut_offset_coef.offset_x, + dev.mag_comp.dut_offset_coef.offset_y, + dev.mag_comp.dut_offset_coef.offset_z); + printf("Temperature offset %.2f\n", dev.mag_comp.dut_offset_coef.t_offs); + printf("Magnetometer Sensitivity:: X: %.2f, Y: %.2f, Z: %.2f\n", + dev.mag_comp.dut_sensit_coef.sens_x, + dev.mag_comp.dut_sensit_coef.sens_y, + dev.mag_comp.dut_sensit_coef.sens_z); + printf("Temperature sensitivity %.2f\n", dev.mag_comp.dut_sensit_coef.t_sens); + printf("TCO:: X: %.2f, Y: %.2f, Z: %.2f\n", + dev.mag_comp.dut_tco.tco_x, + dev.mag_comp.dut_tco.tco_y, + dev.mag_comp.dut_tco.tco_z); + printf("TCS:: X: %.4f, Y: %.4f, Z: %.4f\n", + dev.mag_comp.dut_tcs.tcs_x, + dev.mag_comp.dut_tcs.tcs_y, + dev.mag_comp.dut_tcs.tcs_z); + printf("T0 %.2f\n", dev.mag_comp.dut_t0); + printf("Cross XY %f\n", dev.mag_comp.cross_axis.cross_x_y); + printf("Cross YX %f\n", dev.mag_comp.cross_axis.cross_y_x); + printf("Cross ZX %f\n", dev.mag_comp.cross_axis.cross_z_x); + printf("Cross ZY %f\n", dev.mag_comp.cross_axis.cross_z_y); + + /* Check PMU busy */ + rslt = bmm350_get_pmu_cmd_status_0(&pmu_cmd_stat_0, &dev); + bmm350_error_codes_print_result("bmm350_get_pmu_cmd_status_0", rslt); + + printf("Expected : 0x07 : PMU cmd busy : 0x0\n"); + printf("Read : 0x07 : PMU cmd busy : 0x%X\n", pmu_cmd_stat_0.pmu_cmd_busy); + + /* Get error data */ + rslt = bmm350_get_regs(BMM350_REG_ERR_REG, &err_reg_data, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_error_reg_data", rslt); + + printf("Expected : 0x02 : Error Register : 0x0\n"); + printf("Read : 0x02 : Error Register : 0x%X\n", err_reg_data); + + /* Configure interrupt settings */ + rslt = bmm350_configure_interrupt(BMM350_PULSED, + BMM350_ACTIVE_HIGH, + BMM350_INTR_PUSH_PULL, + BMM350_UNMAP_FROM_PIN, + &dev); + bmm350_error_codes_print_result("bmm350_configure_interrupt", rslt); + + /* Enable data ready interrupt */ + rslt = bmm350_enable_interrupt(BMM350_ENABLE_INTERRUPT, &dev); + bmm350_error_codes_print_result("bmm350_enable_interrupt", rslt); + + /* Get interrupt settings */ + rslt = bmm350_get_regs(BMM350_REG_INT_CTRL, &int_ctrl, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_regs", rslt); + + set_int_ctrl = ((BMM350_INT_POL_ACTIVE_HIGH << 1) | (BMM350_INT_OD_PUSHPULL << 2) | BMM350_ENABLE << 7); + + printf("Expected : 0x2E : Interrupt control : 0x%X\n", set_int_ctrl); + printf("Read : 0x2E : Interrupt control : 0x%X\n", int_ctrl); + + if (int_ctrl & BMM350_DRDY_DATA_REG_EN_MSK) + { + printf("Data ready enabled\n"); + } + + /* Set ODR and performance */ + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_100HZ, BMM350_AVERAGING_4, &dev); + bmm350_error_codes_print_result("bmm350_set_odr_performance", rslt); + + /* Enable all axis */ + rslt = bmm350_enable_axes(BMM350_X_EN, BMM350_Y_EN, BMM350_Z_EN, &dev); + bmm350_error_codes_print_result("bmm350_enable_axes", rslt); + + if (rslt == BMM350_OK) + { + rslt = bmm350_set_powermode(BMM350_NORMAL_MODE, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + printf("\nUncompensated magnetometer and temperature data\n"); + + printf("mag_x_raw, mag_y_raw, mag_z_raw, Temperature(raw), time(secs)\n"); + + while (loop > 0) + { + int_status = 0; + + /* Get data ready interrupt status */ + rslt = bmm350_get_regs(BMM350_REG_INT_STATUS, &int_status, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_regs", rslt); + + /* Check if data ready interrupt occurred */ + if (int_status & BMM350_DRDY_DATA_REG_MSK) + { + /* Get uncompensated mag data */ + rslt = bmm350_read_uncomp_mag_temp_data(&raw_data, &dev); + bmm350_error_codes_print_result("bmm350_read_uncomp_mag_data", rslt); + + rslt = bmm350_read_sensortime(&secs, &nano_secs, &dev); + bmm350_error_codes_print_result("bmm350_read_sensortime", rslt); + + printf("%ld, %ld, %ld, %ld, %lu.%09lu\n", + (long int)raw_data.raw_xdata, + (long int)raw_data.raw_ydata, + (long int)raw_data.raw_zdata, + (long int)raw_data.raw_data_t, + (long unsigned int)secs, + (long unsigned int)nano_secs); + + loop--; + } + } + + loop = 50; + + printf("\nCompensated magnetometer and temperature data\n"); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + while (loop) + { + int_status = 0; + + /* Get data ready interrupt status */ + rslt = bmm350_get_regs(BMM350_REG_INT_STATUS, &int_status, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_regs", rslt); + + /* Check if data ready interrupt occurred */ + if (int_status & BMM350_DRDY_DATA_REG_MSK) + { + rslt = bmm350_get_compensated_mag_xyz_temp_data(&mag_temp_data, &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + mag_temp_data.temperature); + + loop--; + } + } + } + + bmm350_coines_deinit(); + + return rslt; +} diff --git a/examples/bmm350_out_of_range_detect/Makefile b/examples/bmm350_out_of_range_detect/Makefile new file mode 100644 index 0000000..350d1b6 --- /dev/null +++ b/examples/bmm350_out_of_range_detect/Makefile @@ -0,0 +1,18 @@ +COINES_INSTALL_PATH ?= ../../../.. + +EXAMPLE_FILE ?= bmm350_out_of_range_detect.c + +API_LOCATION ?= ../.. + +C_SRCS += \ +$(API_LOCATION)/bmm350.c \ +$(API_LOCATION)/bmm350_oor.c \ +../common/common.c + +INCLUDEPATHS += \ +$(API_LOCATION) \ +../common + +TARGET = MCU_APP30 + +include $(COINES_INSTALL_PATH)/coines.mk \ No newline at end of file diff --git a/examples/bmm350_out_of_range_detect/bmm350_out_of_range_detect.c b/examples/bmm350_out_of_range_detect/bmm350_out_of_range_detect.c new file mode 100644 index 0000000..3795f52 --- /dev/null +++ b/examples/bmm350_out_of_range_detect/bmm350_out_of_range_detect.c @@ -0,0 +1,202 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bmm350_out_of_range_detect.c +* +* @brief This file contains an example to robustly detect if the sensor is out of range, even in presence +* of high-magnetic disturbances +* +*/ + +#include +#include +#include +#include +#include + +#include "bmm350.h" +#include "bmm350_oor.h" +#include "common.h" +#include "coines.h" + +/******************************************************************************/ +/*! Static Variable Declaration */ + +/* Flag to track when to trigger the magnetic reset */ +static bool trigger_magnetic_reset = false; + +/******************************************************************************/ +/*! Functions */ + +/* This function starts the execution of program */ +int main(void) +{ + /* Status of api are returned to this variable */ + int8_t rslt; + + /* Sensor initialization configuration */ + struct bmm350_dev dev = { 0 }; + + /* Structure instance of magnetometer and temperature data */ + struct bmm350_mag_temp_data mag_temp_data = { 0 }; + + /* Structure instance of self-test data */ + struct bmm350_self_test st_data = { 0 }; + + /* Structure instance of out of range detect */ + struct bmm350_oor_params oor = { 0 }; + + enum coines_pin_direction btn_dir = COINES_PIN_DIRECTION_IN; + enum coines_pin_value btn_value = COINES_PIN_VALUE_HIGH; + + bool out_of_range = false; + float field_str = 0.0f; + uint16_t delay_in_us; + + /* Variable to store last measurement time */ + uint32_t last_meas_time = 0; + + /* Update device structure */ + rslt = bmm350_interface_init(&dev); + bmm350_error_codes_print_result("bmm350_interface_selection", rslt); + + (void)coines_set_led(COINES_LED_RED, COINES_LED_STATE_OFF); + + /* Initialize BMM350 */ + rslt = bmm350_init(&dev); + bmm350_error_codes_print_result("bmm350_init", rslt); + + printf("Read : 0x00 : BMM350 Chip ID : 0x%X\n", dev.chip_id); + + /* Enable all axis */ + rslt = bmm350_enable_axes(BMM350_X_EN, BMM350_Y_EN, BMM350_Z_EN, &dev); + bmm350_error_codes_print_result("bmm350_enable_axes", rslt); + + rslt = bmm350_perform_self_test(&st_data, &dev); + bmm350_error_codes_print_result("bmm350_perform_self_test", rslt); + if ((st_data.out_ust_x < BMM350_FULL_ST_THRESHOLD) || (st_data.out_ust_y < BMM350_FULL_ST_THRESHOLD)) + { + out_of_range = true; + } + + /* Set ODR to 200hz for best performance */ + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_200HZ, BMM350_AVERAGING_2, &dev); + bmm350_error_codes_print_result("bmm350_set_odr_performance", rslt); + + rslt = bmm350_set_powermode(BMM350_FORCED_MODE_FAST, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + last_meas_time = coines_get_realtime_usec(); + + /* For 200Hz ODR, poll at 5ms */ + delay_in_us = 5000; + + printf("Measuring data from the sensor\n"); + printf( + "\nMx, My, Mz, field_str, OutOfRange, Xfailed, Yfailed, ST DX, ST DY, Reset, Reset counter, ST active, ST counter\n"); + + /* Read data indefinitely */ + while (rslt == BMM350_OK) + { + /* Read data when ready */ + if ((coines_get_realtime_usec() - last_meas_time) >= delay_in_us) + { + last_meas_time = coines_get_realtime_usec(); + + if (oor.trigger_reset) + { + rslt = bmm350_oor_perform_reset_sequence_forced(&oor, &dev); + } + else + { + rslt = bmm350_oor_read(&out_of_range, &mag_temp_data, &oor, &dev); + } + + /* Light up the LED Green or Red to indicate out of range */ + if (out_of_range) + { + (void)coines_set_led(COINES_LED_RED, COINES_LED_STATE_ON); + (void)coines_set_led(COINES_LED_GREEN, COINES_LED_STATE_OFF); + (void)coines_set_pin_config(COINES_MINI_SHUTTLE_PIN_1_4, COINES_PIN_DIRECTION_OUT, + COINES_PIN_VALUE_HIGH); + } + else + { + (void)coines_set_led(COINES_LED_RED, COINES_LED_STATE_OFF); + (void)coines_set_led(COINES_LED_GREEN, COINES_LED_STATE_ON); + (void)coines_set_pin_config(COINES_MINI_SHUTTLE_PIN_1_4, COINES_PIN_DIRECTION_OUT, + COINES_PIN_VALUE_LOW); + } + + field_str = + sqrtf((mag_temp_data.x * mag_temp_data.x) + (mag_temp_data.y * mag_temp_data.y) + + (mag_temp_data.z * mag_temp_data.z)); + + printf("%.2f\t%.2f\t%.2f\t%.2f\t%d\t%u\t%u\t%.2f\t%.2f\t%u\t%u\t%u\t%u\n", + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + field_str, + (uint8_t)out_of_range, + oor.x_failed, + oor.y_failed, + oor.mag_xp - oor.mag_xn, + oor.mag_yp - oor.mag_yn, + oor.trigger_reset, + oor.reset_counter, + oor.enable_selftest, + oor.st_counter); + } + + /* Press the Button 1 to manually trigger a magnetic reset */ + btn_dir = COINES_PIN_DIRECTION_IN; /* Input */ + btn_value = COINES_PIN_VALUE_HIGH; /* Pull-up */ + + (void)coines_get_pin_config(COINES_APP30_BUTTON_1, &btn_dir, &btn_value); + + if ((btn_value == COINES_PIN_VALUE_LOW) || (out_of_range)) + { + trigger_magnetic_reset = true; + } + + /* Trigger the magnetic reset once the self tests have passed and the button is not pressed (active-low) */ + if (trigger_magnetic_reset && !out_of_range && (btn_value == COINES_PIN_VALUE_HIGH)) + { + oor.trigger_reset = true; + trigger_magnetic_reset = false; + } + } + + bmm350_coines_deinit(); + + return rslt; +} diff --git a/examples/bmm350_polling/Makefile b/examples/bmm350_polling/Makefile new file mode 100644 index 0000000..64b9b8a --- /dev/null +++ b/examples/bmm350_polling/Makefile @@ -0,0 +1,17 @@ +COINES_INSTALL_PATH ?= ../../../.. + +EXAMPLE_FILE ?= bmm350_polling.c + +API_LOCATION ?= ../.. + +C_SRCS += \ +$(API_LOCATION)/bmm350.c \ +../common/common.c + +INCLUDEPATHS += \ +$(API_LOCATION) \ +../common + +COINES_BACKEND=COINES_BRIDGE + +include $(COINES_INSTALL_PATH)/coines.mk diff --git a/examples/bmm350_polling/bmm350_polling.c b/examples/bmm350_polling/bmm350_polling.c new file mode 100644 index 0000000..7870f86 --- /dev/null +++ b/examples/bmm350_polling/bmm350_polling.c @@ -0,0 +1,191 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bmm350_polling.c +* +* @brief This file contains reading of magnetometer data in normal mode by polling method. +* +*/ + +#include +#include "bmm350.h" +#include "common.h" +#include "coines.h" + +/******************************************************************************/ +/*! Functions */ + +/* This function starts the execution of program */ +int main(void) +{ + /* Status of api are returned to this variable */ + int8_t rslt; + + /* Sensor initialization configuration */ + struct bmm350_dev dev = { 0 }; + + uint8_t int_status, int_ctrl, err_reg_data = 0; + uint8_t loop, set_int_ctrl; + uint32_t time_ms = 0; + + struct bmm350_mag_temp_data mag_temp_data; + struct bmm350_pmu_cmd_status_0 pmu_cmd_stat_0; + + /* Update device structure */ + rslt = bmm350_interface_init(&dev); + bmm350_error_codes_print_result("bmm350_interface_selection", rslt); + + /* Initialize BMM350 */ + rslt = bmm350_init(&dev); + bmm350_error_codes_print_result("bmm350_init", rslt); + + printf("Read : 0x00 : BMM350 Chip ID : 0x%X\n", dev.chip_id); + + /* Check PMU busy */ + rslt = bmm350_get_pmu_cmd_status_0(&pmu_cmd_stat_0, &dev); + bmm350_error_codes_print_result("bmm350_get_pmu_cmd_status_0", rslt); + + printf("Expected : 0x07 : PMU cmd busy : 0x0\n"); + printf("Read : 0x07 : PMU cmd busy : 0x%X\n", pmu_cmd_stat_0.pmu_cmd_busy); + + /* Get error data */ + rslt = bmm350_get_regs(BMM350_REG_ERR_REG, &err_reg_data, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_error_reg_data", rslt); + + printf("Expected : 0x02 : Error Register : 0x0\n"); + printf("Read : 0x02 : Error Register : 0x%X\n", err_reg_data); + + /* Configure interrupt settings */ + rslt = bmm350_configure_interrupt(BMM350_PULSED, + BMM350_ACTIVE_HIGH, + BMM350_INTR_PUSH_PULL, + BMM350_UNMAP_FROM_PIN, + &dev); + bmm350_error_codes_print_result("bmm350_configure_interrupt", rslt); + + /* Enable data ready interrupt */ + rslt = bmm350_enable_interrupt(BMM350_ENABLE_INTERRUPT, &dev); + bmm350_error_codes_print_result("bmm350_enable_interrupt", rslt); + + /* Get interrupt settings */ + rslt = bmm350_get_regs(BMM350_REG_INT_CTRL, &int_ctrl, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_regs", rslt); + + set_int_ctrl = (BMM350_INT_POL_ACTIVE_HIGH << 1) | (BMM350_INT_OD_PUSHPULL << 2) | (BMM350_ENABLE << 7); + + printf("Expected : 0x2E : Interrupt control : 0x%X\n", set_int_ctrl); + printf("Read : 0x2E : Interrupt control : 0x%X\n", int_ctrl); + + if (int_ctrl & BMM350_DRDY_DATA_REG_EN_MSK) + { + printf("Data ready enabled\r\n"); + } + + /* Set ODR and performance */ + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_25HZ, BMM350_AVERAGING_8, &dev); + bmm350_error_codes_print_result("bmm350_set_odr_performance", rslt); + + /* Enable all axis */ + rslt = bmm350_enable_axes(BMM350_X_EN, BMM350_Y_EN, BMM350_Z_EN, &dev); + bmm350_error_codes_print_result("bmm350_enable_axes", rslt); + + if (rslt == BMM350_OK) + { + rslt = bmm350_set_powermode(BMM350_NORMAL_MODE, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + loop = 20; + + printf("\nCompensated Magnetometer and temperature data read with delay\n"); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + while (loop) + { + rslt = bmm350_delay_us(36000, &dev); + bmm350_error_codes_print_result("bmm350_delay_us", rslt); + + rslt = bmm350_get_compensated_mag_xyz_temp_data(&mag_temp_data, &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + mag_temp_data.temperature); + + loop--; + } + + loop = 22; + + printf("\nCompensated Magnetometer and temperature data read with INT\n"); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + while (loop) + { + int_status = 0; + + /* Get data ready interrupt status */ + rslt = bmm350_get_regs(BMM350_REG_INT_STATUS, &int_status, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_regs", rslt); + + /* Check if data ready interrupt occurred */ + if (int_status & BMM350_DRDY_DATA_REG_MSK) + { + rslt = bmm350_get_compensated_mag_xyz_temp_data(&mag_temp_data, &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + mag_temp_data.temperature); + + loop--; + } + } + } + + bmm350_coines_deinit(); + + return rslt; +} diff --git a/examples/bmm350_self_test/Makefile b/examples/bmm350_self_test/Makefile new file mode 100644 index 0000000..2dcc97d --- /dev/null +++ b/examples/bmm350_self_test/Makefile @@ -0,0 +1,17 @@ +COINES_INSTALL_PATH ?= ../../../.. + +EXAMPLE_FILE ?= bmm350_self_test.c + +API_LOCATION ?= ../.. + +C_SRCS += \ +$(API_LOCATION)/bmm350.c \ +../common/common.c + +INCLUDEPATHS += \ +$(API_LOCATION) \ +../common + +COINES_BACKEND=COINES_BRIDGE + +include $(COINES_INSTALL_PATH)/coines.mk diff --git a/examples/bmm350_self_test/bmm350_self_test.c b/examples/bmm350_self_test/bmm350_self_test.c new file mode 100644 index 0000000..7a23ec2 --- /dev/null +++ b/examples/bmm350_self_test/bmm350_self_test.c @@ -0,0 +1,218 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bmm350_self_test.c +* +* @brief This file contains reading of magnetometer data in normal mode by performing before and after self-test. +*/ + +#include +#include "coines.h" +#include "common.h" +#include "bmm350.h" + +/******************************************************************************/ +/*! Functions */ + +/* This function starts the execution of program */ +int main(void) +{ + /* Status of api are returned to this variable */ + int8_t rslt; + + /* Sensor initialization configuration */ + struct bmm350_dev dev = { 0 }; + + struct bmm350_self_test out_data; + + uint8_t err_reg_data = 0; + uint8_t loop = 10; + uint32_t time_ms = 0; + + struct bmm350_mag_temp_data mag_temp_data; + struct bmm350_pmu_cmd_status_0 pmu_cmd_stat_0; + + /* Update device structure */ + rslt = bmm350_interface_init(&dev); + bmm350_error_codes_print_result("bmm350_interface_selection", rslt); + + /* Initialize BMM350 */ + rslt = bmm350_init(&dev); + bmm350_error_codes_print_result("bmm350_init", rslt); + + printf("Read : 0x00 : BMM350 Chip ID : 0x%X\n", dev.chip_id); + + /* Check PMU busy */ + rslt = bmm350_get_pmu_cmd_status_0(&pmu_cmd_stat_0, &dev); + bmm350_error_codes_print_result("bmm350_get_pmu_cmd_status_0", rslt); + + printf("Expected : 0x07 : PMU cmd busy : 0x0\n"); + printf("Read : 0x07 : PMU cmd busy : 0x%X\n", pmu_cmd_stat_0.pmu_cmd_busy); + + /* Get error data */ + rslt = bmm350_get_regs(BMM350_REG_ERR_REG, &err_reg_data, 1, &dev); + bmm350_error_codes_print_result("bmm350_get_error_reg_data", rslt); + + printf("Expected : 0x02 : Error Register : 0x0\n"); + printf("Read : 0x02 : Error Register : 0x%X\n", err_reg_data); + + /* Set ODR and performance */ + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_100HZ, BMM350_AVERAGING_4, &dev); + bmm350_error_codes_print_result("bmm350_set_odr_performance", rslt); + + rslt = bmm350_set_powermode(BMM350_NORMAL_MODE, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + rslt = bmm350_delay_us(10000, &dev); + bmm350_error_codes_print_result("bmm350_delay_us", rslt); + + /* Enable all axis */ + rslt = bmm350_enable_axes(BMM350_X_EN, BMM350_Y_EN, BMM350_Z_EN, &dev); + bmm350_error_codes_print_result("bmm350_enable_axes", rslt); + + if (rslt == BMM350_OK) + { + printf("\n**********BEFORE SELFTEST**********\n"); + + printf("\nPower mode is set to normal mode\n"); + + printf("\nCompensated Magnetometer and temperature data with delay\n"); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + while (loop) + { + rslt = bmm350_delay_us(100000, &dev); + bmm350_error_codes_print_result("bmm350_delay_us", rslt); + + rslt = bmm350_get_compensated_mag_xyz_temp_data(&mag_temp_data, &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + mag_temp_data.temperature); + + loop--; + } + + printf("\nSelf-test data in suspend mode\n"); + + printf("\nIteration, OUT_UST_X, OUT_UST_Y\n"); + + while (loop < 20) + { + rslt = bmm350_perform_self_test(&out_data, &dev); + bmm350_error_codes_print_result("bmm350_perform_self_test", rslt); + + printf("%d, %f, %f\n", loop, out_data.out_ust_x, out_data.out_ust_y); + + loop++; + } + + printf("\n**********AFTER SELFTEST**********\n"); + + loop = 20; + + printf("\nCompensated Magnetometer and temperature data\n"); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + while (loop) + { + rslt = bmm350_delay_us(10000, &dev); + bmm350_error_codes_print_result("bmm350_delay_us", rslt); + + rslt = bmm350_get_compensated_mag_xyz_temp_data(&mag_temp_data, &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + mag_temp_data.temperature); + + loop--; + } + + printf("\nSelf-test data in normal mode\n"); + + rslt = bmm350_perform_self_test(&out_data, &dev); + bmm350_error_codes_print_result("bmm350_perform_self_test", rslt); + + printf("Self-test data\n"); + + printf("\nOUT_UST_X, OUT_UST_Y\n"); + + printf("%f, %f\n", out_data.out_ust_x, out_data.out_ust_y); + + loop = 20; + + printf("\nCompensated Magnetometer and temperature data\n"); + + printf("Timestamp(ms), Mag_X(uT), Mag_Y(uT), Mag_Z(uT), Temperature(degC)\n"); + + /* Time in milliseconds */ + time_ms = coines_get_millis(); + + while (loop) + { + rslt = bmm350_delay_us(10000, &dev); + bmm350_error_codes_print_result("bmm350_delay_us", rslt); + + rslt = bmm350_get_compensated_mag_xyz_temp_data(&mag_temp_data, &dev); + bmm350_error_codes_print_result("bmm350_get_compensated_mag_xyz_temp_data", rslt); + + printf("%lu, %f, %f, %f, %f\n", + (long unsigned int)(coines_get_millis() - time_ms), + mag_temp_data.x, + mag_temp_data.y, + mag_temp_data.z, + mag_temp_data.temperature); + + loop--; + } + } + + bmm350_coines_deinit(); + + return rslt; +} diff --git a/examples/bmm350_sensor_time/Makefile b/examples/bmm350_sensor_time/Makefile new file mode 100644 index 0000000..fff1abf --- /dev/null +++ b/examples/bmm350_sensor_time/Makefile @@ -0,0 +1,17 @@ +COINES_INSTALL_PATH ?= ../../../.. + +EXAMPLE_FILE ?= bmm350_sensor_time.c + +API_LOCATION ?= ../.. + +C_SRCS += \ +$(API_LOCATION)/bmm350.c \ +../common/common.c + +INCLUDEPATHS += \ +$(API_LOCATION) \ +../common + +COINES_BACKEND=COINES_BRIDGE + +include $(COINES_INSTALL_PATH)/coines.mk diff --git a/examples/bmm350_sensor_time/bmm350_sensor_time.c b/examples/bmm350_sensor_time/bmm350_sensor_time.c new file mode 100644 index 0000000..a58a78b --- /dev/null +++ b/examples/bmm350_sensor_time/bmm350_sensor_time.c @@ -0,0 +1,160 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bmm350_sensor_time.c +* +* @brief This file contains reading of sensortime data with respect to power modes, ODR and average. +* +*/ + +#include +#include "bmm350.h" +#include "common.h" +#include "coines.h" + +/******************************************************************************/ +/*! Functions */ + +/* This function starts the execution of program */ +int main(void) +{ + /* Status of api are returned to this variable */ + int8_t rslt; + + /* Sensor initialization configuration */ + struct bmm350_dev dev = { 0 }; + + uint8_t loop = 20; + uint32_t secs, nano_secs = 0; + + /* Update device structure */ + rslt = bmm350_interface_init(&dev); + bmm350_error_codes_print_result("bmm350_interface_selection", rslt); + + /* Initialize BMM350 */ + rslt = bmm350_init(&dev); + bmm350_error_codes_print_result("bmm350_init", rslt); + + printf("Read : 0x00 : BMM350 Chip ID : 0x%X\n", dev.chip_id); + + /* Set ODR and performance */ + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_100HZ, BMM350_AVERAGING_4, &dev); + bmm350_error_codes_print_result("bmm350_set_odr_performance", rslt); + + /* Enable all axis */ + rslt = bmm350_enable_axes(BMM350_X_EN, BMM350_Y_EN, BMM350_Z_EN, &dev); + bmm350_error_codes_print_result("bmm350_enable_axes", rslt); + + if (rslt == BMM350_OK) + { + rslt = bmm350_set_powermode(BMM350_SUSPEND_MODE, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + printf("\nSensortime in suspend mode\n"); + printf("Time(secs)\n"); + + while (loop > 0) + { + rslt = bmm350_read_sensortime(&secs, &nano_secs, &dev); + bmm350_error_codes_print_result("bmm350_read_sensortime", rslt); + + printf("%lu.%09lu\n", (long unsigned int)secs, (long unsigned int)nano_secs); + + loop--; + } + + rslt = bmm350_set_ctrl_user(BMM350_CFG_SENS_TIM_AON_EN, &dev); + bmm350_error_codes_print_result("bmm350_set_ctrl_user", rslt); + + loop = 20; + + printf("\nSensortime in forced mode\n"); + + printf("Time(secs)\n"); + + while (loop > 0) + { + rslt = bmm350_set_powermode(BMM350_FORCED_MODE, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + rslt = bmm350_delay_us(40000, &dev); + bmm350_error_codes_print_result("bmm350_delay_us", rslt); + + rslt = bmm350_read_sensortime(&secs, &nano_secs, &dev); + bmm350_error_codes_print_result("bmm350_read_sensortime", rslt); + + printf("\n%lu.%09lu\n", (long unsigned int)secs, (long unsigned int)nano_secs); + + rslt = bmm350_read_sensortime(&secs, &nano_secs, &dev); + bmm350_error_codes_print_result("bmm350_read_sensortime", rslt); + + printf("%lu.%09lu\n", (long unsigned int)secs, (long unsigned int)nano_secs); + + rslt = bmm350_read_sensortime(&secs, &nano_secs, &dev); + bmm350_error_codes_print_result("bmm350_read_sensortime", rslt); + + printf("%lu.%09lu\n", (long unsigned int)secs, (long unsigned int)nano_secs); + + loop--; + } + + rslt = bmm350_set_powermode(BMM350_NORMAL_MODE, &dev); + bmm350_error_codes_print_result("bmm350_set_powermode", rslt); + + /* Set ODR and performance */ + rslt = bmm350_set_odr_performance(BMM350_DATA_RATE_100HZ, BMM350_AVERAGING_2, &dev); + bmm350_error_codes_print_result("bmm350_set_odr_performance", rslt); + + loop = 20; + + printf("\nChange in ODR\n"); + + printf("Time(secs)\n"); + + while (loop > 0) + { + rslt = bmm350_delay_us(11000, &dev); + bmm350_error_codes_print_result("bmm350_delay_us", rslt); + + rslt = bmm350_read_sensortime(&secs, &nano_secs, &dev); + bmm350_error_codes_print_result("bmm350_read_sensortime", rslt); + + printf("%lu.%09lu\n", (long unsigned int)secs, (long unsigned int)nano_secs); + + loop--; + } + } + + bmm350_coines_deinit(); + + return rslt; +} diff --git a/examples/common/common.c b/examples/common/common.c new file mode 100644 index 0000000..c77c66e --- /dev/null +++ b/examples/common/common.c @@ -0,0 +1,235 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file common.c +* +*/ + +#include +#include +#include + +#include "coines.h" +#include "bmm350.h" +#include "common.h" + +/******************************************************************************/ +/*! Structure definition */ + +#define BMM350_SHUTTLE_ID UINT16_C(0x27) + +/******************************************************************************/ +/*! Static variable definition */ + +/*! Variable that holds the I2C device address selection */ +static uint8_t dev_addr; + +/*! Variable to store coines I2C bus selection */ +static enum coines_i2c_bus i2c_bus; + +/******************************************************************************/ +/*! User interface functions */ + +/*! + * I2C read function map to COINES platform + */ +BMM350_INTF_RET_TYPE bmm350_i2c_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, void *intf_ptr) +{ + uint8_t device_addr = *(uint8_t*)intf_ptr; + + (void)intf_ptr; + + return coines_read_i2c(i2c_bus, device_addr, reg_addr, reg_data, (uint16_t)length); +} + +/*! + * I2C write function map to COINES platform + */ +BMM350_INTF_RET_TYPE bmm350_i2c_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length, void *intf_ptr) +{ + uint8_t device_addr = *(uint8_t*)intf_ptr; + + (void)intf_ptr; + + return coines_write_i2c(i2c_bus, device_addr, reg_addr, (uint8_t *)reg_data, (uint16_t)length); +} + +/*! + * Delay function map to COINES platform + */ +void bmm350_delay(uint32_t period, void *intf_ptr) +{ + (void)intf_ptr; + +#if defined(MCU_APP30) + coines_delay_realtime_usec(period); +#else + coines_delay_usec(period); +#endif +} + +/*! + * @brief Prints the execution status of the APIs. + */ +void bmm350_error_codes_print_result(const char api_name[], int8_t rslt) +{ + switch (rslt) + { + case BMM350_OK: + break; + + case BMM350_E_NULL_PTR: + printf("%s Error [%d] : Null pointer\r\n", api_name, rslt); + break; + case BMM350_E_COM_FAIL: + printf("%s Error [%d] : Communication fail\r\n", api_name, rslt); + break; + case BMM350_E_DEV_NOT_FOUND: + printf("%s Error [%d] : Device not found\r\n", api_name, rslt); + break; + case BMM350_E_INVALID_CONFIG: + printf("%s Error [%d] : Invalid configuration\r\n", api_name, rslt); + break; + case BMM350_E_BAD_PAD_DRIVE: + printf("%s Error [%d] : Bad pad drive\r\n", api_name, rslt); + break; + case BMM350_E_RESET_UNFINISHED: + printf("%s Error [%d] : Reset unfinished\r\n", api_name, rslt); + break; + case BMM350_E_INVALID_INPUT: + printf("%s Error [%d] : Invalid input\r\n", api_name, rslt); + break; + case BMM350_E_SELF_TEST_INVALID_AXIS: + printf("%s Error [%d] : Self-test invalid axis selection\r\n", api_name, rslt); + break; + case BMM350_E_OTP_BOOT: + printf("%s Error [%d] : OTP boot\r\n", api_name, rslt); + break; + case BMM350_E_OTP_PAGE_RD: + printf("%s Error [%d] : OTP page read\r\n", api_name, rslt); + break; + case BMM350_E_OTP_PAGE_PRG: + printf("%s Error [%d] : OTP page prog\r\n", api_name, rslt); + break; + case BMM350_E_OTP_SIGN: + printf("%s Error [%d] : OTP sign\r\n", api_name, rslt); + break; + case BMM350_E_OTP_INV_CMD: + printf("%s Error [%d] : OTP invalid command\r\n", api_name, rslt); + break; + case BMM350_E_OTP_UNDEFINED: + printf("%s Error [%d] : OTP undefined\r\n", api_name, rslt); + break; + case BMM350_E_ALL_AXIS_DISABLED: + printf("%s Error [%d] : All axis are disabled\r\n", api_name, rslt); + break; + case BMM350_E_PMU_CMD_VALUE: + printf("%s Error [%d] : Unexpected PMU CMD value\r\n", api_name, rslt); + break; + default: + printf("%s Error [%d] : Unknown error code\r\n", api_name, rslt); + break; + } +} + +/*! + * @brief Function to select the interface. + */ +int8_t bmm350_interface_init(struct bmm350_dev *dev) +{ + int8_t rslt = BMM350_OK; + struct coines_board_info board_info; + + if (dev != NULL) + { + int16_t result = coines_open_comm_intf(COINES_COMM_INTF_USB, NULL); + if (result < COINES_SUCCESS) + { + printf( + "\n Unable to connect with Application Board ! \n" " 1. Check if the board is connected and powered on. \n" " 2. Check if Application Board USB driver is installed. \n" + " 3. Check if board is in use by another application. (Insufficient permissions to access USB) \n"); + exit(result); + } + + (void)coines_get_board_info(&board_info); + + if (board_info.shuttle_id == BMM350_SHUTTLE_ID) + { + i2c_bus = COINES_I2C_BUS_0; + } + else + { + i2c_bus = COINES_I2C_BUS_1; + } + + dev_addr = BMM350_I2C_ADSEL_SET_LOW; + dev->intf_ptr = &dev_addr; + dev->read = bmm350_i2c_read; + dev->write = bmm350_i2c_write; + dev->delay_us = bmm350_delay; + +#if !defined(MCU_APP20) + (void)coines_set_pin_config(COINES_MINI_SHUTTLE_PIN_1_4, COINES_PIN_DIRECTION_OUT, COINES_PIN_VALUE_LOW); +#endif + + (void)coines_config_i2c_bus(i2c_bus, COINES_I2C_STANDARD_MODE); + + (void)coines_set_shuttleboard_vdd_vddio_config(0, 0); + + coines_delay_msec(100); + + (void)coines_set_shuttleboard_vdd_vddio_config(1800, 1800); + + coines_delay_msec(100); + } + else + { + rslt = BMM350_E_NULL_PTR; + } + + return rslt; +} + +void bmm350_coines_deinit(void) +{ + (void)fflush(stdout); + + (void)coines_set_shuttleboard_vdd_vddio_config(0, 0); + + coines_delay_msec(2000); + + coines_soft_reset(); + + coines_delay_msec(100); + + (void)coines_close_comm_intf(COINES_COMM_INTF_USB, NULL); +} diff --git a/examples/common/common.h b/examples/common/common.h new file mode 100644 index 0000000..ba4ed70 --- /dev/null +++ b/examples/common/common.h @@ -0,0 +1,132 @@ +/** +* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file common.h +* +*/ + +#ifndef _COMMON_H +#define _COMMON_H + +/*! CPP guard */ +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "bmm350.h" + +/***************************************************************************/ + +/*! User function prototypes + ****************************************************************************/ + +/*! + * @brief Function for reading the sensor's registers through I2C bus. + * + * @param[in] reg_addr : Register address from which data is read. + * @param[out] reg_data : Pointer to data buffer where read data is stored. + * @param[in] length : Number of bytes of data to be read. + * @param[in, out] intf_ptr : Void pointer that can enable the linking of descriptors + * for interface related call backs. + * + * @return Status of execution + * + * @retval BMM350_INTF_RET_SUCCESS -> Success. + * @retval != BMM350_INTF_RET_SUCCESS -> Fail. + * + */ +BMM350_INTF_RET_TYPE bmm350_i2c_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, void *intf_ptr); + +/*! + * @brief Function for writing the sensor's registers through I2C bus. + * + * @param[in] reg_addr : Register address to which the data is written. + * @param[in] reg_data : Pointer to data buffer in which data to be written + * is stored. + * @param[in] length : Number of bytes of data to be written. + * @param[in, out] intf_ptr : Void pointer that can enable the linking of descriptors + * for interface related call backs + * + * @return Status of execution + * + * @retval BMM350_INTF_RET_SUCCESS -> Success. + * @retval != BMM350_INTF_RET_SUCCESS -> Failure. + * + */ +BMM350_INTF_RET_TYPE bmm350_i2c_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length, void *intf_ptr); + +/*! + * @brief This function provides the delay for required time (Microsecond) as per the input provided in some of the + * APIs. + * + * @param[in] period_us : The required wait time in microsecond. + * @return void. + * + */ +void bmm350_delay(uint32_t period_us, void *intf_ptr); + +/*! + * @brief Function to select the interface. + * Also to initialize coines platform. + * + * @param[in] dev : Structure instance of bmm350_dev + * + * @return Status of execution + * @retval 0 -> Success + * @retval < 0 -> Failure Info + */ +int8_t bmm350_interface_init(struct bmm350_dev *dev); + +/*! + * @brief Prints the execution status of the APIs. + * + * @param[in] api_name : Name of the API whose execution status has to be printed. + * @param[in] rslt : Error code returned by the API whose execution status has to be printed. + * + * @return void. + */ +void bmm350_error_codes_print_result(const char api_name[], int8_t rslt); + +/*! + * @brief This function deinitializes coines platform + * + * @return void. + * + */ +void bmm350_coines_deinit(void); + +#ifdef __cplusplus +} +#endif /* End of CPP guard */ + +#endif /* _COMMON_H */