Mercurial > public > ostc4
diff Small_CPU/Src/compass.c @ 38:5f11787b4f42
include in ostc4 repository
author | heinrichsweikamp |
---|---|
date | Sat, 28 Apr 2018 11:52:34 +0200 |
parents | |
children | 6a6116d7b5bb |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Small_CPU/Src/compass.c Sat Apr 28 11:52:34 2018 +0200 @@ -0,0 +1,2222 @@ +/** + ****************************************************************************** + * @file compass.c + * @author heinrichs weikamp gmbh + * @date 27-March-2014 + * @version V0.2.0 + * @since 21-April-2016 + * @brief for Honeywell Compass and ST LSM303D + * + @verbatim + ============================================================================== + ##### How to use ##### + ============================================================================== + V0.1.0 09-March-2016 + V0.2.0 21-April-2016 Orientation fixed for LSM303D, + roll and pitch added to calibration output, + orientation double checked with datasheets and layout + as well as with value output during calibration + V0.2.1 19-May-2016 New date rate config and full-scale selection + + @endverbatim + ****************************************************************************** + * @attention + * + * <h2><center>© COPYRIGHT(c) 2016 heinrichs weikamp</center></h2> + * + ****************************************************************************** + */ + +#include <math.h> +#include <string.h> + +#include "compass.h" +#include "compass_LSM303D.h" +#include "compass_LSM303DLHC.h" + +#include "i2c.h" +#include "RTE_FlashAccess.h" // to store compass_calib_data + +#include "stm32f4xx_hal.h" + +#define MODE_LSM303DLHC +#define TEST_IF_HMC5883L +//#define COMPASS_DEACTIVATE + +/// split byte to bits +typedef struct{ +uint8_t bit0:1; ///< split byte to bits +uint8_t bit1:1; ///< split byte to bits +uint8_t bit2:1; ///< split byte to bits +uint8_t bit3:1; ///< split byte to bits +uint8_t bit4:1; ///< split byte to bits +uint8_t bit5:1; ///< split byte to bits +uint8_t bit6:1; ///< split byte to bits +uint8_t bit7:1; ///< split byte to bits +} ubit8_t; + + +/// split byte to bits +typedef union{ +ubit8_t ub; ///< split byte to bits +uint8_t uw; ///< split byte to bits +} bit8_Type; + + +/// split word to 2 bytes +typedef struct{ +uint8_t low; ///< split word to 2 bytes +uint8_t hi; ///< split word to 2 bytes +} two_byte; + + +/// split word to 2 bytes +typedef union{ +two_byte Byte; ///< split word to 2 bytes +uint16_t Word; ///< split word to 2 bytes +} tword; + + +/// split signed word to 2 bytes +typedef union{ +two_byte Byte; ///< split signed word to 2 bytes +int16_t Word; ///< split signed word to 2 bytes +} signed_tword; + + +/// split full32 to 2 words +typedef struct{ +uint16_t low16; ///< split word to 2 bytes +uint16_t hi16; ///< split word to 2 bytes +} two_word; + +typedef union{ +two_word Word16; ///< split word to 2 bytes +uint32_t Full32; ///< split word to 2 bytes +} tfull32; + + +/// crazy compass calibration stuff +typedef struct +{ +unsigned short int compass_N; +float Su, Sv, Sw; +float Suu, Svv, Sww, Suv, Suw, Svw; +float Suuu, Svvv, Swww; +float Suuv, Suuw, Svvu, Svvw, Swwu, Swwv; +} SCompassCalib; + + +#define Q_PI (18000) +#define Q_PIO2 (9000) + +#define HMC5883L (1) ///< id used with hardwareCompass +#define LSM303D (2) ///< id used with hardwareCompass +#define LSM303DLHC (3) ///< id used with hardwareCompass +#define COMPASS_NOT_RECOGNIZED (4) ///< id used with hardwareCompass + + +////////////////////////////////////////////////////////////////////////////// +// fifth order of polynomial approximation of atan(), giving 0.05 deg max error +// +#define K1 (5701) // Needs K1/2**16 +#define K2 (1645) // Needs K2/2**48 WAS NEGATIV +#define K3 ( 446) // Needs K3/2**80 + +const float PI = 3.14159265; ///< pi, used in compass_calc() + +typedef short int Int16; +typedef signed char Int8; +typedef Int16 Angle; + + +/// The (filtered) components of the magnetometer sensor +int16_t compass_DX_f; ///< output from sensor +int16_t compass_DY_f; ///< output from sensor +int16_t compass_DZ_f; ///< output from sensor + + +/// Found soft-iron calibration values, deduced from already filtered values +int16_t compass_CX_f; ///< calibration value +int16_t compass_CY_f; ///< calibration value +int16_t compass_CZ_f; ///< calibration value + + +/// The (filtered) components of the accelerometer sensor +int16_t accel_DX_f; ///< output from sensor +int16_t accel_DY_f; ///< output from sensor +int16_t accel_DZ_f; ///< output from sensor + + +/// The compass result values +float compass_heading; ///< the final result calculated in compass_calc() +float compass_roll; ///< the final result calculated in compass_calc() +float compass_pitch; ///< the final result calculated in compass_calc() + + +uint8_t compass_gain; ///< 7 on start, can be reduced during calibration + +uint8_t hardwareCompass = 0; ///< either HMC5883L or LSM303D or not defined yet ( = 0 ) + +/// LSM303D variables +uint8_t magDataBuffer[6]; ///< here raw data from LSM303D is stored, can be local +uint8_t accDataBuffer[6]; ///< here raw data from LSM303D is stored, can be local + +//uint16_t velMag = 0; +//uint16_t velAcc = 0; + +//uint16_t magODR[] = {31,62,125,250,500,1000,2000}; +//uint16_t accODR[] = {0,31,62,125,250,500,1000,2000,4000,8000,16000}; +//uint8_t fastest = 10; //no sensor is the fastest +//uint8_t datas1 = 0; +//uint8_t zoffFlag = 0; +//uint8_t sendFlag = 0; + + +// all by pixhawk code: + +// struct accel_scale _accel_scale; +unsigned _accel_range_m_s2; +float _accel_range_scale; +unsigned _accel_samplerate; +unsigned _accel_onchip_filter_bandwith; + +// struct mag_scale _mag_scale; +unsigned _mag_range_ga; +float _mag_range_scale; +unsigned _mag_samplerate; + +// default scale factors +float _accel_scale_x_offset = 0.0f; +float _accel_scale_x_scale = 1.0f; +float _accel_scale_y_offset = 0.0f; +float _accel_scale_y_scale = 1.0f; +float _accel_scale_z_offset = 0.0f; +float _accel_scale_z_scale = 1.0f; + +float _mag_scale_x_offset = 0.0f; +float _mag_scale_x_scale = 1.0f; +float _mag_scale_y_offset = 0.0f; +float _mag_scale_y_scale = 1.0f; +float _mag_scale_z_offset = 0.0f; +float _mag_scale_z_scale = 1.0f; + + +/* External function prototypes ----------------------------------------------*/ + +extern void copyCompassDataDuringCalibration(int16_t dx, int16_t dy, int16_t dz); + +/* Private function prototypes -----------------------------------------------*/ + +void compass_reset_calibration(SCompassCalib *g); +void compass_add_calibration(SCompassCalib *g); +void compass_solve_calibration(SCompassCalib *g); + +void compass_init_HMC5883L(uint8_t fast, uint8_t gain); +void compass_sleep_HMC5883L(void); +void compass_read_HMC5883L(void); + +void accelerator_init_MMA8452Q(void); +void accelerator_sleep_MMA8452Q(void); +void acceleration_read_MMA8452Q(void); + +void compass_init_LSM303D(uint8_t fast, uint8_t gain); +void compass_sleep_LSM303D(void); +void compass_read_LSM303D(void); +void acceleration_read_LSM303D(void); + +void compass_init_LSM303DLHC(uint8_t fast, uint8_t gain); +void compass_sleep_LSM303DLHC(void); +void compass_read_LSM303DLHC(void); +void acceleration_read_LSM303DLHC(void); + + +int LSM303D_accel_set_onchip_lowpass_filter_bandwidth(unsigned bandwidth); +int compass_calib_common(void); + +void compass_calc_roll_pitch_only(void); + +void rotate_mag_3f(float *x, float *y, float *z); +void rotate_accel_3f(float *x, float *y, float *z); + + +/* Exported functions --------------------------------------------------------*/ + + +// =============================================================================== +// compass_init +/// @brief This might be called several times with different gain values during calibration +/// On first call it figures out which hardware is integrated +/// +/// @param gain: 7 is max gain, compass_calib() might reduce it +// =============================================================================== + +uint8_t testCompassTypeDebug = 0xFF; + +void compass_init(uint8_t fast, uint8_t gain) +{ +// quick off +#ifdef COMPASS_DEACTIVATE + hardwareCompass = COMPASS_NOT_RECOGNIZED; +#endif + +// don't call again with fast, gain in calib mode etc. +// if unknown + if(hardwareCompass == COMPASS_NOT_RECOGNIZED) + { + return; + } + +// old code but without else + if(hardwareCompass == 0) + { + uint8_t data = WHO_AM_I; + I2C_Master_Transmit( DEVICE_COMPASS_303D, &data, 1); + I2C_Master_Receive( DEVICE_COMPASS_303D, &data, 1); + if(data == WHOIAM_VALUE) + hardwareCompass = LSM303D; +// else +// hardwareCompass = HMC5883L; + } + + +// könnte Probleme mit altem Chip machen +// beim 303D führt dieser Code dazu, dass WHOIAM_VALUE nicht geschickt wird!!! + +#ifdef MODE_LSM303DLHC + HAL_StatusTypeDef resultOfOperation = HAL_TIMEOUT; + + if(hardwareCompass == 0) + { + uint8_t data = DLHC_CTRL_REG1_A; + resultOfOperation = I2C_Master_Transmit( DEVICE_ACCELARATOR_303DLHC, &data, 1); + if(resultOfOperation == HAL_OK) + { + I2C_Master_Receive( DEVICE_ACCELARATOR_303DLHC, &data, 1); + testCompassTypeDebug = data; + if((data & 0x0f) == 0x07) + { + hardwareCompass = LSM303DLHC; + } + } + else + { + testCompassTypeDebug = 0xEE; + } + } + +#endif +/* + if(hardwareCompass == 0) + { + uint8_t data = WHO_AM_I; + I2C_Master_Transmit( DEVICE_COMPASS_303D, &data, 1); + I2C_Master_Receive( DEVICE_COMPASS_303D, &data, 1); + if(data == WHOIAM_VALUE) + hardwareCompass = LSM303D; + else + hardwareCompass = HMC5883L; + } +*/ +// was in else before ! + if(hardwareCompass == 0) + hardwareCompass = HMC5883L; + +#ifdef TEST_IF_HMC5883L + HAL_StatusTypeDef resultOfOperationHMC_MMA = HAL_TIMEOUT; + + if(hardwareCompass == HMC5883L) + { + uint8_t data = 0x2A; // CTRL_REG1 of DEVICE_ACCELARATOR_MMA8452Q + resultOfOperationHMC_MMA = I2C_Master_Transmit( DEVICE_ACCELARATOR_MMA8452Q, &data, 1); + if(resultOfOperationHMC_MMA == HAL_OK) + { + hardwareCompass = HMC5883L; // all fine, keep it + } + else + { + hardwareCompass = COMPASS_NOT_RECOGNIZED; + testCompassTypeDebug = 0xEC; + } + } +#endif + + + if(hardwareCompass == LSM303DLHC) + { + compass_init_LSM303DLHC(fast, gain); + } + else + if(hardwareCompass == LSM303D) + { + compass_init_LSM303D(fast, gain); + } + else + if(hardwareCompass == HMC5883L) + { + compass_init_HMC5883L(fast, gain); + } + + tfull32 dataBlock[4]; + if(BFA_readLastDataBlock((uint32_t *)dataBlock) == BFA_OK) + { + compass_CX_f = dataBlock[0].Word16.low16; + compass_CY_f = dataBlock[0].Word16.hi16; + compass_CZ_f = dataBlock[1].Word16.low16; + } + +} + + +// =============================================================================== +// compass_calib +/// @brief with onchip_lowpass_filter configuration for accelerometer of LSM303D +// =============================================================================== +int compass_calib(void) +{ + if(hardwareCompass == LSM303DLHC) + { + return compass_calib_common(); // 170821 zur Zeit kein lowpass filtering gefunden, nur high pass auf dem Register ohne Erklärung + } + else + if(hardwareCompass == LSM303D) + { + LSM303D_accel_set_onchip_lowpass_filter_bandwidth(773); + int out = compass_calib_common(); + LSM303D_accel_set_onchip_lowpass_filter_bandwidth(LSM303D_ACCEL_DEFAULT_ONCHIP_FILTER_FREQ); + return out; + } + else + if(hardwareCompass == HMC5883L) + { + return compass_calib_common(); + } + else + { + return 0; // standard answer of compass_calib_common(); + } + + +} + + +// =============================================================================== +// compass_sleep +/// @brief low power mode +// =============================================================================== +void compass_sleep(void) +{ + if(hardwareCompass == LSM303DLHC) + { + compass_sleep_LSM303DLHC(); + } + else + if(hardwareCompass == LSM303D) + { + compass_sleep_LSM303D(); + } + else + if(hardwareCompass == HMC5883L) + { + compass_sleep_HMC5883L(); + } +} + + +// =============================================================================== +// compass_read +/// @brief reads magnetometer and accelerometer for LSM303D, +/// otherwise magnetometer only +// =============================================================================== +void compass_read(void) +{ + if(hardwareCompass == LSM303DLHC) + { + compass_read_LSM303DLHC(); + } + else + if(hardwareCompass == LSM303D) + { + compass_read_LSM303D(); + } + else + if(hardwareCompass == HMC5883L) + { + compass_read_HMC5883L(); + } +} + + +// =============================================================================== +// accelerator_init +/// @brief empty for for LSM303D +// =============================================================================== +void accelerator_init(void) +{ +// if((hardwareCompass != LSM303D) && (hardwareCompass != LSM303DLHC)) + if(hardwareCompass == HMC5883L) + accelerator_init_MMA8452Q(); +} + + +// =============================================================================== +// accelerator_sleep +/// @brief empty for for LSM303D +// =============================================================================== +void accelerator_sleep(void) +{ +// if((hardwareCompass != LSM303D) && (hardwareCompass != LSM303DLHC)) + if(hardwareCompass == HMC5883L) + accelerator_sleep_MMA8452Q(); +} + + +// =============================================================================== +// acceleration_read +/// @brief empty for for LSM303D +// =============================================================================== +void acceleration_read(void) +{ + if(hardwareCompass == LSM303DLHC) + { + acceleration_read_LSM303DLHC(); + } + else + if(hardwareCompass == LSM303D) + { + acceleration_read_LSM303D(); + } + else + if(hardwareCompass == HMC5883L) + { + acceleration_read_MMA8452Q(); + } +} + + +/* Private functions ---------------------------------------------------------*/ + +// =============================================================================== +// LSM303D_read_reg +/// @brief tiny helpers by pixhawk +// =============================================================================== +uint8_t LSM303D_read_reg(uint8_t addr) +{ + uint8_t data; + + I2C_Master_Transmit( DEVICE_COMPASS_303D, &addr, 1); + I2C_Master_Receive( DEVICE_COMPASS_303D, &data, 1); + return data; +} + + +// =============================================================================== +// LSM303D_write_reg +/// @brief tiny helpers by pixhawk +// =============================================================================== +void LSM303D_write_reg(uint8_t addr, uint8_t value) +{ + uint8_t data[2]; + + /* enable accel*/ + data[0] = addr; + data[1] = value; + I2C_Master_Transmit( DEVICE_COMPASS_303D, data, 2); +} + + +// =============================================================================== +// LSM303D_write_checked_reg +/// @brief tiny helpers by pixhawk. This runs unchecked at the moment. +// =============================================================================== +void LSM303D_write_checked_reg(uint8_t addr, uint8_t value) +{ + LSM303D_write_reg(addr, value); +} + + +// =============================================================================== +// LSM303D_modify_reg +/// @brief tiny helpers by pixhawk +// =============================================================================== +void LSM303D_modify_reg(unsigned reg, uint8_t clearbits, uint8_t setbits) +{ + uint8_t val; + + val = LSM303D_read_reg(reg); + val &= ~clearbits; + val |= setbits; + LSM303D_write_checked_reg(reg, val); +} + + + +// =============================================================================== +// LSM303DLHC_accelerator_read_req +/// @brief +// =============================================================================== +uint8_t LSM303DLHC_accelerator_read_req(uint8_t addr) +{ + uint8_t data; + + I2C_Master_Transmit( DEVICE_ACCELARATOR_303DLHC, &addr, 1); + I2C_Master_Receive( DEVICE_ACCELARATOR_303DLHC, &data, 1); + return data; +} + + +// =============================================================================== +// LSM303DLHC_accelerator_write_req +/// @brief +// =============================================================================== +void LSM303DLHC_accelerator_write_req(uint8_t addr, uint8_t value) +{ + uint8_t data[2]; + + /* enable accel*/ + data[0] = addr; + data[1] = value; + I2C_Master_Transmit( DEVICE_ACCELARATOR_303DLHC, data, 2); +} + +/* +// =============================================================================== +// LSM303D_accel_set_range +/// @brief tiny helpers by pixhawk +// =============================================================================== +int LSM303D_accel_set_range(unsigned max_g) +{ + uint8_t setbits = 0; + uint8_t clearbits = REG2_FULL_SCALE_BITS_A; + float new_scale_g_digit = 0.0f; + + if (max_g == 0) { + max_g = 16; + } + + if (max_g <= 2) { + _accel_range_m_s2 = 2.0f * LSM303D_ONE_G; + setbits |= REG2_FULL_SCALE_2G_A; + new_scale_g_digit = 0.061e-3f; + + } else if (max_g <= 4) { + _accel_range_m_s2 = 4.0f * LSM303D_ONE_G; + setbits |= REG2_FULL_SCALE_4G_A; + new_scale_g_digit = 0.122e-3f; + + } else if (max_g <= 6) { + _accel_range_m_s2 = 6.0f * LSM303D_ONE_G; + setbits |= REG2_FULL_SCALE_6G_A; + new_scale_g_digit = 0.183e-3f; + + } else if (max_g <= 8) { + _accel_range_m_s2 = 8.0f * LSM303D_ONE_G; + setbits |= REG2_FULL_SCALE_8G_A; + new_scale_g_digit = 0.244e-3f; + + } else if (max_g <= 16) { + _accel_range_m_s2 = 16.0f * LSM303D_ONE_G; + setbits |= REG2_FULL_SCALE_16G_A; + new_scale_g_digit = 0.732e-3f; + + } else { + return -1; + } + + _accel_range_scale = new_scale_g_digit * LSM303D_ONE_G; + + + LSM303D_modify_reg(ADDR_CTRL_REG2, clearbits, setbits); + + return 0; +} +*/ +/* +// =============================================================================== +// LSM303D_mag_set_range +/// @brief tiny helpers by pixhawk +// =============================================================================== +int LSM303D_mag_set_range(unsigned max_ga) +{ + uint8_t setbits = 0; + uint8_t clearbits = REG6_FULL_SCALE_BITS_M; + float new_scale_ga_digit = 0.0f; + + if (max_ga == 0) { + max_ga = 12; + } + + if (max_ga <= 2) { + _mag_range_ga = 2; + setbits |= REG6_FULL_SCALE_2GA_M; + new_scale_ga_digit = 0.080e-3f; + + } else if (max_ga <= 4) { + _mag_range_ga = 4; + setbits |= REG6_FULL_SCALE_4GA_M; + new_scale_ga_digit = 0.160e-3f; + + } else if (max_ga <= 8) { + _mag_range_ga = 8; + setbits |= REG6_FULL_SCALE_8GA_M; + new_scale_ga_digit = 0.320e-3f; + + } else if (max_ga <= 12) { + _mag_range_ga = 12; + setbits |= REG6_FULL_SCALE_12GA_M; + new_scale_ga_digit = 0.479e-3f; + + } else { + return -1; + } + + _mag_range_scale = new_scale_ga_digit; + + LSM303D_modify_reg(ADDR_CTRL_REG6, clearbits, setbits); + + return 0; +} +*/ + +// =============================================================================== +// LSM303D_accel_set_onchip_lowpass_filter_bandwidth +/// @brief tiny helpers by pixhawk +// =============================================================================== +int LSM303D_accel_set_onchip_lowpass_filter_bandwidth(unsigned bandwidth) +{ + uint8_t setbits = 0; + uint8_t clearbits = REG2_ANTIALIAS_FILTER_BW_BITS_A; + + if (bandwidth == 0) { + bandwidth = 773; + } + + if (bandwidth <= 50) { + setbits |= REG2_AA_FILTER_BW_50HZ_A; + _accel_onchip_filter_bandwith = 50; + + } else if (bandwidth <= 194) { + setbits |= REG2_AA_FILTER_BW_194HZ_A; + _accel_onchip_filter_bandwith = 194; + + } else if (bandwidth <= 362) { + setbits |= REG2_AA_FILTER_BW_362HZ_A; + _accel_onchip_filter_bandwith = 362; + + } else if (bandwidth <= 773) { + setbits |= REG2_AA_FILTER_BW_773HZ_A; + _accel_onchip_filter_bandwith = 773; + + } else { + return -1; + } + + LSM303D_modify_reg(ADDR_CTRL_REG2, clearbits, setbits); + + return 0; +} + + +// =============================================================================== +// LSM303D_accel_set_driver_lowpass_filter +/// @brief tiny helpers by pixhawk. This one is not used at the moment! +// =============================================================================== +int LSM303D_accel_set_driver_lowpass_filter(float samplerate, float bandwidth) +{ +/* + _accel_filter_x_set_cutoff_frequency(samplerate, bandwidth); + _accel_filter_y_set_cutoff_frequency(samplerate, bandwidth); + _accel_filter_z_set_cutoff_frequency(samplerate, bandwidth); +*/ + return 0; +} + +/* unused 170821 +// =============================================================================== +// LSM303D_accel_set_samplerate +/// @brief tiny helpers by pixhawk +// =============================================================================== +int LSM303D_accel_set_samplerate(unsigned frequency) +{ + uint8_t setbits = 0; + uint8_t clearbits = REG1_RATE_BITS_A; + +// if (frequency == 0 || frequency == ACCEL_SAMPLERATE_DEFAULT) { + frequency = 1600; +// } + + if (frequency <= 3) { + setbits |= REG1_RATE_3_125HZ_A; + _accel_samplerate = 3; + + } else if (frequency <= 6) { + setbits |= REG1_RATE_6_25HZ_A; + _accel_samplerate = 6; + + } else if (frequency <= 12) { + setbits |= REG1_RATE_12_5HZ_A; + _accel_samplerate = 12; + + } else if (frequency <= 25) { + setbits |= REG1_RATE_25HZ_A; + _accel_samplerate = 25; + + } else if (frequency <= 50) { + setbits |= REG1_RATE_50HZ_A; + _accel_samplerate = 50; + + } else if (frequency <= 100) { + setbits |= REG1_RATE_100HZ_A; + _accel_samplerate = 100; + + } else if (frequency <= 200) { + setbits |= REG1_RATE_200HZ_A; + _accel_samplerate = 200; + + } else if (frequency <= 400) { + setbits |= REG1_RATE_400HZ_A; + _accel_samplerate = 400; + + } else if (frequency <= 800) { + setbits |= REG1_RATE_800HZ_A; + _accel_samplerate = 800; + + } else if (frequency <= 1600) { + setbits |= REG1_RATE_1600HZ_A; + _accel_samplerate = 1600; + + } else { + return -1; + } + + LSM303D_modify_reg(ADDR_CTRL_REG1, clearbits, setbits); + return 0; +} +// =============================================================================== +// LSM303D_mag_set_samplerate +/// @brief tiny helpers by pixhawk +// =============================================================================== +int LSM303D_mag_set_samplerate(unsigned frequency) +{ + uint8_t setbits = 0; + uint8_t clearbits = REG5_RATE_BITS_M; + + if (frequency == 0) { + frequency = 100; + } + + if (frequency <= 3) { + setbits |= REG5_RATE_3_125HZ_M; + _mag_samplerate = 25; + + } else if (frequency <= 6) { + setbits |= REG5_RATE_6_25HZ_M; + _mag_samplerate = 25; + + } else if (frequency <= 12) { + setbits |= REG5_RATE_12_5HZ_M; + _mag_samplerate = 25; + + } else if (frequency <= 25) { + setbits |= REG5_RATE_25HZ_M; + _mag_samplerate = 25; + + } else if (frequency <= 50) { + setbits |= REG5_RATE_50HZ_M; + _mag_samplerate = 50; + + } else if (frequency <= 100) { + setbits |= REG5_RATE_100HZ_M; + _mag_samplerate = 100; + + } else { + return -1; + } + + LSM303D_modify_reg(ADDR_CTRL_REG5, clearbits, setbits); + return 0; +} +*/ + + +// rotate_mag_3f: nicht genutzt aber praktisch; rotate_accel_3f wird benutzt +// =============================================================================== +// rotate_mag_3f +/// @brief swap axis in convient way, by hw +/// @param *x raw input is set to *y input +/// @param *y raw input is set to -*x input +/// @param *z raw is not touched +// =============================================================================== +void rotate_mag_3f(float *x, float *y, float *z) +{ + return; +/* + *x = *x; // HMC: *x = -*y + *y = *y; // HMC: *y = *x // change 20.04.2016: zuvor *y = -*y + *z = *z; // HMC: *z = *z +*/ +} + + +// =============================================================================== +// rotate_accel_3f +/// @brief swap axis in convient way, by hw, same as MMA8452Q +/// @param *x raw input, output is with sign change +/// @param *y raw input, output is with sign change +/// @param *z raw input, output is with sign change +// =============================================================================== +void rotate_accel_3f(float *x, float *y, float *z) +{ + *x = -*x; + *y = -*y; + *z = -*z; + /* tested: + x = x, y =-y, z=-z: does not work with roll + x = x, y =y, z=-z: does not work with pitch + x = x, y =y, z=z: does not work at all + */ +} + + +// =============================================================================== +// compass_init_LSM303D by PIXhawk (LSM303D::reset()) +// https://raw.githubusercontent.com/PX4/Firmware/master/src/drivers/lsm303d/lsm303d.cpp +/// @brief The new ST 303D +/// This might be called several times with different gain values during calibration +/// but gain change is not supported at the moment. +/// +/// @param gain: 7 is max gain and set with here, compass_calib() might reduce it +// =============================================================================== + +//uint8_t testCompassLS303D[11]; + +void compass_init_LSM303D(uint8_t fast, uint8_t gain) +{ +// matthias version 160620 + if(fast == 0) + { + LSM303D_write_checked_reg(ADDR_CTRL_REG0, 0x00); + LSM303D_write_checked_reg(ADDR_CTRL_REG1, 0x3F); // mod 12,5 Hz 3 instead of 6,25 Hz 2 + LSM303D_write_checked_reg(ADDR_CTRL_REG2, 0xC0); + LSM303D_write_checked_reg(ADDR_CTRL_REG3, 0x00); + LSM303D_write_checked_reg(ADDR_CTRL_REG4, 0x00); + LSM303D_write_checked_reg(ADDR_CTRL_REG5, 0x68); // mod 12,5 Hz 8 instead of 6,25 Hz 4 + } + else + { + LSM303D_write_checked_reg(ADDR_CTRL_REG0, 0x00); + LSM303D_write_checked_reg(ADDR_CTRL_REG1, 0x6F); // 100 Hz + LSM303D_write_checked_reg(ADDR_CTRL_REG2, 0xC0); + LSM303D_write_checked_reg(ADDR_CTRL_REG3, 0x00); + LSM303D_write_checked_reg(ADDR_CTRL_REG4, 0x00); + LSM303D_write_checked_reg(ADDR_CTRL_REG5, 0x74); // 100 Hz + } + LSM303D_write_checked_reg(ADDR_CTRL_REG6, 0x00); + LSM303D_write_checked_reg(ADDR_CTRL_REG7, 0x00); + + /* +uint8_t data; +for(int i=0;i<11;i++) +{ + data = ADDR_INT_THS_L_M + i; + I2C_Master_Transmit( DEVICE_COMPASS_303D, &data, 1); + I2C_Master_Receive( DEVICE_COMPASS_303D, &testCompassLS303D[i], 1); +} +*/ + + return; +/* + LSM303D_accel_set_range(LSM303D_ACCEL_DEFAULT_RANGE_G); // modifies ADDR_CTRL_REG2 + LSM303D_accel_set_samplerate(LSM303D_ACCEL_DEFAULT_RATE); // modifies ADDR_CTRL_REG1 + + LSM303D_mag_set_range(LSM303D_MAG_DEFAULT_RANGE_GA); + LSM303D_mag_set_samplerate(LSM303D_MAG_DEFAULT_RATE); +*/ + +/* +// my stuff hw + // enable accel + LSM303D_write_checked_reg(ADDR_CTRL_REG1, + REG1_X_ENABLE_A | REG1_Y_ENABLE_A | REG1_Z_ENABLE_A | REG1_BDU_UPDATE | REG1_RATE_800HZ_A); + + // enable mag + LSM303D_write_checked_reg(ADDR_CTRL_REG7, REG7_CONT_MODE_M); + LSM303D_write_checked_reg(ADDR_CTRL_REG5, REG5_RES_HIGH_M | REG5_ENABLE_T); + LSM303D_write_checked_reg(ADDR_CTRL_REG3, 0x04); // DRDY on ACCEL on INT1 + LSM303D_write_checked_reg(ADDR_CTRL_REG4, 0x04); // DRDY on MAG on INT2 + + LSM303D_accel_set_range(LSM303D_ACCEL_DEFAULT_RANGE_G); + LSM303D_accel_set_samplerate(LSM303D_ACCEL_DEFAULT_RATE); + LSM303D_accel_set_driver_lowpass_filter((float)LSM303D_ACCEL_DEFAULT_RATE, (float)LSM303D_ACCEL_DEFAULT_DRIVER_FILTER_FREQ); + //LSM303D_accel_set_onchip_lowpass_filter_bandwidth(773); // factory setting + + // we setup the anti-alias on-chip filter as 50Hz. We believe + // this operates in the analog domain, and is critical for + // anti-aliasing. The 2 pole software filter is designed to + // operate in conjunction with this on-chip filter + if(fast) + LSM303D_accel_set_onchip_lowpass_filter_bandwidth(773); // factory setting + else + LSM303D_accel_set_onchip_lowpass_filter_bandwidth(LSM303D_ACCEL_DEFAULT_ONCHIP_FILTER_FREQ); + + + LSM303D_mag_set_range(LSM303D_MAG_DEFAULT_RANGE_GA); + LSM303D_mag_set_samplerate(LSM303D_MAG_DEFAULT_RATE); +*/ +} + + +// =============================================================================== +// compass_sleep_LSM303D +/// @brief The new compass chip, hopefully this works! +// =============================================================================== +void compass_sleep_LSM303D(void) +{ + LSM303D_write_checked_reg(ADDR_CTRL_REG1, 0x00); // CNTRL1: acceleration sensor Power-down mode + LSM303D_write_checked_reg(ADDR_CTRL_REG7, 0x02); // CNTRL7: magnetic sensor Power-down mode +} + + +// =============================================================================== +// acceleration_read_LSM303D +/// @brief The new LSM303D, code by pixhawk +/// +/// output is accel_DX_f, accel_DY_f, accel_DZ_f +// =============================================================================== +void acceleration_read_LSM303D(void) +{ + uint8_t data; + float xraw_f, yraw_f, zraw_f; + float accel_report_x, accel_report_y, accel_report_z; + + memset(accDataBuffer,0,6); + + accel_DX_f = 0; + accel_DY_f = 0; + accel_DZ_f = 0; + + for(int i=0;i<6;i++) + { + data = ADDR_OUT_X_L_A + i; + I2C_Master_Transmit( DEVICE_COMPASS_303D, &data, 1); + I2C_Master_Receive( DEVICE_COMPASS_303D, &accDataBuffer[i], 1); + } + + xraw_f = ((float)( (int16_t)((accDataBuffer[1] << 8) | (accDataBuffer[0])))); + yraw_f = ((float)( (int16_t)((accDataBuffer[3] << 8) | (accDataBuffer[2])))); + zraw_f = ((float)( (int16_t)((accDataBuffer[5] << 8) | (accDataBuffer[4])))); + + rotate_accel_3f(&xraw_f, &yraw_f, &zraw_f); + + // mh + accel_report_x = xraw_f; + accel_report_y = yraw_f; + accel_report_z = zraw_f; + + // my stuff +/* + accel_report_x = ((xraw_f * _accel_range_scale) - _accel_scale_x_offset) * _accel_scale_x_scale; + accel_report_y = ((yraw_f * _accel_range_scale) - _accel_scale_y_offset) * _accel_scale_y_scale; + accel_report_z = ((zraw_f * _accel_range_scale) - _accel_scale_z_offset) * _accel_scale_z_scale; +*/ + accel_DX_f = ((int16_t)(accel_report_x)); + accel_DY_f = ((int16_t)(accel_report_y)); + accel_DZ_f = ((int16_t)(accel_report_z)); +} +/* special code after accel_report_z = ... + * prior to output +// we have logs where the accelerometers get stuck at a fixed +// large value. We want to detect this and mark the sensor as +// being faulty + + if (fabsf(_last_accel[0] - x_in_new) < 0.001f && + fabsf(_last_accel[1] - y_in_new) < 0.001f && + fabsf(_last_accel[2] - z_in_new) < 0.001f && + fabsf(x_in_new) > 20 && + fabsf(y_in_new) > 20 && + fabsf(z_in_new) > 20) { + _constant_accel_count += 1; + + } else { + _constant_accel_count = 0; + } + + if (_constant_accel_count > 100) { + // we've had 100 constant accel readings with large + // values. The sensor is almost certainly dead. We + // will raise the error_count so that the top level + // flight code will know to avoid this sensor, but + // we'll still give the data so that it can be logged + // and viewed + perf_count(_bad_values); + _constant_accel_count = 0; + } + + _last_accel[0] = x_in_new; + _last_accel[1] = y_in_new; + _last_accel[2] = z_in_new; + + accel_report.x = _accel_filter_x.apply(x_in_new); + accel_report.y = _accel_filter_y.apply(y_in_new); + accel_report.z = _accel_filter_z.apply(z_in_new); + + math::Vector<3> aval(x_in_new, y_in_new, z_in_new); + math::Vector<3> aval_integrated; + + bool accel_notify = _accel_int.put(accel_report.timestamp, aval, aval_integrated, accel_report.integral_dt); + accel_report.x_integral = aval_integrated(0); + accel_report.y_integral = aval_integrated(1); + accel_report.z_integral = aval_integrated(2); +*/ + + +// =============================================================================== +// compass_read_LSM303D +/// @brief The new LSM303D, code by pixhawk +/// +/// output is compass_DX_f, compass_DY_f, compass_DZ_f +// =============================================================================== +void compass_read_LSM303D(void) +{ + uint8_t data; +// float xraw_f, yraw_f, zraw_f; +// float mag_report_x, mag_report_y, mag_report_z; + + memset(magDataBuffer,0,6); + + compass_DX_f = 0; + compass_DY_f = 0; + compass_DZ_f = 0; + + for(int i=0;i<6;i++) + { + data = ADDR_OUT_X_L_M + i; + I2C_Master_Transmit( DEVICE_COMPASS_303D, &data, 1); + I2C_Master_Receive( DEVICE_COMPASS_303D, &magDataBuffer[i], 1); + } + + // mh 160620 flip x and y if flip display + compass_DX_f = (((int16_t)((magDataBuffer[1] << 8) | (magDataBuffer[0])))); + compass_DY_f = (((int16_t)((magDataBuffer[3] << 8) | (magDataBuffer[2])))); + compass_DZ_f = (((int16_t)((magDataBuffer[5] << 8) | (magDataBuffer[4])))); + // no rotation + return; +/* + // my stuff + compass_DX_f = (((int16_t)((magDataBuffer[1] << 8) | (magDataBuffer[0]))) / 10) - 200; + compass_DY_f = (((int16_t)((magDataBuffer[3] << 8) | (magDataBuffer[2]))) / 10) - 200; + compass_DZ_f = (((int16_t)((magDataBuffer[5] << 8) | (magDataBuffer[4]))) / 10) - 200; +*/ + // old + /* + xraw_f = ((float)( (int16_t)((magDataBuffer[1] << 8) | (magDataBuffer[0])))); + yraw_f = ((float)( (int16_t)((magDataBuffer[3] << 8) | (magDataBuffer[2])))); + zraw_f = ((float)( (int16_t)((magDataBuffer[5] << 8) | (magDataBuffer[4])))); + + rotate_mag_3f(&xraw_f, &yraw_f, &zraw_f); + + compass_DX_f = (int16_t)((xraw_f * 0.1f) - 200.0f); + compass_DY_f = (int16_t)((yraw_f * 0.1f) - 200.0f); + compass_DZ_f = (int16_t)((zraw_f * 0.1f) - 200.0f); +*/ +/* + mag_report_x = ((xraw_f * _mag_range_scale) - _mag_scale_x_offset) * _mag_scale_x_scale; + mag_report_y = ((yraw_f * _mag_range_scale) - _mag_scale_y_offset) * _mag_scale_y_scale; + mag_report_z = ((zraw_f * _mag_range_scale) - _mag_scale_z_offset) * _mag_scale_z_scale; + + compass_DX_f = (int16_t)(mag_report_x * 1000.0f); // 1000.0 is just a wild guess by hw + compass_DY_f = (int16_t)(mag_report_y * 1000.0f); + compass_DZ_f = (int16_t)(mag_report_z * 1000.0f); +*/ +} + + +// =============================================================================== +// compass_init_LSM303DLHC +/// @brief The new ST 303DLHC 2017/2018 +/// This might be called several times with different gain values during calibration +/// but gain change is not supported at the moment. +/// parts from KOMPASS LSM303DLH-compass-app-note.pdf +/// +/// @param gain: +/// @param fast: +// =============================================================================== + + + +void compass_init_LSM303DLHC(uint8_t fast, uint8_t gain) +{ +// acceleration + // todo : BDU an (wie 303D) und high res, beides in REG4 + //LSM303D_write_checked_reg(DLHC_CTRL_REG2_A,0x00); // 0x00 default, hier könnte filter sein 0x8?80, cutoff freq. not beschrieben + + if(fast == 0) + { + LSM303DLHC_accelerator_write_req(DLHC_CTRL_REG1_A, 0x27); // 10 hz + } + else + { + LSM303DLHC_accelerator_write_req(DLHC_CTRL_REG1_A, 0x57); // 100 hz + } +// LSM303D_write_checked_reg(DLHC_CTRL_REG4_A, 0x88); // 0x88: BDU + HighRes, BDU ist doof! + LSM303D_write_checked_reg(DLHC_CTRL_REG4_A, 0x00); // 0x00 little-endian, ist's immer +// LSM303D_write_checked_reg(DLHC_CTRL_REG4_A, 0x08); // 0x08: HighRes + //LSM303D_write_checked_reg(DLHC_CTRL_REG4_A, 0x80); // + + +// compass + LSM303D_write_checked_reg(DLHC_CRA_REG_M,0x10); // 15 Hz + + if(fast == 0) + { + LSM303D_write_checked_reg(DLHC_CRA_REG_M,0x10); // 15 Hz + } + else + { + LSM303D_write_checked_reg(DLHC_CRA_REG_M,0x18); // 75 Hz + } + LSM303D_write_checked_reg(DLHC_CRB_REG_M,0x20); // 0x60: 2.5 Gauss ,0x40: +/-1.9 Gauss,0x20: +/-1.3 Gauss + LSM303D_write_checked_reg(DLHC_MR_REG_M,0x00); //continuous conversation + + + + return; + + +// LSM303D_write_checked_reg(,); +// LSM303D_write_checked_reg(DLHC_CTRL_REG1_A, 0x27); // 0x27 = acc. normal mode with ODR 50Hz - passt nicht mit datenblatt!! +// LSM303D_write_checked_reg(DLHC_CTRL_REG4_A, 0x40); // 0x40 = full scale range ±2 gauss in continuous data update mode and change the little-endian to a big-endian structure. + + if(fast == 0) + { + LSM303DLHC_accelerator_write_req(DLHC_CTRL_REG1_A, 0x27); // 0x27 = acc. normal mode, all axes, with ODR 10HZ laut LSM303DLHC, page 25/42 + // + //LSM303D_write_checked_reg(DLHC_CTRL_REG2_A,0x00); // 0x00 default, hier könnte filter sein 0x8?80, cutoff freq. not beschrieben + //LSM303D_write_checked_reg(DLHC_CTRL_REG3_A,0x00); // 0x00 default + // + LSM303DLHC_accelerator_write_req(DLHC_CTRL_REG4_A, 0x00); // 0x00 = ich glaube little-endian ist gut +// LSM303D_write_checked_reg(DLHC_CTRL_REG4_A, 0x40); // 0x00 = ich glaube little-endian ist gut + // + //LSM303D_write_checked_reg(DLHC_CTRL_REG5_A,0x00); // 0x00 default + //LSM303D_write_checked_reg(DLHC_CTRL_REG6_A,0x00); // 0x00 default + // magnetic sensor + LSM303D_write_checked_reg(DLHC_CRA_REG_M,0x10); // 15 Hz + } + else + { + LSM303DLHC_accelerator_write_req(DLHC_CTRL_REG1_A, 0x57); // 0x57 = acc. normal mode, all axes, with ODR 100HZ, LSM303DLHC, page 25/42 + // + //LSM303D_write_checked_reg(DLHC_CTRL_REG2_A,0x00); // 0x00 default, hier könnte filter sein 0x8?80, cutoff freq. not beschrieben + //LSM303D_write_checked_reg(DLHC_CTRL_REG3_A,0x00); // 0x00 default + // + LSM303DLHC_accelerator_write_req(DLHC_CTRL_REG4_A, 0x00); // 0x00 = ich glaube little-endian ist gut +// LSM303D_write_checked_reg(DLHC_CTRL_REG4_A, 0x40); // 0x00 = ich glaube little-endian ist gut + // + //LSM303D_write_checked_reg(DLHC_CTRL_REG5_A,0x00); // 0x00 default + //LSM303D_write_checked_reg(DLHC_CTRL_REG6_A,0x00); // 0x00 default + // magnetic sensor + LSM303D_write_checked_reg(DLHC_CRA_REG_M,0x18); // 75 Hz + } + LSM303D_write_checked_reg(DLHC_CRB_REG_M,0x02); // +/-1.9 Gauss + LSM303D_write_checked_reg(DLHC_MR_REG_M,0x00); //continuous conversation + + +/* +// matthias version 160620 + if(fast == 0) + { + LSM303D_write_checked_reg(ADDR_CTRL_REG0, 0x00); + LSM303D_write_checked_reg(ADDR_CTRL_REG1, 0x3F); // mod 12,5 Hz 3 instead of 6,25 Hz 2 + LSM303D_write_checked_reg(ADDR_CTRL_REG2, 0xC0); // anti alias 50 Hz (minimum) + LSM303D_write_checked_reg(ADDR_CTRL_REG3, 0x00); + LSM303D_write_checked_reg(ADDR_CTRL_REG4, 0x00); + LSM303D_write_checked_reg(ADDR_CTRL_REG5, 0x68); // mod 12,5 Hz 8 instead of 6,25 Hz 4 + } + else + { + LSM303D_write_checked_reg(ADDR_CTRL_REG0, 0x00); + LSM303D_write_checked_reg(ADDR_CTRL_REG1, 0x6F); // 100 Hz + LSM303D_write_checked_reg(ADDR_CTRL_REG2, 0xC0); + LSM303D_write_checked_reg(ADDR_CTRL_REG3, 0x00); + LSM303D_write_checked_reg(ADDR_CTRL_REG4, 0x00); + LSM303D_write_checked_reg(ADDR_CTRL_REG5, 0x74); // 100 Hz + } + LSM303D_write_checked_reg(ADDR_CTRL_REG6, 0x00); + LSM303D_write_checked_reg(ADDR_CTRL_REG7, 0x00); +*/ + return; +} + +// =============================================================================== +// compass_sleep_LSM303DLHC +/// @brief The new 2017/2018 compass chip. +// =============================================================================== +void compass_sleep_LSM303DLHC(void) +{ + LSM303DLHC_accelerator_write_req(DLHC_CTRL_REG1_A, 0x07); // CTRL_REG1_A: linear acceleration Power-down mode + LSM303D_write_checked_reg(DLHC_MR_REG_M, 0x02); // MR_REG_M: magnetic sensor Power-down mode +} + + +// =============================================================================== +// compass_read_LSM303DLHC +/// @brief The new 2017/2018 compass chip. +// =============================================================================== +void compass_read_LSM303DLHC(void) +{ + uint8_t data; + + memset(magDataBuffer,0,6); + + compass_DX_f = 0; + compass_DY_f = 0; + compass_DZ_f = 0; + + for(int i=0;i<6;i++) + { + data = DLHC_OUT_X_L_M + i; + I2C_Master_Transmit( DEVICE_COMPASS_303D, &data, 1); + I2C_Master_Receive( DEVICE_COMPASS_303D, &magDataBuffer[i], 1); + } + + // 303DLHC new order + compass_DX_f = (((int16_t)((magDataBuffer[0] << 8) | (magDataBuffer[1])))); + compass_DZ_f = (((int16_t)((magDataBuffer[2] << 8) | (magDataBuffer[3])))); + compass_DY_f = (((int16_t)((magDataBuffer[4] << 8) | (magDataBuffer[5])))); + + // no rotation, otherwise see compass_read_LSM303D() + return; +} + + +// =============================================================================== +// acceleration_read_LSM303DLHC +/// @brief The new 2017/2018 compass chip. +// =============================================================================== +void acceleration_read_LSM303DLHC(void) +{ + uint8_t data; + float xraw_f, yraw_f, zraw_f; + float accel_report_x, accel_report_y, accel_report_z; + + memset(accDataBuffer,0,6); + + accel_DX_f = 0; + accel_DY_f = 0; + accel_DZ_f = 0; + + for(int i=0;i<6;i++) + { + data = DLHC_OUT_X_L_A + i; + I2C_Master_Transmit( DEVICE_ACCELARATOR_303DLHC, &data, 1); + I2C_Master_Receive( DEVICE_ACCELARATOR_303DLHC, &accDataBuffer[i], 1); + } + + xraw_f = ((float)( (int16_t)((accDataBuffer[1] << 8) | (accDataBuffer[0])))); + yraw_f = ((float)( (int16_t)((accDataBuffer[3] << 8) | (accDataBuffer[2])))); + zraw_f = ((float)( (int16_t)((accDataBuffer[5] << 8) | (accDataBuffer[4])))); + + rotate_accel_3f(&xraw_f, &yraw_f, &zraw_f); + + // mh für 303D + accel_report_x = xraw_f; + accel_report_y = yraw_f; + accel_report_z = zraw_f; + + accel_DX_f = ((int16_t)(accel_report_x)); + accel_DY_f = ((int16_t)(accel_report_y)); + accel_DZ_f = ((int16_t)(accel_report_z)); +} + + +// -------------------------------------------------------------------------------- +// ----------EARLIER COMPONENTS --------------------------------------------------- +// -------------------------------------------------------------------------------- + +// =============================================================================== +// compass_init_HMC5883L +/// @brief The horrible Honeywell compass chip +/// This might be called several times during calibration +/// +/// @param fast: 1 is fast mode, 0 is normal mode +/// @param gain: 7 is max gain and set with here, compass_calib() might reduce it +// =============================================================================== +void compass_init_HMC5883L(uint8_t fast, uint8_t gain) +{ + uint8_t write_buffer[4]; + + compass_gain = gain; + uint16_t length = 0; + write_buffer[0] = 0x00; // 00 = config Register A + + if( fast ) + write_buffer[1] = 0x38; // 0b 0011 1000; // ConfigA: 75Hz, 2 Samples averaged + else + write_buffer[1] = 0x68; // 0b 0110 1000; // ConfigA: 3Hz, 8 Samples averaged + + switch(gain) + { + case 7: + write_buffer[2] = 0xE0; //0b 1110 0000; // ConfigB: gain + break; + case 6: + write_buffer[2] = 0xC0; //0b 1100 0000; // ConfigB: gain + break; + case 5: + write_buffer[2] = 0xA0; //0b 1010 0000; // ConfigB: gain + break; + case 4: + write_buffer[2] = 0x80; //0b 1000 0000; // ConfigB: gain + break; + case 3: + write_buffer[2] = 0x60; //0b 0110 0000; // ConfigB: gain + break; + case 2: + write_buffer[2] = 0x40; //0b 01000 0000; // ConfigB: gain + break; + case 1: + write_buffer[2] = 0x20; //0b 00100 0000; // ConfigB: gain + break; + case 0: + write_buffer[2] = 0x00; //0b 00000 0000; // ConfigB: gain + break; + } + write_buffer[3] = 0x00; // Mode: continuous mode + length = 4; + //hmc_twi_write(0); + I2C_Master_Transmit( DEVICE_COMPASS_HMC5883L, write_buffer, length); +} + + + +// =============================================================================== +// compass_sleep_HMC5883L +/// @brief Power-down mode for Honeywell compass chip +// =============================================================================== +void compass_sleep_HMC5883L(void) +{ + uint8_t write_buffer[4]; + uint16_t length = 0; + + write_buffer[0] = 0x00; // 00 = config Register A + write_buffer[1] = 0x68; // 0b 0110 1000; // ConfigA + write_buffer[2] = 0x20; // 0b 0010 0000; // ConfigB + write_buffer[3] = 0x02; // 0b 0000 0010; // Idle Mode + length = 4; + I2C_Master_Transmit( DEVICE_COMPASS_HMC5883L, write_buffer, length); +} + + +// =============================================================================== +// accelerator_init_MMA8452Q +/// @brief Power-down mode for acceleration chip used in combination with Honeywell compass +// =============================================================================== +void accelerator_init_MMA8452Q(void) +{ + uint8_t write_buffer[4]; + uint16_t length = 0; + //HAL_Delay(1); + //return; + write_buffer[0] = 0x0E; // XYZ_DATA_CFG + write_buffer[1] = 0x00;//0b00000000; // High pass Filter=0 , +/- 2g range + length = 2; + I2C_Master_Transmit( DEVICE_ACCELARATOR_MMA8452Q, write_buffer, length); + //HAL_Delay(1); + write_buffer[0] = 0x2A; // CTRL_REG1 + write_buffer[1] = 0x34; //0b00110100; // CTRL_REG1: 160ms data rate, St.By Mode, reduced noise mode + write_buffer[2] = 0x02; //0b00000010; // CTRL_REG2: High Res in Active mode + length = 3; + I2C_Master_Transmit( DEVICE_ACCELARATOR_MMA8452Q, write_buffer, length); + + //HAL_Delay(1); + //hw_delay_us(100); + write_buffer[0] = 0x2A; // CTRL_REG1 + write_buffer[1] = 0x35; //0b00110101; // CTRL_REG1: ... Active Mode + length = 2; + I2C_Master_Transmit( DEVICE_ACCELARATOR_MMA8452Q, write_buffer, length); +/* + HAL_Delay(6); + compass_read(); + HAL_Delay(1); + acceleration_read(); + + compass_calc(); +*/ +} + + +// =============================================================================== +// accelerator_sleep_MMA8452Q +/// @brief compass_sleep_HMC5883L +// =============================================================================== +void accelerator_sleep_MMA8452Q(void) +{ + uint16_t length = 0; + uint8_t write_buffer[4]; + + write_buffer[0] = 0x2A; // CTRL_REG1 + write_buffer[1] = 0x00; //0b00000000; // CTRL_REG1: Standby Mode + length = 2; + I2C_Master_Transmit( DEVICE_ACCELARATOR_MMA8452Q, write_buffer, length); +} + + +// =============================================================================== +// compass_read_HMC5883L +/// @brief The new ST 303D - get ALL data and store in static variables +/// +/// output is compass_DX_f, compass_DY_f, compass_DZ_f +// =============================================================================== +void compass_read_HMC5883L(void) +{ + uint8_t buffer[20]; + compass_DX_f = 0; + compass_DY_f = 0; + compass_DZ_f = 0; + uint8_t length = 0; + uint8_t read_buffer[6]; + signed_tword data; + for(int i = 0; i<6;i++) + read_buffer[i] = 0; + buffer[0] = 0x03; // 03 = Data Output X MSB Register + length = 1; + I2C_Master_Transmit( DEVICE_COMPASS_HMC5883L, buffer, length); + length = 6; + I2C_Master_Receive( DEVICE_COMPASS_HMC5883L, read_buffer, length); + + + data.Byte.hi = read_buffer[0]; + data.Byte.low = read_buffer[1]; + //Y = Z + compass_DY_f = - data.Word; + + data.Byte.hi = read_buffer[2]; + data.Byte.low = read_buffer[3]; + compass_DZ_f = data.Word; + + data.Byte.hi = read_buffer[4]; + data.Byte.low = read_buffer[5]; + //X = -Y + compass_DX_f = data.Word; +} + + +// =============================================================================== +// acceleration_read_MMA8452Q +/// @brief The old MMA8452Q used with the Honeywell compass +/// get the acceleration data and store in static variables +/// +/// output is accel_DX_f, accel_DY_f, accel_DZ_f +// =============================================================================== +void acceleration_read_MMA8452Q(void) +{ + uint8_t buffer[20]; + accel_DX_f = 0; + accel_DY_f = 0; + accel_DZ_f = 0; + uint8_t length = 0; +// bit8_Type status ; + uint8_t read_buffer[7]; + signed_tword data; + for(int i = 0; i<6;i++) + read_buffer[i] = 0; + buffer[0] = 0x00; // 03 = Data Output X MSB Register + length = 1; + I2C_Master_Transmit( DEVICE_ACCELARATOR_MMA8452Q, buffer, length); + length = 7; + I2C_Master_Receive( DEVICE_ACCELARATOR_MMA8452Q, read_buffer, length); + +// status.uw = read_buffer[0]; + data.Byte.hi = read_buffer[1]; + data.Byte.low = read_buffer[2]; + accel_DX_f =data.Word/16; + data.Byte.hi = read_buffer[3]; + data.Byte.low = read_buffer[4]; + accel_DY_f =data.Word/16; + data.Byte.hi = read_buffer[5]; + data.Byte.low = read_buffer[6]; + accel_DZ_f =data.Word/16; + + accel_DX_f *= -1; + accel_DY_f *= -1; + accel_DZ_f *= -1; +} + + +// =============================================================================== +// compass_calc_roll_pitch_only +/// @brief only the roll and pitch parts of compass_calc() +/// +/// input is accel_DX_f, accel_DY_f, accel_DZ_f +/// output is compass_pitch and compass_roll +// =============================================================================== +void compass_calc_roll_pitch_only(void) +{ + float sinPhi, cosPhi; + float Phi, Teta; + + //---- Calculate sine and cosine of roll angle Phi ----------------------- + Phi= atan2f(accel_DY_f, accel_DZ_f) ; + compass_roll = Phi * 180.0f /PI; + sinPhi = sinf(Phi); + cosPhi = cosf(Phi); + + //---- calculate sin and cosine of pitch angle Theta --------------------- + Teta = atanf(-(float)accel_DX_f/(accel_DY_f * sinPhi + accel_DZ_f * cosPhi)); + compass_pitch = Teta * 180.0f /PI; +} + + +// =============================================================================== +// compass_calc +/// @brief all the fancy stuff first implemented in OSTC3 +/// +/// input is compass_DX_f, compass_DY_f, compass_DZ_f, accel_DX_f, accel_DY_f, accel_DZ_f +/// and compass_CX_f, compass_CY_f, compass_CZ_f +/// output is compass_heading, compass_pitch and compass_roll +// =============================================================================== +void compass_calc(void) +{ + float sinPhi, cosPhi, sinTeta, cosTeta; + float Phi, Teta, Psi; + int16_t iBfx, iBfy; + int16_t iBpx, iBpy, iBpz; + + //---- Make hard iron correction ----------------------------------------- + // Measured magnetometer orientation, measured ok. + // From matthias drawing: (X,Y,Z) --> (X,Y,Z) : no rotation. + iBpx = compass_DX_f - compass_CX_f; // X + iBpy = compass_DY_f - compass_CY_f; // Y + iBpz = compass_DZ_f - compass_CZ_f; // Z + + //---- Calculate sine and cosine of roll angle Phi ----------------------- + //sincos(accel_DZ_f, accel_DY_f, &sin, &cos); + Phi= atan2f(accel_DY_f, accel_DZ_f) ; + compass_roll = Phi * 180.0f /PI; + sinPhi = sinf(Phi); + cosPhi = cosf(Phi); + + //---- rotate by roll angle (-Phi) --------------------------------------- + iBfy = iBpy * cosPhi - iBpz * sinPhi; + iBpz = iBpy * sinPhi + iBpz * cosPhi; + //Gz = imul(accel_DY_f, sin) + imul(accel_DZ_f, cos); + + //---- calculate sin and cosine of pitch angle Theta --------------------- + //sincos(Gz, -accel_DX_f, &sin, &cos); // NOTE: changed sin sign. + // Teta takes into account roll of computer and sends combination of Y and Z :-) understand now hw 160421 + Teta = atanf(-(float)accel_DX_f/(accel_DY_f * sinPhi + accel_DZ_f * cosPhi)); + compass_pitch = Teta * 180.0f /PI; + sinTeta = sinf(Teta); + cosTeta = cosf(Teta); + /* correct cosine if pitch not in range -90 to 90 degrees */ + if( cosTeta < 0 ) cosTeta = -cosTeta; + + ///---- de-rotate by pitch angle Theta ----------------------------------- + iBfx = iBpx * cosTeta + iBpz * sinTeta; + + //---- Detect uncalibrated compass --------------------------------------- + if( !compass_CX_f && !compass_CY_f && !compass_CZ_f ) + { + compass_heading = -1; + return; + } + + //---- calculate current yaw = e-compass angle Psi ----------------------- + // Result in degree (no need of 0.01 deg precision... + Psi = atan2f(-iBfy,iBfx); + compass_heading = Psi * 180.0f /PI; + // Result in 0..360 range: + if( compass_heading < 0 ) + compass_heading += 360; +} + + +/* +// =============================================================================== +// compass_calc_mini_during_calibration +/// @brief all the fancy stuff first implemented in OSTC3 +/// +/// input is accel_DX_f, accel_DY_f, accel_DZ_f +/// output is compass_pitch and compass_roll +// =============================================================================== +void compass_calc_mini_during_calibration(void) +{ + float sinPhi, cosPhi; + float Phi, Teta; + + //---- Calculate sine and cosine of roll angle Phi ----------------------- + //sincos(accel_DZ_f, accel_DY_f, &sin, &cos); + Phi= atan2f(accel_DY_f, accel_DZ_f) ; + compass_roll = Phi * 180.0f /PI; + sinPhi = sinf(Phi); + cosPhi = cosf(Phi); + + //---- calculate sin and cosine of pitch angle Theta --------------------- + //sincos(Gz, -accel_DX_f, &sin, &cos); // NOTE: changed sin sign. + Teta = atanf(-(float)accel_DX_f/(accel_DY_f * sinPhi + accel_DZ_f * cosPhi)); + compass_pitch = Teta * 180.0f /PI; +} +*/ + + +// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// // - Calibration - /////////////////////////////////////////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/* can be lost during sleep as those are reset with compass_reset_calibration() */ + +// =============================================================================== +// compass_reset_calibration +/// @brief all the fancy stuff first implemented in OSTC3 +/// +/// output is struct g and compass_CX_f, compass_CY_f, compass_CZ_f +/// +/// @param g: is a struct with crazy stuff like Suuu, Svvv, Svvu, etc. +/// all is set to zero here +// =============================================================================== +void compass_reset_calibration(SCompassCalib *g) +{ + g->compass_N = 0; + g->Su = g->Sv = g->Sw = 0.0; + g->Suu = g->Svv = g->Sww = g->Suv = g->Suw = g->Svw = 0.0; + g->Suuu = g->Svvv = g->Swww = 0.0; + g->Suuv = g->Suuw = g->Svvu = g->Svvw = g->Swwu = g->Swwv = 0.0; + compass_CX_f = compass_CY_f = compass_CZ_f = 0.0; +} + + +// =============================================================================== +// compass_add_calibration +/// @brief all the fancy stuff first implemented in OSTC3 +/// +/// input is compass_DX_f, compass_DY_f, compass_DZ_f +/// and compass_CX_f, compass_CY_f, compass_CZ_f +/// output is struct g +/// +/// @param g: is a struct with crazy stuff like Suuu, Svvv, Svvu, etc. +// =============================================================================== +void compass_add_calibration(SCompassCalib *g) +{ + float u, v, w; + + u = (compass_DX_f - compass_CX_f) / 32768.0f; + v = (compass_DY_f - compass_CY_f) / 32768.0f; + w = (compass_DZ_f - compass_CZ_f) / 32768.0f; + + g->compass_N++; + g->Su += u; + g->Sv += v; + g->Sw += w; + g->Suv += u*v; + g->Suw += u*w; + g->Svw += v*w; + g->Suu += u*u; + g->Suuu += u*u*u; + g->Suuv += v*u*u; + g->Suuw += w*u*u; + g->Svv += v*v; + g->Svvv += v*v*v; + g->Svvu += u*v*v; + g->Svvw += w*v*v; + g->Sww += w*w; + g->Swww += w*w*w; + g->Swwu += u*w*w; + g->Swwv += v*w*w; +} + +////////////////////////////////////////////////////////////////////////////// + +// =============================================================================== +// compass_solve_calibration +/// @brief all the fancy stuff first implemented in OSTC3 +/// +/// input is compass_CX_f, compass_CY_f, compass_CZ_f and g +/// output is struct g +/// +/// @param g: is a struct with crazy stuff like Suuu, Svvv, Svvu, etc. +// =============================================================================== +void compass_solve_calibration(SCompassCalib *g) +{ + float yu, yv, yw; + float delta; + float uc, vc, wc; + + + //---- Normalize partial sums -------------------------------------------- + // + // u, v, w should be centered on the mean value um, vm, wm: + // x = u + um, with um = Sx/N + // + // So: + // (u + um)**2 = u**2 + 2u*um + um**2 + // Su = 0, um = Sx/N + // Sxx = Suu + 2 um Su + N*(Sx/N)**2 = Suu + Sx**2/N + // Suu = Sxx - Sx**2/N + yu = g->Su/g->compass_N; + yv = g->Sv/g->compass_N; + yw = g->Sw/g->compass_N; + + g->Suu -= g->Su*yu; + g->Svv -= g->Sv*yv; + g->Sww -= g->Sw*yw; + + // (u + um)(v + vm) = uv + u vm + v um + um vm + // Sxy = Suv + N * um vm + // Suv = Sxy - N * (Sx/N)(Sy/N); + g->Suv -= g->Su*yv; + g->Suw -= g->Su*yw; + g->Svw -= g->Sv*yw; + + // (u + um)**3 = u**3 + 3 u**2 um + 3 u um**2 + um**3 + // Sxxx = Suuu + 3 um Suu + 3 um**2 Su + N.um**3 + // Su = 0, um = Sx/N: + // Suuu = Sxxx - 3 Sx*Suu/N - N.(Sx/N)**3 + // = Sxxx - 3 Sx*Suu/N - Sx**3/N**2 + + // (u + um)**2 (v + vm) = (u**2 + 2 u um + um**2)(v + vm) + // Sxxy = Suuv + vm Suu + 2 um (Suv + vm Su) + um**2 (Sv + N.vm) + // + // Su = 0, Sv = 0, vm = Sy/N: + // Sxxy = Suuv + vm Suu + 2 um Suv + N um**2 vm + // + // Suuv = Sxxy - (Sy/N) Suu - 2 (Sx/N) Suv - (Sx/N)**2 Sy + // = Sxxy - Suu*Sy/N - 2 Suv*Sx/N - Sx*Sx*Sy/N/N + // = Sxxy - (Suu + Sx*Sx/N)*Sy/N - 2 Suv*Sx/N + g->Suuu -= (3*g->Suu + g->Su*yu)*yu; + g->Suuv -= (g->Suu + g->Su*yu)*yv + 2*g->Suv*yu; + g->Suuw -= (g->Suu + g->Su*yu)*yw + 2*g->Suw*yu; + + g->Svvu -= (g->Svv + g->Sv*yv)*yu + 2*g->Suv*yv; + g->Svvv -= (3*g->Svv + g->Sv*yv)*yv; + g->Svvw -= (g->Svv + g->Sv*yv)*yw + 2*g->Svw*yv; + + g->Swwu -= (g->Sww + g->Sw*yw)*yu + 2*g->Suw*yw; + g->Swwv -= (g->Sww + g->Sw*yw)*yv + 2*g->Svw*yw; + g->Swww -= (3*g->Sww + g->Sw*yw)*yw; + + //---- Solve the system -------------------------------------------------- + // uc Suu + vc Suv + wc Suw = (Suuu + Svvu + Swwu) / 2 + // uc Suv + vc Svv + wc Svw = (Suuv + Svvv + Swwv) / 2 + // uc Suw + vc Svw + wc Sww = (Suuw + Svvw + Swww) / 2 + // Note this is symetric, with a positiv diagonal, hence + // it always have a uniq solution. + yu = 0.5f * (g->Suuu + g->Svvu + g->Swwu); + yv = 0.5f * (g->Suuv + g->Svvv + g->Swwv); + yw = 0.5f * (g->Suuw + g->Svvw + g->Swww); + delta = g->Suu * (g->Svv * g->Sww - g->Svw * g->Svw) + - g->Suv * (g->Suv * g->Sww - g->Svw * g->Suw) + + g->Suw * (g->Suv * g->Svw - g->Svv * g->Suw); + + uc = (yu * (g->Svv * g->Sww - g->Svw * g->Svw) + - yv * (g->Suv * g->Sww - g->Svw * g->Suw) + + yw * (g->Suv * g->Svw - g->Svv * g->Suw) )/delta; + vc = (g->Suu * ( yv * g->Sww - yw * g->Svw) + - g->Suv * ( yu * g->Sww - yw * g->Suw) + + g->Suw * ( yu * g->Svw - yv * g->Suw) )/delta; + wc = (g->Suu * (g->Svv * yw - g->Svw * yv ) + - g->Suv * (g->Suv * yw - g->Svw * yu ) + + g->Suw * (g->Suv * yv - g->Svv * yu ) )/delta; + + // Back to uncentered coordinates: + // xc = um + uc + uc = g->Su/g->compass_N + compass_CX_f/32768.0f + uc; + vc = g->Sv/g->compass_N + compass_CY_f/32768.0f + vc; + wc = g->Sw/g->compass_N + compass_CZ_f/32768.0f + wc; + + // Then save the new calibrated center: + compass_CX_f = (short)(32768 * uc); + compass_CY_f = (short)(32768 * vc); + compass_CZ_f = (short)(32768 * wc); +} + + +// =============================================================================== +// compass_calib +/// @brief the main loop for calibration +/// output is compass_CX_f, compass_CY_f, compass_CZ_f and g +/// 160704 removed -4096 limit for LSM303D +/// +/// @return always 0 +// =============================================================================== +int compass_calib_common(void) +{ + SCompassCalib g; + + // Starts with no calibration at all: + compass_reset_calibration(&g); + + int64_t tickstart = 0; + uint32_t ticks = 0; + uint32_t lasttick = 0; + tickstart = HAL_GetTick(); + // Eine Minute kalibrieren + while((ticks) < 60 * 1000) + { + compass_read(); + + acceleration_read(); + compass_calc_roll_pitch_only(); + + if((hardwareCompass == HMC5883L) + &&((compass_DX_f == -4096) || + (compass_DY_f == -4096) || + (compass_DZ_f == -4096) )) + { + if(compass_gain == 0) + return -1; + compass_gain--; + + compass_init(1, compass_gain); + compass_reset_calibration(&g); + //tickstart = HAL_GetTick(); + continue; + } + + copyCompassDataDuringCalibration(compass_DX_f,compass_DY_f,compass_DZ_f); + compass_add_calibration(&g); + HAL_Delay(1); + lasttick = HAL_GetTick(); + if(lasttick == 0) + { + tickstart = -ticks; + } + ticks = lasttick - tickstart; + } + + compass_solve_calibration(&g); + + tfull32 dataBlock[4]; + dataBlock[0].Word16.low16 = compass_CX_f; + dataBlock[0].Word16.hi16 = compass_CY_f; + dataBlock[1].Word16.low16 = compass_CZ_f; + dataBlock[1].Word16.hi16 = 0xFFFF; + dataBlock[2].Full32 = 0x7FFFFFFF; + dataBlock[3].Full32 = 0x7FFFFFFF; + BFA_writeDataBlock((uint32_t *)dataBlock); + + return 0; +} + +// //////////////////////////// TEST CODE ///////////////////////////////////// + + + +//#include <QtDebug> +//#include <stdio.h> +//#include <math.h> +/*#include <stdlib.h> + +short compass_DX_f, compass_DY_f, compass_DZ_f; +short compass_CX_f, compass_CY_f, compass_CZ_f; + +inline float uniform(void) { + return (rand() & 0xFFFF) / 65536.0f; +} +inline float sqr(float x) { + return x*x; +} + +static const float radius = 0.21f; +static const float cx = 0.79f, cy = -0.46f, cz = 0.24f; +// const float cx = 0, cy = 0, cz = 0; + +float check_compass_calib(void) +{ + + // Starts with no calibration at all: + compass_CX_f = compass_CY_f = compass_CZ_f = 0; + + // Try 10 recalibration passes: + for(int p=0; p<10; ++p) + { + compass_reset_calibration(); + + //---- Generates random points on a sphere ------------------------------- + // of radius,center (cx, cy, cz): + for(int i=0; i<100; ++i) + { + float theta = uniform()*360.0f; + float phi = uniform()*180.0f - 90.0f; + + float x = cx + radius * cosf(phi)*cosf(theta); + float y = cy + radius * cosf(phi)*sinf(theta); + float z = cz + radius * sinf(phi); + + compass_DX_f = (short)(32768 * x); + compass_DY_f = (short)(32768 * y); + compass_DZ_f = (short)(32768 * z); + compass_add_calibration(); + } + + compass_solve_calibration(); + //qDebug() << "Center =" +// << compass_CX_f/32768.0f +// << compass_CY_f/32768.0f +// << compass_CZ_f/32768.0f; + + float r2 = sqr(compass_CX_f/32768.0f - cx) + + sqr(compass_CY_f/32768.0f - cy) + + sqr(compass_CZ_f/32768.0f - cz); + if( r2 > 0.01f*0.01f ) + return sqrtf(r2); + } + return 0; +}*/ + + + +/* +void compass_read_LSM303D_v3(void) +{ + uint8_t data; + + memset(magDataBuffer,0,6); + + compass_DX_f = 0; + compass_DY_f = 0; + compass_DZ_f = 0; + + //magnetometer multi read, order xl,xh, yl,yh, zl, zh + data = REG_MAG_DATA_ADDR; + I2C_Master_Transmit( DEVICE_COMPASS_303D, &data, 1); + I2C_Master_Receive( DEVICE_COMPASS_303D, magDataBuffer, 6); + + compass_DX_f = ((int16_t)( (int16_t)((magDataBuffer[1] << 8) | (magDataBuffer[0])))); + compass_DY_f = ((int16_t)( (int16_t)((magDataBuffer[3] << 8) | (magDataBuffer[2])))); + compass_DZ_f = ((int16_t)( (int16_t)((magDataBuffer[5] << 8) | (magDataBuffer[4])))); + +// compass_DX_f = compass_DX_f * stat->sensitivity_mag; +// compass_DY_f = compass_DY_f * stat->sensitivity_mag; +// compass_DZ_f = compass_DZ_f * stat->sensitivity_mag; +} + + +// =============================================================================== +// compass_init_LSM303D by STMicroelectronics 2013 V1.0.5 2013/Oct/23 +/// @brief The new ST 303D +/// This might be called several times with different gain values during calibration +/// +/// @param gain: 7 is max gain and set with here, compass_calib() might reduce it +// =============================================================================== + +void compass_init_LSM303D_v3(uint8_t gain) +{ + uint8_t data[10]; + + // CNTRL1 + // 0011 acceleration data rate 0011 = 12.5 Hz (3.125 Hz - 1600 Hz) + // 0xxx block data update off + // x111 enable all three axes + + // CNTRL5 + // 0xxx xxxx temp sensor off + // x00x xxxx magnetic resolution + // xxx0 1xxx magentic data rate 01 = 6,25 Hz (3.125 Hz - 50 Hz (100 Hz)) + // xxxx xx00 latch irq requests off + + // CNTRL7 + // 00xx high pass filter mode, 00 normal mode + // xx0x filter for acceleration data bypassed + // xxx0 temperature sensor mode only off + // x0xx magnetic data low-power mode off + // xx00 magnetic sensor mode 00 = continous-conversion mode (default 10 power-down) + + data[0] = CNTRL0; + data[1] = 0x00; + I2C_Master_Transmit( DEVICE_COMPASS_303D, data, 2); + + // acc + data[0] = CNTRL1; + data[1] = 0x00; + data[2] = 0x0F; + data[3] = 0x00; + data[4] = 0x00; + I2C_Master_Transmit( DEVICE_COMPASS_303D, data, 5); + + // mag + data[0] = CNTRL3; + data[1] = 0x00; + data[2] = 0x00; + data[3] = 0x18; + data[4] = 0x20; + I2C_Master_Transmit( DEVICE_COMPASS_303D, data, 5); + + data[0] = CNTRL7; + data[1] = ((MSMS_MASK & CONTINUOS_CONVERSION) | + ((~MSMS_MASK) & CNTRL7_RESUME_VALUE)); + I2C_Master_Transmit( DEVICE_COMPASS_303D, data, 2); + + HAL_Delay(100); +} + + +// =============================================================================== +// compass_init_LSM303D by nordevx for arduion +/// @brief The new ST 303D +/// This might be called several times with different gain values during calibration +/// +/// @param gain: 7 is max gain and set with here, compass_calib() might reduce it +// =============================================================================== +void compass_init_LSM303D_v2(uint8_t gain) +{ + uint8_t data[2]; + + // CNTRL1 + // 0011 acceleration data rate 0011 = 12.5 Hz (3.125 Hz - 1600 Hz) + // 0xxx block data update off + // x111 enable all three axes + + // CNTRL5 + // 0xxx xxxx temp sensor off + // x00x xxxx magnetic resolution + // xxx0 1xxx magentic data rate 01 = 6,25 Hz (3.125 Hz - 50 Hz (100 Hz)) + // xxxx xx00 latch irq requests off + + // CNTRL7 + // 00xx high pass filter mode, 00 normal mode + // xx0x filter for acceleration data bypassed + // xxx0 temperature sensor mode only off + // x0xx magnetic data low-power mode off + // xx00 magnetic sensor mode 00 = continous-conversion mode (default 10 power-down) + + data[0] = CNTRL1; + data[1] = 0x37; //0b 0011 0111 + I2C_Master_Transmit( DEVICE_COMPASS_303D, data, 2); + + data[0] = CNTRL5; + data[1] = 0x08; // 0b 0000 1000 + I2C_Master_Transmit( DEVICE_COMPASS_303D, data, 2); + + data[0] = CNTRL7; + data[1] = 0x00; // 0b 0000 0000 + I2C_Master_Transmit( DEVICE_COMPASS_303D, data, 2); + + HAL_Delay(100); +} + + +// =============================================================================== +// compass_init_LSM303D_v1 by ST lsm303d.c +/// @brief The new ST 303D +/// This might be called several times with different gain values during calibration +/// +/// @param gain: 7 is max gain and set with here, compass_calib() might reduce it +// =============================================================================== +void compass_init_LSM303D_v1(uint8_t gain) +{ + uint8_t data; + + compass_gain = gain; + + memset(magDataBuffer,0,6); + memset(accDataBuffer,0,6); + + data = CNTRL5; + I2C_Master_Transmit( DEVICE_COMPASS_303D, &data, 1); + I2C_Master_Receive( DEVICE_COMPASS_303D, &data, 1); + data = (data & 0x1c) >> 2; + velMag = magODR[data]; + + data = CNTRL1; + I2C_Master_Transmit( DEVICE_COMPASS_303D, &data, 1); + I2C_Master_Receive( DEVICE_COMPASS_303D, &data, 1); + data = (data & 0xf0) >> 4; + velAcc = accODR[data]; + + data = CNTRL7; + I2C_Master_Transmit( DEVICE_COMPASS_303D, &data, 1); + I2C_Master_Receive( DEVICE_COMPASS_303D, &datas1, 1); + datas1 = (datas1 & 0x02); + + //if mag is not pd + //mag is bigger than gyro + if( (velMag < velAcc) || datas1 != 0 ) { + //acc is the biggest + fastest = ACC_IS_FASTEST; + } + else { + //acc is the biggest + fastest = MAG_IS_FASTEST; + } + + zoffFlag = 1; + + if( fastest == MAG_IS_FASTEST) + { + data = STATUS_REG_M; + I2C_Master_Transmit( DEVICE_COMPASS_303D, &data, 1); + I2C_Master_Receive( DEVICE_COMPASS_303D, &data, 1); + +// if(ValBit(data, ZYXMDA)) { + sendFlag = 1; +// } + + } + else if(fastest == ACC_IS_FASTEST) + { + data = STATUS_REG_A; + I2C_Master_Transmit( DEVICE_COMPASS_303D, &data, 1); + I2C_Master_Receive( DEVICE_COMPASS_303D, &data, 1); +// if(ValBit(data, DATAREADY_BIT)) { + sendFlag = 1; +// } + } +} + +// =============================================================================== +// compass_read_LSM303D +/// @brief The new LSM303D :-) +/// +/// output is compass_DX_f, compass_DY_f, compass_DZ_f, accel_DX_f, accel_DY_f, accel_DZ_f +// =============================================================================== +void compass_read_LSM303D_v2(void) +{ + uint8_t data; + + memset(magDataBuffer,0,6); + memset(accDataBuffer,0,6); + + compass_DX_f = 0; + compass_DY_f = 0; + compass_DZ_f = 0; + + accel_DX_f = 0; + accel_DY_f = 0; + accel_DZ_f = 0; + + //Accelerometer multi read, order xl,xh, yl,yh, zl, zh + data = REG_ACC_DATA_ADDR; + I2C_Master_Transmit( DEVICE_COMPASS_303D, &data, 1); + I2C_Master_Receive( DEVICE_COMPASS_303D, accDataBuffer, 6); + + //magnetometer multi read, order xl,xh, yl,yh, zl, zh + data = OUT_X_L_M; + I2C_Master_Transmit( DEVICE_COMPASS_303D, &data, 1); + I2C_Master_Receive( DEVICE_COMPASS_303D, magDataBuffer, 6); + + accel_DX_f = ((int16_t)( (int16_t)((accDataBuffer[1] << 8) | (accDataBuffer[0])))); + accel_DY_f = ((int16_t)( (int16_t)((accDataBuffer[3] << 8) | (accDataBuffer[2])))); + accel_DZ_f = ((int16_t)( (int16_t)((accDataBuffer[5] << 8) | (accDataBuffer[4])))); + +// accel_DX_f = accel_DX_f * stat->sensitivity_acc; +// accel_DY_f = accel_DY_f * stat->sensitivity_acc; +// accel_DZ_f = accel_DZ_f * stat->sensitivity_acc; + + + compass_DX_f = magDataBuffer[1]; + compass_DX_f *= 256; + compass_DX_f += magDataBuffer[0]; + + compass_DY_f = magDataBuffer[3]; + compass_DY_f *= 256; + compass_DY_f += magDataBuffer[2]; + + compass_DY_f = magDataBuffer[5]; + compass_DY_f *= 256; + compass_DY_f += magDataBuffer[4]; + +} + + +*/ +