From 8f6f6b351fa2fad09076f6c526655c8691c03676 Mon Sep 17 00:00:00 2001 From: Daniel Nakhooda Date: Sun, 28 Sep 2025 11:21:02 -0400 Subject: [PATCH 1/8] driver --- general/include/lis2mdl_reg.h | 510 ++++++++++++ general/src/lis2mdl_reg.c | 1417 +++++++++++++++++++++++++++++++++ 2 files changed, 1927 insertions(+) create mode 100644 general/include/lis2mdl_reg.h create mode 100644 general/src/lis2mdl_reg.c diff --git a/general/include/lis2mdl_reg.h b/general/include/lis2mdl_reg.h new file mode 100644 index 00000000..7d79ce04 --- /dev/null +++ b/general/include/lis2mdl_reg.h @@ -0,0 +1,510 @@ +/** + ****************************************************************************** + * @file lis2mdl_reg.h + * @author Sensors Software Solution Team + * @brief This file contains all the functions prototypes for the + * lis2mdl_reg.c driver. + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef LIS2MDL_REGS_H +#define LIS2MDL_REGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include +#include +#include + +/** @addtogroup LIS2MDL + * @{ + * + */ + +/** @defgroup Endianness definitions + * @{ + * + */ + +#ifndef DRV_BYTE_ORDER +#ifndef __BYTE_ORDER__ + +#define DRV_LITTLE_ENDIAN 1234 +#define DRV_BIG_ENDIAN 4321 + +/** if _BYTE_ORDER is not defined, choose the endianness of your architecture + * by uncommenting the define which fits your platform endianness + */ +//#define DRV_BYTE_ORDER DRV_BIG_ENDIAN +#define DRV_BYTE_ORDER DRV_LITTLE_ENDIAN + +#else /* defined __BYTE_ORDER__ */ + +#define DRV_LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +#define DRV_BIG_ENDIAN __ORDER_BIG_ENDIAN__ +#define DRV_BYTE_ORDER __BYTE_ORDER__ + +#endif /* __BYTE_ORDER__*/ +#endif /* DRV_BYTE_ORDER */ + +/** + * @} + * + */ + +/** @defgroup STMicroelectronics sensors common types + * @{ + * + */ + +#ifndef MEMS_SHARED_TYPES +#define MEMS_SHARED_TYPES + +typedef struct { +#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN + uint8_t bit0 : 1; + uint8_t bit1 : 1; + uint8_t bit2 : 1; + uint8_t bit3 : 1; + uint8_t bit4 : 1; + uint8_t bit5 : 1; + uint8_t bit6 : 1; + uint8_t bit7 : 1; +#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN + uint8_t bit7 : 1; + uint8_t bit6 : 1; + uint8_t bit5 : 1; + uint8_t bit4 : 1; + uint8_t bit3 : 1; + uint8_t bit2 : 1; + uint8_t bit1 : 1; + uint8_t bit0 : 1; +#endif /* DRV_BYTE_ORDER */ +} bitwise_t; + +#define PROPERTY_DISABLE (0U) +#define PROPERTY_ENABLE (1U) + +/** @addtogroup Interfaces_Functions + * @brief This section provide a set of functions used to read and + * write a generic register of the device. + * MANDATORY: return 0 -> no Error. + * @{ + * + */ + +typedef int32_t (*stmdev_write_ptr)(void *, uint8_t, const uint8_t *, uint16_t); +typedef int32_t (*stmdev_read_ptr)(void *, uint8_t, uint8_t *, uint16_t); +typedef void (*stmdev_mdelay_ptr)(uint32_t millisec); + +typedef struct { + /** Component mandatory fields **/ + stmdev_write_ptr write_reg; + stmdev_read_ptr read_reg; + /** Component optional fields **/ + stmdev_mdelay_ptr mdelay; + /** Customizable optional pointer **/ + void *handle; + + /** private data **/ + void *priv_data; +} stmdev_ctx_t; + +/** + * @} + * + */ + +#endif /* MEMS_SHARED_TYPES */ + +#ifndef MEMS_UCF_SHARED_TYPES +#define MEMS_UCF_SHARED_TYPES + +/** @defgroup Generic address-data structure definition + * @brief This structure is useful to load a predefined configuration + * of a sensor. + * You can create a sensor configuration by your own or using + * Unico / Unicleo tools available on STMicroelectronics + * web site. + * + * @{ + * + */ + +typedef struct { + uint8_t address; + uint8_t data; +} ucf_line_t; + +/** + * @} + * + */ + +#endif /* MEMS_UCF_SHARED_TYPES */ + +/** + * @} + * + */ + +/** @defgroup LSM9DS1_Infos + * @{ + * + */ + +/** I2C Device Address 8 bit format **/ +#define LIS2MDL_I2C_ADD 0x3DU + +/** Device Identification (Who am I) **/ +#define LIS2MDL_ID 0x40U + +/** + * @} + * + */ + +#define LIS2MDL_OFFSET_X_REG_L 0x45U +#define LIS2MDL_OFFSET_X_REG_H 0x46U +#define LIS2MDL_OFFSET_Y_REG_L 0x47U +#define LIS2MDL_OFFSET_Y_REG_H 0x48U +#define LIS2MDL_OFFSET_Z_REG_L 0x49U +#define LIS2MDL_OFFSET_Z_REG_H 0x4AU +#define LIS2MDL_WHO_AM_I 0x4FU +#define LIS2MDL_CFG_REG_A 0x60U +typedef struct { +#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN + uint8_t md : 2; + uint8_t odr : 2; + uint8_t lp : 1; + uint8_t soft_rst : 1; + uint8_t reboot : 1; + uint8_t comp_temp_en : 1; +#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN + uint8_t comp_temp_en : 1; + uint8_t reboot : 1; + uint8_t soft_rst : 1; + uint8_t lp : 1; + uint8_t odr : 2; + uint8_t md : 2; +#endif /* DRV_BYTE_ORDER */ +} lis2mdl_cfg_reg_a_t; + +#define LIS2MDL_CFG_REG_B 0x61U +typedef struct { +#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN + uint8_t lpf : 1; + uint8_t set_rst : 2; /* OFF_CANC + Set_FREQ */ + uint8_t int_on_dataoff : 1; + uint8_t off_canc_one_shot : 1; + uint8_t not_used_01 : 3; +#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN + uint8_t not_used_01 : 3; + uint8_t off_canc_one_shot : 1; + uint8_t int_on_dataoff : 1; + uint8_t set_rst : 2; /* OFF_CANC + Set_FREQ */ + uint8_t lpf : 1; +#endif /* DRV_BYTE_ORDER */ +} lis2mdl_cfg_reg_b_t; + +#define LIS2MDL_CFG_REG_C 0x62U +typedef struct { +#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN + uint8_t drdy_on_pin : 1; + uint8_t self_test : 1; + uint8_t _4wspi : 1; + uint8_t ble : 1; + uint8_t bdu : 1; + uint8_t i2c_dis : 1; + uint8_t int_on_pin : 1; + uint8_t not_used_02 : 1; +#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN + uint8_t not_used_02 : 1; + uint8_t int_on_pin : 1; + uint8_t i2c_dis : 1; + uint8_t bdu : 1; + uint8_t ble : 1; + uint8_t _4wspi : 1; + uint8_t self_test : 1; + uint8_t drdy_on_pin : 1; +#endif /* DRV_BYTE_ORDER */ +} lis2mdl_cfg_reg_c_t; + +#define LIS2MDL_INT_CRTL_REG 0x63U +typedef struct { +#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN + uint8_t ien : 1; + uint8_t iel : 1; + uint8_t iea : 1; + uint8_t not_used_01 : 2; + uint8_t zien : 1; + uint8_t yien : 1; + uint8_t xien : 1; +#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN + uint8_t xien : 1; + uint8_t yien : 1; + uint8_t zien : 1; + uint8_t not_used_01 : 2; + uint8_t iea : 1; + uint8_t iel : 1; + uint8_t ien : 1; +#endif /* DRV_BYTE_ORDER */ +} lis2mdl_int_crtl_reg_t; + +#define LIS2MDL_INT_SOURCE_REG 0x64U +typedef struct { +#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN + uint8_t _int : 1; + uint8_t mroi : 1; + uint8_t n_th_s_z : 1; + uint8_t n_th_s_y : 1; + uint8_t n_th_s_x : 1; + uint8_t p_th_s_z : 1; + uint8_t p_th_s_y : 1; + uint8_t p_th_s_x : 1; +#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN + uint8_t p_th_s_x : 1; + uint8_t p_th_s_y : 1; + uint8_t p_th_s_z : 1; + uint8_t n_th_s_x : 1; + uint8_t n_th_s_y : 1; + uint8_t n_th_s_z : 1; + uint8_t mroi : 1; + uint8_t _int : 1; +#endif /* DRV_BYTE_ORDER */ +} lis2mdl_int_source_reg_t; + +#define LIS2MDL_INT_THS_L_REG 0x65U +#define LIS2MDL_INT_THS_H_REG 0x66U +#define LIS2MDL_STATUS_REG 0x67U +typedef struct { +#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN + uint8_t xda : 1; + uint8_t yda : 1; + uint8_t zda : 1; + uint8_t zyxda : 1; + uint8_t _xor : 1; + uint8_t yor : 1; + uint8_t zor : 1; + uint8_t zyxor : 1; +#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN + uint8_t zyxor : 1; + uint8_t zor : 1; + uint8_t yor : 1; + uint8_t _xor : 1; + uint8_t zyxda : 1; + uint8_t zda : 1; + uint8_t yda : 1; + uint8_t xda : 1; +#endif /* DRV_BYTE_ORDER */ +} lis2mdl_status_reg_t; + +#define LIS2MDL_OUTX_L_REG 0x68U +#define LIS2MDL_OUTX_H_REG 0x69U +#define LIS2MDL_OUTY_L_REG 0x6AU +#define LIS2MDL_OUTY_H_REG 0x6BU +#define LIS2MDL_OUTZ_L_REG 0x6CU +#define LIS2MDL_OUTZ_H_REG 0x6DU +#define LIS2MDL_TEMP_OUT_L_REG 0x6EU +#define LIS2MDL_TEMP_OUT_H_REG 0x6FU + +/** + * @defgroup LIS2MDL_Register_Union + * @brief This union group all the registers having a bit-field + * description. + * This union is useful but it's not needed by the driver. + * + * REMOVING this union you are compliant with: + * MISRA-C 2012 [Rule 19.2] -> " Union are not allowed " + * + * @{ + * + */ +typedef union { + lis2mdl_cfg_reg_a_t cfg_reg_a; + lis2mdl_cfg_reg_b_t cfg_reg_b; + lis2mdl_cfg_reg_c_t cfg_reg_c; + lis2mdl_int_crtl_reg_t int_crtl_reg; + lis2mdl_int_source_reg_t int_source_reg; + lis2mdl_status_reg_t status_reg; + bitwise_t bitwise; + uint8_t byte; +} lis2mdl_reg_t; + +/** + * @} + * + */ + +#ifndef __weak +#define __weak __attribute__((weak)) +#endif /* __weak */ + +/* + * These are the basic platform dependent I/O routines to read + * and write device registers connected on a standard bus. + * The driver keeps offering a default implementation based on function + * pointers to read/write routines for backward compatibility. + * The __weak directive allows the final application to overwrite + * them with a custom implementation. + */ + +int32_t lis2mdl_read_reg(const stmdev_ctx_t *ctx, uint8_t reg, uint8_t *data, + uint16_t len); +int32_t lis2mdl_write_reg(const stmdev_ctx_t *ctx, uint8_t reg, uint8_t *data, + uint16_t len); + +float_t lis2mdl_from_lsb_to_mgauss(int16_t lsb); + +float_t lis2mdl_from_lsb_to_celsius(int16_t lsb); + +int32_t lis2mdl_mag_user_offset_set(const stmdev_ctx_t *ctx, int16_t *val); +int32_t lis2mdl_mag_user_offset_get(const stmdev_ctx_t *ctx, int16_t *val); + +typedef enum { + LIS2MDL_CONTINUOUS_MODE = 0, + LIS2MDL_SINGLE_TRIGGER = 1, + LIS2MDL_POWER_DOWN = 2, +} lis2mdl_md_t; +int32_t lis2mdl_operating_mode_set(const stmdev_ctx_t *ctx, lis2mdl_md_t val); +int32_t lis2mdl_operating_mode_get(const stmdev_ctx_t *ctx, lis2mdl_md_t *val); + +typedef enum { + LIS2MDL_ODR_10Hz = 0, + LIS2MDL_ODR_20Hz = 1, + LIS2MDL_ODR_50Hz = 2, + LIS2MDL_ODR_100Hz = 3, +} lis2mdl_odr_t; +int32_t lis2mdl_data_rate_set(const stmdev_ctx_t *ctx, lis2mdl_odr_t val); +int32_t lis2mdl_data_rate_get(const stmdev_ctx_t *ctx, lis2mdl_odr_t *val); + +typedef enum { + LIS2MDL_HIGH_RESOLUTION = 0, + LIS2MDL_LOW_POWER = 1, +} lis2mdl_lp_t; +int32_t lis2mdl_power_mode_set(const stmdev_ctx_t *ctx, lis2mdl_lp_t val); +int32_t lis2mdl_power_mode_get(const stmdev_ctx_t *ctx, lis2mdl_lp_t *val); + +int32_t lis2mdl_offset_temp_comp_set(const stmdev_ctx_t *ctx, uint8_t val); +int32_t lis2mdl_offset_temp_comp_get(const stmdev_ctx_t *ctx, uint8_t *val); + +typedef enum { + LIS2MDL_ODR_DIV_2 = 0, + LIS2MDL_ODR_DIV_4 = 1, +} lis2mdl_lpf_t; +int32_t lis2mdl_low_pass_bandwidth_set(const stmdev_ctx_t *ctx, + lis2mdl_lpf_t val); +int32_t lis2mdl_low_pass_bandwidth_get(const stmdev_ctx_t *ctx, + lis2mdl_lpf_t *val); + +typedef enum { + LIS2MDL_SET_SENS_ODR_DIV_63 = 0, + LIS2MDL_SENS_OFF_CANC_EVERY_ODR = 1, + LIS2MDL_SET_SENS_ONLY_AT_POWER_ON = 2, +} lis2mdl_set_rst_t; +int32_t lis2mdl_set_rst_mode_set(const stmdev_ctx_t *ctx, + lis2mdl_set_rst_t val); +int32_t lis2mdl_set_rst_mode_get(const stmdev_ctx_t *ctx, + lis2mdl_set_rst_t *val); + +int32_t lis2mdl_set_rst_sensor_single_set(const stmdev_ctx_t *ctx, uint8_t val); +int32_t lis2mdl_set_rst_sensor_single_get(const stmdev_ctx_t *ctx, + uint8_t *val); + +int32_t lis2mdl_block_data_update_set(const stmdev_ctx_t *ctx, uint8_t val); +int32_t lis2mdl_block_data_update_get(const stmdev_ctx_t *ctx, uint8_t *val); + +int32_t lis2mdl_mag_data_ready_get(const stmdev_ctx_t *ctx, uint8_t *val); + +int32_t lis2mdl_mag_data_ovr_get(const stmdev_ctx_t *ctx, uint8_t *val); + +int32_t lis2mdl_magnetic_raw_get(const stmdev_ctx_t *ctx, int16_t *val); + +int32_t lis2mdl_temperature_raw_get(const stmdev_ctx_t *ctx, int16_t *val); + +int32_t lis2mdl_device_id_get(const stmdev_ctx_t *ctx, uint8_t *buff); + +int32_t lis2mdl_reset_set(const stmdev_ctx_t *ctx, uint8_t val); +int32_t lis2mdl_reset_get(const stmdev_ctx_t *ctx, uint8_t *val); + +int32_t lis2mdl_boot_set(const stmdev_ctx_t *ctx, uint8_t val); +int32_t lis2mdl_boot_get(const stmdev_ctx_t *ctx, uint8_t *val); + +int32_t lis2mdl_self_test_set(const stmdev_ctx_t *ctx, uint8_t val); +int32_t lis2mdl_self_test_get(const stmdev_ctx_t *ctx, uint8_t *val); + +typedef enum { + LIS2MDL_LSB_AT_LOW_ADD = 0, + LIS2MDL_MSB_AT_LOW_ADD = 1, +} lis2mdl_ble_t; +int32_t lis2mdl_data_format_set(const stmdev_ctx_t *ctx, lis2mdl_ble_t val); +int32_t lis2mdl_data_format_get(const stmdev_ctx_t *ctx, lis2mdl_ble_t *val); + +int32_t lis2mdl_status_get(const stmdev_ctx_t *ctx, lis2mdl_status_reg_t *val); + +typedef enum { + LIS2MDL_CHECK_BEFORE = 0, + LIS2MDL_CHECK_AFTER = 1, +} lis2mdl_int_on_dataoff_t; +int32_t lis2mdl_offset_int_conf_set(const stmdev_ctx_t *ctx, + lis2mdl_int_on_dataoff_t val); +int32_t lis2mdl_offset_int_conf_get(const stmdev_ctx_t *ctx, + lis2mdl_int_on_dataoff_t *val); + +int32_t lis2mdl_drdy_on_pin_set(const stmdev_ctx_t *ctx, uint8_t val); +int32_t lis2mdl_drdy_on_pin_get(const stmdev_ctx_t *ctx, uint8_t *val); + +int32_t lis2mdl_int_on_pin_set(const stmdev_ctx_t *ctx, uint8_t val); +int32_t lis2mdl_int_on_pin_get(const stmdev_ctx_t *ctx, uint8_t *val); + +int32_t lis2mdl_int_gen_conf_set(const stmdev_ctx_t *ctx, + lis2mdl_int_crtl_reg_t *val); +int32_t lis2mdl_int_gen_conf_get(const stmdev_ctx_t *ctx, + lis2mdl_int_crtl_reg_t *val); + +int32_t lis2mdl_int_gen_source_get(const stmdev_ctx_t *ctx, + lis2mdl_int_source_reg_t *val); + +int32_t lis2mdl_int_gen_threshold_set(const stmdev_ctx_t *ctx, uint16_t val); +int32_t lis2mdl_int_gen_threshold_get(const stmdev_ctx_t *ctx, uint16_t *val); + +typedef enum { + LIS2MDL_SPI_4_WIRE = 1, + LIS2MDL_SPI_3_WIRE = 0, +} lis2mdl_sim_t; +int32_t lis2mdl_spi_mode_set(const stmdev_ctx_t *ctx, lis2mdl_sim_t val); +int32_t lis2mdl_spi_mode_get(const stmdev_ctx_t *ctx, lis2mdl_sim_t *val); + +typedef enum { + LIS2MDL_I2C_ENABLE = 0, + LIS2MDL_I2C_DISABLE = 1, +} lis2mdl_i2c_dis_t; +int32_t lis2mdl_i2c_interface_set(const stmdev_ctx_t *ctx, + lis2mdl_i2c_dis_t val); +int32_t lis2mdl_i2c_interface_get(const stmdev_ctx_t *ctx, + lis2mdl_i2c_dis_t *val); + +/** + *@} + * + */ + +#ifdef __cplusplus +} +#endif + +#endif /* LIS2MDL_REGS_H */ diff --git a/general/src/lis2mdl_reg.c b/general/src/lis2mdl_reg.c new file mode 100644 index 00000000..df559124 --- /dev/null +++ b/general/src/lis2mdl_reg.c @@ -0,0 +1,1417 @@ +/** + ****************************************************************************** + * @file lis2mdl_reg.c + * @author Sensors Software Solution Team + * @brief LIS2MDL driver file + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#include "lis2mdl_reg.h" + +/** + * @defgroup LIS2MDL + * @brief This file provides a set of functions needed to drive the + * lis2mdl enhanced inertial module. + * @{ + * + */ + +/** + * @defgroup LIS2MDL_Interfaces_Functions + * @brief This section provide a set of functions used to read and + * write a generic register of the device. + * MANDATORY: return 0 -> no Error. + * @{ + * + */ + +/** + * @brief Read generic device register + * + * @param ctx read / write interface definitions(ptr) + * @param reg register to read + * @param data pointer to buffer that store the data read(ptr) + * @param len number of consecutive register to read + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t __weak lis2mdl_read_reg(const stmdev_ctx_t *ctx, uint8_t reg, + uint8_t *data, uint16_t len) +{ + int32_t ret; + + if (ctx == NULL) { + return -1; + } + + ret = ctx->read_reg(ctx->handle, reg, data, len); + + return ret; +} + +/** + * @brief Write generic device register + * + * @param ctx read / write interface definitions(ptr) + * @param reg register to write + * @param data pointer to data to write in register reg(ptr) + * @param len number of consecutive register to write + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t __weak lis2mdl_write_reg(const stmdev_ctx_t *ctx, uint8_t reg, + uint8_t *data, uint16_t len) +{ + int32_t ret; + + if (ctx == NULL) { + return -1; + } + + ret = ctx->write_reg(ctx->handle, reg, data, len); + + return ret; +} + +/** + * @} + * + */ + +/** + * @defgroup LIS2MDL_Sensitivity + * @brief These functions convert raw-data into engineering units. + * @{ + * + */ +float_t lis2mdl_from_lsb_to_mgauss(int16_t lsb) +{ + return ((float_t)lsb * 1.5f); +} + +float_t lis2mdl_from_lsb_to_celsius(int16_t lsb) +{ + return (((float_t)lsb / 8.0f) + 25.0f); +} + +/** + * @} + * + */ + +/** + * @defgroup LIS2MDL_data_generation + * @brief This section group all the functions concerning + * data generation + * @{ + * + */ + +/** + * @brief These registers comprise a 3 group of 16-bit number and represent + * hard-iron offset in order to compensate environmental effects. + * Data format is the same of output data raw: two's complement + * with 1LSb = 1.5mG. These values act on the magnetic output data + * value in order to delete the environmental offset.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param buff buffer that contains data to write + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_mag_user_offset_set(const stmdev_ctx_t *ctx, int16_t *val) +{ + uint8_t buff[6]; + int32_t ret; + + buff[1] = (uint8_t)((uint16_t)val[0] / 256U); + buff[0] = (uint8_t)((uint16_t)val[0] - (buff[1] * 256U)); + buff[3] = (uint8_t)((uint16_t)val[1] / 256U); + buff[2] = (uint8_t)((uint16_t)val[1] - (buff[3] * 256U)); + buff[5] = (uint8_t)((uint16_t)val[2] / 256U); + buff[4] = (uint8_t)((uint16_t)val[2] - (buff[5] * 256U)); + ret = lis2mdl_write_reg(ctx, LIS2MDL_OFFSET_X_REG_L, buff, 6); + + return ret; +} + +/** + * @brief These registers comprise a 3 group of 16-bit number and represent + * hard-iron offset in order to compensate environmental effects. + * Data format is the same of output data raw: two's complement + * with 1LSb = 1.5mG. These values act on the magnetic output data + * value in order to delete the environmental offset.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param buff that stores data read + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_mag_user_offset_get(const stmdev_ctx_t *ctx, int16_t *val) +{ + uint8_t buff[6]; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_OFFSET_X_REG_L, buff, 6); + + if (ret != 0) { + return ret; + } + + val[0] = (int16_t)buff[1]; + val[0] = (val[0] * 256) + (int16_t)buff[0]; + val[1] = (int16_t)buff[3]; + val[1] = (val[1] * 256) + (int16_t)buff[2]; + val[2] = (int16_t)buff[5]; + val[2] = (val[2] * 256) + (int16_t)buff[4]; + + return ret; +} + +/** + * @brief Operating mode selection.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of md in reg CFG_REG_A + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_operating_mode_set(const stmdev_ctx_t *ctx, lis2mdl_md_t val) +{ + lis2mdl_cfg_reg_a_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, 1); + + if (ret == 0) { + reg.md = (uint8_t)val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief Operating mode selection.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val Get the values of md in reg CFG_REG_A.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_operating_mode_get(const stmdev_ctx_t *ctx, lis2mdl_md_t *val) +{ + lis2mdl_cfg_reg_a_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + switch (reg.md) { + case LIS2MDL_POWER_DOWN: + *val = LIS2MDL_POWER_DOWN; + break; + + case LIS2MDL_CONTINUOUS_MODE: + *val = LIS2MDL_CONTINUOUS_MODE; + break; + + case LIS2MDL_SINGLE_TRIGGER: + *val = LIS2MDL_SINGLE_TRIGGER; + break; + + default: + *val = LIS2MDL_POWER_DOWN; + break; + } + + return ret; +} + +/** + * @brief Output data rate selection.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of odr in reg CFG_REG_A + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_data_rate_set(const stmdev_ctx_t *ctx, lis2mdl_odr_t val) +{ + lis2mdl_cfg_reg_a_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, 1); + + if (ret == 0) { + reg.odr = (uint8_t)val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief Output data rate selection.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val Get the values of odr in reg CFG_REG_A.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_data_rate_get(const stmdev_ctx_t *ctx, lis2mdl_odr_t *val) +{ + lis2mdl_cfg_reg_a_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + switch (reg.odr) { + case LIS2MDL_ODR_10Hz: + *val = LIS2MDL_ODR_10Hz; + break; + + case LIS2MDL_ODR_20Hz: + *val = LIS2MDL_ODR_20Hz; + break; + + case LIS2MDL_ODR_50Hz: + *val = LIS2MDL_ODR_50Hz; + break; + + case LIS2MDL_ODR_100Hz: + *val = LIS2MDL_ODR_100Hz; + break; + + default: + *val = LIS2MDL_ODR_10Hz; + break; + } + + return ret; +} + +/** + * @brief Enables high-resolution/low-power mode.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of lp in reg CFG_REG_A + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_power_mode_set(const stmdev_ctx_t *ctx, lis2mdl_lp_t val) +{ + lis2mdl_cfg_reg_a_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, 1); + + if (ret == 0) { + reg.lp = (uint8_t)val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief Enables high-resolution/low-power mode.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val Get the values of lp in reg CFG_REG_A.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_power_mode_get(const stmdev_ctx_t *ctx, lis2mdl_lp_t *val) +{ + lis2mdl_cfg_reg_a_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + switch (reg.lp) { + case LIS2MDL_HIGH_RESOLUTION: + *val = LIS2MDL_HIGH_RESOLUTION; + break; + + case LIS2MDL_LOW_POWER: + *val = LIS2MDL_LOW_POWER; + break; + + default: + *val = LIS2MDL_HIGH_RESOLUTION; + break; + } + + return ret; +} + +/** + * @brief Enables the magnetometer temperature compensation.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of comp_temp_en in reg CFG_REG_A + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_offset_temp_comp_set(const stmdev_ctx_t *ctx, uint8_t val) +{ + lis2mdl_cfg_reg_a_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, 1); + + if (ret == 0) { + reg.comp_temp_en = val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief Enables the magnetometer temperature compensation.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of comp_temp_en in reg CFG_REG_A.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_offset_temp_comp_get(const stmdev_ctx_t *ctx, uint8_t *val) +{ + lis2mdl_cfg_reg_a_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + *val = reg.comp_temp_en; + + return ret; +} + +/** + * @brief Low-pass bandwidth selection.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of lpf in reg CFG_REG_B + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_low_pass_bandwidth_set(const stmdev_ctx_t *ctx, + lis2mdl_lpf_t val) +{ + lis2mdl_cfg_reg_b_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_B, (uint8_t *)®, 1); + + if (ret == 0) { + reg.lpf = (uint8_t)val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_B, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief Low-pass bandwidth selection.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val Get the values of lpf in reg CFG_REG_B.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_low_pass_bandwidth_get(const stmdev_ctx_t *ctx, + lis2mdl_lpf_t *val) +{ + lis2mdl_cfg_reg_b_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_B, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + switch (reg.lpf) { + case LIS2MDL_ODR_DIV_2: + *val = LIS2MDL_ODR_DIV_2; + break; + + case LIS2MDL_ODR_DIV_4: + *val = LIS2MDL_ODR_DIV_4; + break; + + default: + *val = LIS2MDL_ODR_DIV_2; + break; + } + + return ret; +} + +/** + * @brief Reset mode.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of set_rst in reg CFG_REG_B + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_set_rst_mode_set(const stmdev_ctx_t *ctx, lis2mdl_set_rst_t val) +{ + lis2mdl_cfg_reg_b_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_B, (uint8_t *)®, 1); + + if (ret == 0) { + reg.set_rst = (uint8_t)val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_B, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief Reset mode.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val Get the values of set_rst in reg CFG_REG_B.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_set_rst_mode_get(const stmdev_ctx_t *ctx, + lis2mdl_set_rst_t *val) +{ + lis2mdl_cfg_reg_b_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_B, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + switch (reg.set_rst) { + case LIS2MDL_SET_SENS_ODR_DIV_63: + *val = LIS2MDL_SET_SENS_ODR_DIV_63; + break; + + case LIS2MDL_SENS_OFF_CANC_EVERY_ODR: + *val = LIS2MDL_SENS_OFF_CANC_EVERY_ODR; + break; + + case LIS2MDL_SET_SENS_ONLY_AT_POWER_ON: + *val = LIS2MDL_SET_SENS_ONLY_AT_POWER_ON; + break; + + default: + *val = LIS2MDL_SET_SENS_ODR_DIV_63; + break; + } + + return ret; +} + +/** + * @brief Enables offset cancellation in single measurement mode. + * The OFF_CANC bit must be set to 1 when enabling offset + * cancellation in single measurement mode this means a + * call function: set_rst_mode(SENS_OFF_CANC_EVERY_ODR) + * is need.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of off_canc_one_shot in reg CFG_REG_B + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_set_rst_sensor_single_set(const stmdev_ctx_t *ctx, uint8_t val) +{ + lis2mdl_cfg_reg_b_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_B, (uint8_t *)®, 1); + + if (ret == 0) { + reg.off_canc_one_shot = val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_B, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief Enables offset cancellation in single measurement mode. + * The OFF_CANC bit must be set to 1 when enabling offset + * cancellation in single measurement mode this means a + * call function: set_rst_mode(SENS_OFF_CANC_EVERY_ODR) + * is need.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of off_canc_one_shot in reg CFG_REG_B.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_set_rst_sensor_single_get(const stmdev_ctx_t *ctx, uint8_t *val) +{ + lis2mdl_cfg_reg_b_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_B, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + *val = reg.off_canc_one_shot; + + return ret; +} + +/** + * @brief Blockdataupdate.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of bdu in reg CFG_REG_C + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_block_data_update_set(const stmdev_ctx_t *ctx, uint8_t val) +{ + lis2mdl_cfg_reg_c_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, 1); + + if (ret == 0) { + reg.bdu = val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief Blockdataupdate.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of bdu in reg CFG_REG_C.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_block_data_update_get(const stmdev_ctx_t *ctx, uint8_t *val) +{ + lis2mdl_cfg_reg_c_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + *val = reg.bdu; + + return ret; +} + +/** + * @brief Magnetic set of data available.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of zyxda in reg STATUS_REG.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_mag_data_ready_get(const stmdev_ctx_t *ctx, uint8_t *val) +{ + lis2mdl_status_reg_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_STATUS_REG, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + *val = reg.zyxda; + + return ret; +} + +/** + * @brief Magnetic set of data overrun.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of zyxor in reg STATUS_REG.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_mag_data_ovr_get(const stmdev_ctx_t *ctx, uint8_t *val) +{ + lis2mdl_status_reg_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_STATUS_REG, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + *val = reg.zyxor; + + return ret; +} + +/** + * @brief Magnetic output value.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param buff that stores data read + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_magnetic_raw_get(const stmdev_ctx_t *ctx, int16_t *val) +{ + uint8_t buff[6]; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_OUTX_L_REG, buff, 6); + + if (ret != 0) { + return ret; + } + + val[0] = (int16_t)buff[1]; + val[0] = (val[0] * 256) + (int16_t)buff[0]; + val[1] = (int16_t)buff[3]; + val[1] = (val[1] * 256) + (int16_t)buff[2]; + val[2] = (int16_t)buff[5]; + val[2] = (val[2] * 256) + (int16_t)buff[4]; + + return ret; +} + +/** + * @brief Temperature output value.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param buff that stores data read + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_temperature_raw_get(const stmdev_ctx_t *ctx, int16_t *val) +{ + uint8_t buff[2]; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_TEMP_OUT_L_REG, buff, 2); + + if (ret != 0) { + return ret; + } + + *val = (int16_t)buff[1]; + *val = (*val * 256) + (int16_t)buff[0]; + + return ret; +} + +/** + * @} + * + */ + +/** + * @defgroup LIS2MDL_common + * @brief This section group common useful functions + * @{ + * + */ + +/** + * @brief DeviceWhoamI.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param buff that stores data read + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_device_id_get(const stmdev_ctx_t *ctx, uint8_t *buff) +{ + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_WHO_AM_I, buff, 1); + + return ret; +} + +/** + * @brief Software reset. Restore the default values in user registers.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of soft_rst in reg CFG_REG_A + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_reset_set(const stmdev_ctx_t *ctx, uint8_t val) +{ + lis2mdl_cfg_reg_a_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, 1); + + if (ret == 0) { + reg.soft_rst = val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief Software reset. Restore the default values in user registers.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of soft_rst in reg CFG_REG_A.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_reset_get(const stmdev_ctx_t *ctx, uint8_t *val) +{ + lis2mdl_cfg_reg_a_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + *val = reg.soft_rst; + + return ret; +} + +/** + * @brief Reboot memory content. Reload the calibration parameters.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of reboot in reg CFG_REG_A + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_boot_set(const stmdev_ctx_t *ctx, uint8_t val) +{ + lis2mdl_cfg_reg_a_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, 1); + + if (ret == 0) { + reg.reboot = val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief Reboot memory content. Reload the calibration parameters.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of reboot in reg CFG_REG_A.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_boot_get(const stmdev_ctx_t *ctx, uint8_t *val) +{ + lis2mdl_cfg_reg_a_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_A, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + *val = reg.reboot; + + return ret; +} + +/** + * @brief Selftest.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of self_test in reg CFG_REG_C + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_self_test_set(const stmdev_ctx_t *ctx, uint8_t val) +{ + lis2mdl_cfg_reg_c_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, 1); + + if (ret == 0) { + reg.self_test = val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief Selftest.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of self_test in reg CFG_REG_C.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_self_test_get(const stmdev_ctx_t *ctx, uint8_t *val) +{ + lis2mdl_cfg_reg_c_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + *val = reg.self_test; + + return ret; +} + +/** + * @brief Big/Little Endian data selection.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of ble in reg CFG_REG_C + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_data_format_set(const stmdev_ctx_t *ctx, lis2mdl_ble_t val) +{ + lis2mdl_cfg_reg_c_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, 1); + + if (ret == 0) { + reg.ble = (uint8_t)val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief Big/Little Endian data selection.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val Get the values of ble in reg CFG_REG_C.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_data_format_get(const stmdev_ctx_t *ctx, lis2mdl_ble_t *val) +{ + lis2mdl_cfg_reg_c_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + switch (reg.ble) { + case LIS2MDL_LSB_AT_LOW_ADD: + *val = LIS2MDL_LSB_AT_LOW_ADD; + break; + + case LIS2MDL_MSB_AT_LOW_ADD: + *val = LIS2MDL_MSB_AT_LOW_ADD; + break; + + default: + *val = LIS2MDL_LSB_AT_LOW_ADD; + break; + } + + return ret; +} + +/** + * @brief Info about device status.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val registers STATUS_REG.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_status_get(const stmdev_ctx_t *ctx, lis2mdl_status_reg_t *val) +{ + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_STATUS_REG, (uint8_t *)val, 1); + + return ret; +} + +/** + * @} + * + */ + +/** + * @defgroup LIS2MDL_interrupts + * @brief This section group all the functions that manage interrupts + * @{ + * + */ + +/** + * @brief The interrupt block recognition checks data after/before the + * hard-iron correction to discover the interrupt.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of int_on_dataoff in reg CFG_REG_B + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_offset_int_conf_set(const stmdev_ctx_t *ctx, + lis2mdl_int_on_dataoff_t val) +{ + lis2mdl_cfg_reg_b_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_B, (uint8_t *)®, 1); + + if (ret == 0) { + reg.int_on_dataoff = (uint8_t)val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_B, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief The interrupt block recognition checks data after/before the + * hard-iron correction to discover the interrupt.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val Get the values of int_on_dataoff in reg CFG_REG_B.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_offset_int_conf_get(const stmdev_ctx_t *ctx, + lis2mdl_int_on_dataoff_t *val) +{ + lis2mdl_cfg_reg_b_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_B, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + switch (reg.int_on_dataoff) { + case LIS2MDL_CHECK_BEFORE: + *val = LIS2MDL_CHECK_BEFORE; + break; + + case LIS2MDL_CHECK_AFTER: + *val = LIS2MDL_CHECK_AFTER; + break; + + default: + *val = LIS2MDL_CHECK_BEFORE; + break; + } + + return ret; +} + +/** + * @brief Data-ready signal on INT_DRDY pin.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of drdy_on_pin in reg CFG_REG_C + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_drdy_on_pin_set(const stmdev_ctx_t *ctx, uint8_t val) +{ + lis2mdl_cfg_reg_c_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, 1); + + if (ret == 0) { + reg.drdy_on_pin = val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief Data-ready signal on INT_DRDY pin.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of drdy_on_pin in reg CFG_REG_C.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_drdy_on_pin_get(const stmdev_ctx_t *ctx, uint8_t *val) +{ + lis2mdl_cfg_reg_c_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + *val = reg.drdy_on_pin; + + return ret; +} + +/** + * @brief Interrupt signal on INT_DRDY pin.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of int_on_pin in reg CFG_REG_C + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_int_on_pin_set(const stmdev_ctx_t *ctx, uint8_t val) +{ + lis2mdl_cfg_reg_c_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, 1); + + if (ret == 0) { + reg.int_on_pin = val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief Interrupt signal on INT_DRDY pin.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of int_on_pin in reg CFG_REG_C.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_int_on_pin_get(const stmdev_ctx_t *ctx, uint8_t *val) +{ + lis2mdl_cfg_reg_c_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + *val = reg.int_on_pin; + + return ret; +} + +/** + * @brief Interrupt generator configuration register.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val registers INT_CRTL_REG.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_int_gen_conf_set(const stmdev_ctx_t *ctx, + lis2mdl_int_crtl_reg_t *val) +{ + int32_t ret; + + ret = lis2mdl_write_reg(ctx, LIS2MDL_INT_CRTL_REG, (uint8_t *)val, 1); + + return ret; +} + +/** + * @brief Interrupt generator configuration register.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val registers INT_CRTL_REG.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_int_gen_conf_get(const stmdev_ctx_t *ctx, + lis2mdl_int_crtl_reg_t *val) +{ + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_INT_CRTL_REG, (uint8_t *)val, 1); + + return ret; +} + +/** + * @brief Interrupt generator source register.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val registers INT_SOURCE_REG.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_int_gen_source_get(const stmdev_ctx_t *ctx, + lis2mdl_int_source_reg_t *val) +{ + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_INT_SOURCE_REG, (uint8_t *)val, 1); + + return ret; +} + +/** + * @brief User-defined threshold value for xl interrupt event on generator. + * Data format is the same of output data raw: two's complement with + * 1LSb = 1.5mG.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param buff that contains data to write + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_int_gen_threshold_set(const stmdev_ctx_t *ctx, uint16_t val) +{ + uint8_t buff[2]; + int32_t ret; + + buff[1] = (uint8_t)(val / 256U); + buff[0] = (uint8_t)(val - (buff[1] * 256U)); + ret = lis2mdl_write_reg(ctx, LIS2MDL_INT_THS_L_REG, buff, 2); + + return ret; +} + +/** + * @brief User-defined threshold value for xl interrupt event on generator. + * Data format is the same of output data raw: two's complement with + * 1LSb = 1.5mG.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param buff that stores data read + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_int_gen_threshold_get(const stmdev_ctx_t *ctx, uint16_t *val) +{ + uint8_t buff[2]; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_INT_THS_L_REG, buff, 2); + + if (ret != 0) { + return ret; + } + + *val = buff[1]; + *val = (*val * 256U) + buff[0]; + + return ret; +} + +/** + * @} + * + */ + +/** + * @defgroup LIS2MDL_serial_interface + * @brief This section group all the functions concerning serial + * interface management + * @{ + * + */ + +/** + * @brief SPI Serial Interface Mode selection.[set] + * + * @param ctx read / write interface definitions + * @param val change the values of 4wspi in reg CFG_REG_C + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_spi_mode_set(const stmdev_ctx_t *ctx, lis2mdl_sim_t val) +{ + lis2mdl_cfg_reg_c_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, 1); + + if (ret == 0) { + reg._4wspi = (uint8_t)val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief SPI Serial Interface Mode selection.[get] + * + * @param ctx read / write interface definitions + * @param val Get the values of 4wspi in reg CFG_REG_C + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_spi_mode_get(const stmdev_ctx_t *ctx, lis2mdl_sim_t *val) +{ + lis2mdl_cfg_reg_c_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + switch (reg._4wspi) { + case LIS2MDL_SPI_4_WIRE: + *val = LIS2MDL_SPI_4_WIRE; + break; + + case LIS2MDL_SPI_3_WIRE: + *val = LIS2MDL_SPI_3_WIRE; + break; + + default: + *val = LIS2MDL_SPI_3_WIRE; + break; + } + + return ret; +} + +/** + * @brief Enable/Disable I2C interface.[set] + * + * @param ctx read / write interface definitions.(ptr) + * @param val change the values of i2c_dis in reg CFG_REG_C + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_i2c_interface_set(const stmdev_ctx_t *ctx, + lis2mdl_i2c_dis_t val) +{ + lis2mdl_cfg_reg_c_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, 1); + + if (ret == 0) { + reg.i2c_dis = (uint8_t)val; + ret = lis2mdl_write_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, + 1); + } + + return ret; +} + +/** + * @brief Enable/Disable I2C interface.[get] + * + * @param ctx read / write interface definitions.(ptr) + * @param val Get the values of i2c_dis in reg CFG_REG_C.(ptr) + * @retval interface status.(MANDATORY: return 0 -> no Error) + * + */ +int32_t lis2mdl_i2c_interface_get(const stmdev_ctx_t *ctx, + lis2mdl_i2c_dis_t *val) +{ + lis2mdl_cfg_reg_c_t reg; + int32_t ret; + + ret = lis2mdl_read_reg(ctx, LIS2MDL_CFG_REG_C, (uint8_t *)®, 1); + + if (ret != 0) { + return ret; + } + + switch (reg.i2c_dis) { + case LIS2MDL_I2C_ENABLE: + *val = LIS2MDL_I2C_ENABLE; + break; + + case LIS2MDL_I2C_DISABLE: + *val = LIS2MDL_I2C_DISABLE; + break; + + default: + *val = LIS2MDL_I2C_ENABLE; + break; + } + + return ret; +} + +/** + * @} + * + */ From 28828b6c7909fc88addc228ad31779feee698994 Mon Sep 17 00:00:00 2001 From: Daniel Nakhooda Date: Sun, 12 Oct 2025 17:17:29 -0400 Subject: [PATCH 2/8] fixes --- general/include/as3935.h | 12 +++++++----- general/src/as3935.c | 13 ++++++++----- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/general/include/as3935.h b/general/include/as3935.h index 81017f5e..99355db0 100644 --- a/general/include/as3935.h +++ b/general/include/as3935.h @@ -19,6 +19,8 @@ #include #include +#include "stm32h5xx_hal.h" + /* Registers */ #define AS3935_AFE_GB 0x00 #define AS3935_NF_LEV 0x01 @@ -55,14 +57,14 @@ #define AS3935_AFE_OUTDOOR 0b01110 /* Outdoor mode */ #define AS3935_READ_CMD \ - 0b0100 0000 0000 0000 /* First few bits for read command */ + 0x4000 /* 0b0100000000000000 First few bits for read command */ #define AS3935_WRITE_CMD \ - 0b0000 0000 0000 0000 /* First few bits of write command */ + 0x0 /* 0b0000000000000000 First few bits of write command */ #define AS3935_DISTANCE_OUT_OF_RANGE \ - 0b111111 /* This distance reading means storm is out of range */ + 3F /* 0b111111 This distance reading means storm is out of range */ #define AS3935_DISTANCE_OVERHEAD \ - 0b000001 /* This distance reading means the storm is overhead */ + 0x1 /* 0b000001 This distance reading means the storm is overhead */ typedef struct { SPI_HandleTypeDef *hspi; @@ -88,4 +90,4 @@ uint8_t as3935_get_distance(as3935_t *as3935); uint32_t as3935_get_energy(as3935_t *as3935); -#endif AS3935_H \ No newline at end of file +#endif //AS3935_H \ No newline at end of file diff --git a/general/src/as3935.c b/general/src/as3935.c index e076ea7e..bd4db67d 100644 --- a/general/src/as3935.c +++ b/general/src/as3935.c @@ -1,4 +1,5 @@ #include "as3935.h" +#include "stm32h5xx_hal.h" /** * @brief initializes attributes for as3935_t struct; also makes sure cs pin is high @@ -29,7 +30,8 @@ void as3935_init(as3935_t *as3935, SPI_HandleTypeDef *hspi, uint8_t as3935_read(as3935_t *as3935, uint8_t reg) { // first two bits of tx_data is be 0x01. Next 6 bits should be register address. - uint16_t tx_data = AS3935_READ_CMD | ((reg & 0b111111) << 8); + uint16_t tx_data = AS3935_READ_CMD | + ((reg & 0x3F) << 8); /* 0x3F = 0b111111*/ uint8_t rx_buf[2] = { 0 }; HAL_GPIO_WritePin(as3935->cs_port, as3935->cs_pin, GPIO_PIN_RESET); @@ -54,7 +56,8 @@ uint8_t as3935_read(as3935_t *as3935, uint8_t reg) */ uint8_t as3935_write(as3935_t *as3935, uint8_t reg, uint8_t value) { - uint16_t tx_data = AS3935_WRITE_CMD | ((reg & 0b111111) << 8) | value; + uint16_t tx_data = AS3935_WRITE_CMD | ((reg & 0x3F) << 8) | + value; /* 0x3F = 0b111111*/ HAL_GPIO_WritePin(as3935->cs_port, as3935->cs_pin, GPIO_PIN_RESET); // HAL SPI wants an 8 bit array of length 2 for tx_data @@ -106,7 +109,7 @@ uint8_t as3935_set_AFE(as3935_t *as3935, uint8_t afe_setting) } // clear AFE_GB bits 5-1 and set it to new afe_setting value - current_reg &= 0b11000001; // clear bits 5-1 + current_reg &= 0xC1; // clear bits 5-1 (C1 = 0b11000001) current_reg |= (afe_setting << 1); return as3935_write(as3935, AS3935_AFE_GB, current_reg); @@ -129,7 +132,7 @@ uint8_t as3935_get_interrupt(as3935_t *as3935) } // return only interrupt bits - return int_reg & 0b00001111; + return int_reg & 0xF; // 0xF = 0b00001111 } /** @@ -149,7 +152,7 @@ uint8_t as3935_get_distance(as3935_t *as3935) } // read first 5 bits - return dist_reg & 0b111111; + return dist_reg & 0x3F; /* 0x3F = 0b00001111 */ } /** From e7723c11fffecb3ee67d8a013a9d1a7aea53f9a3 Mon Sep 17 00:00:00 2001 From: Daniel Nakhooda Date: Sun, 12 Oct 2025 17:35:08 -0400 Subject: [PATCH 3/8] another fix --- general/include/as3935.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/general/include/as3935.h b/general/include/as3935.h index 99355db0..c2e0122a 100644 --- a/general/include/as3935.h +++ b/general/include/as3935.h @@ -53,8 +53,8 @@ #define AS3935_INT_D 0x04 /* Disruptor detected */ #define AS3935_INT_L 0x08 /* Lightning detected */ -#define AS3935_AFE_INDOOR 0b10010 /* Indoor mode */ -#define AS3935_AFE_OUTDOOR 0b01110 /* Outdoor mode */ +#define AS3935_AFE_INDOOR 0x12 /* 0b10010 Indoor mode */ +#define AS3935_AFE_OUTDOOR 0xE /* 0b01110 Outdoor mode */ #define AS3935_READ_CMD \ 0x4000 /* 0b0100000000000000 First few bits for read command */ From 892f6bb3600a6c610001279e9f2ad3428a58e9d3 Mon Sep 17 00:00:00 2001 From: Daniel Nakhooda Date: Sun, 19 Oct 2025 18:11:42 -0400 Subject: [PATCH 4/8] have spi transmit do heavy work --- general/src/as3935.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/general/src/as3935.c b/general/src/as3935.c index bd4db67d..7c54a6e7 100644 --- a/general/src/as3935.c +++ b/general/src/as3935.c @@ -34,11 +34,9 @@ uint8_t as3935_read(as3935_t *as3935, uint8_t reg) ((reg & 0x3F) << 8); /* 0x3F = 0b111111*/ uint8_t rx_buf[2] = { 0 }; - HAL_GPIO_WritePin(as3935->cs_port, as3935->cs_pin, GPIO_PIN_RESET); // HAL SPI wants an 8 bit array of length 2 for tx_data HAL_StatusTypeDef status = HAL_SPI_TransmitReceive( as3935->hspi, (uint8_t *)&tx_data, &rx_buf, 2, HAL_MAX_DELAY); - HAL_GPIO_WritePin(as3935->cs_port, as3935->cs_pin, GPIO_PIN_SET); if (status != HAL_OK) { return 0xFF; From 8eaf5d25dd2ced72372dce1d7b8d05e3704bd272 Mon Sep 17 00:00:00 2001 From: Daniel Nakhooda Date: Sat, 25 Oct 2025 23:47:57 -0400 Subject: [PATCH 5/8] fixes --- general/src/as3935.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/general/src/as3935.c b/general/src/as3935.c index 7c54a6e7..b5d93161 100644 --- a/general/src/as3935.c +++ b/general/src/as3935.c @@ -13,11 +13,7 @@ void as3935_init(as3935_t *as3935, SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin) { as3935->hspi = hspi; - as3935->cs_port = cs_port; - as3935->cs_pin = cs_pin; as3935->address = 0; - - HAL_GPIO_WritePin(as3935->cs_port, as3935->cs_pin, GPIO_PIN_SET); } /** @@ -57,13 +53,11 @@ uint8_t as3935_write(as3935_t *as3935, uint8_t reg, uint8_t value) uint16_t tx_data = AS3935_WRITE_CMD | ((reg & 0x3F) << 8) | value; /* 0x3F = 0b111111*/ - HAL_GPIO_WritePin(as3935->cs_port, as3935->cs_pin, GPIO_PIN_RESET); // HAL SPI wants an 8 bit array of length 2 for tx_data HAL_StatusTypeDef status = HAL_SPI_Transmit( as3935->hspi, (uint8_t *)&tx_data, 2, HAL_MAX_DELAY); - HAL_GPIO_WritePin(as3935->cs_port, as3935->cs_pin, GPIO_PIN_SET); - return status == HAL_OK; + return status; } /** From d73b5a8586e6b1c5e45677c75027b03442d11b74 Mon Sep 17 00:00:00 2001 From: Daniel Nakhooda Date: Sun, 26 Oct 2025 16:53:12 -0400 Subject: [PATCH 6/8] small thing --- general/src/as3935.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/general/src/as3935.c b/general/src/as3935.c index b5d93161..04b03cbe 100644 --- a/general/src/as3935.c +++ b/general/src/as3935.c @@ -6,11 +6,8 @@ * * @param as3935 pointer to the allocated as3935_t struct * @param hspi pointer to the SPI_HandleTypeDef of the sensor - * @param cs_port port of the cs line in spi - * @param cs_pin pin of the cs line in spi */ -void as3935_init(as3935_t *as3935, SPI_HandleTypeDef *hspi, - GPIO_TypeDef *cs_port, uint16_t cs_pin) +void as3935_init(as3935_t *as3935, SPI_HandleTypeDef *hspi) { as3935->hspi = hspi; as3935->address = 0; From 45c5597ad6d054e3ba03a6f41c7a2110922b750a Mon Sep 17 00:00:00 2001 From: Daniel Nakhooda Date: Sun, 26 Oct 2025 16:53:57 -0400 Subject: [PATCH 7/8] another small thing --- general/include/as3935.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/general/include/as3935.h b/general/include/as3935.h index c2e0122a..f2303516 100644 --- a/general/include/as3935.h +++ b/general/include/as3935.h @@ -73,8 +73,7 @@ typedef struct { uint8_t address; } as3935_t; -void as3935_init(as3935_t *as3935, SPI_HandleTypeDef *hspi, - GPIO_TypeDef *cs_port, uint16_t cs_pin); +void as3935_init(as3935_t *as3935, SPI_HandleTypeDef *hspi); uint8_t as3935_read(as3935_t *as3935, uint8_t reg); uint8_t as3935_write(as3935_t *as3935, uint8_t reg, uint8_t value); From 255d73d9941e2228ad3c2687241558146950ec34 Mon Sep 17 00:00:00 2001 From: Daniel Nakhooda Date: Sun, 23 Nov 2025 00:01:04 -0500 Subject: [PATCH 8/8] small fix --- general/src/as3935.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/general/src/as3935.c b/general/src/as3935.c index 04b03cbe..4433b1da 100644 --- a/general/src/as3935.c +++ b/general/src/as3935.c @@ -29,7 +29,7 @@ uint8_t as3935_read(as3935_t *as3935, uint8_t reg) // HAL SPI wants an 8 bit array of length 2 for tx_data HAL_StatusTypeDef status = HAL_SPI_TransmitReceive( - as3935->hspi, (uint8_t *)&tx_data, &rx_buf, 2, HAL_MAX_DELAY); + as3935->hspi, (uint8_t *)&tx_data, rx_buf, 2, HAL_MAX_DELAY); if (status != HAL_OK) { return 0xFF; @@ -164,7 +164,7 @@ uint32_t as3935_get_energy(as3935_t *as3935) } // combine the three values. Only read the first 5 bits for energy_mm - energy = ((energy_mm & 0b11111) << 16) | (energy_m << 8) | energy_l; + energy = ((energy_mm & 0x1F) << 16) | (energy_m << 8) | energy_l; return energy; } \ No newline at end of file