Driver for the LSM303D digital compass. Permits access to all LSM303D registers by name, including multi-byte register sets, and has convenience methods for floating-point accelerometer and magnetometer reads scaled according to the device settings. Written from scratch for Mbed 6.0

Dependents:   UoY-32C-lab8-exercise UoY-32C-lab5-lsm303d

Driver for the LSM303D digital compass

Permits access to all LSM303D registers by name, including multi-byte register sets. Convenience methods are included for sensor reads, including floating-point accelerometer and magnetometer reads scaled according to the device settings, and for the more common settings (data rates and scales).

I2C connection only. Written from scratch for Mbed 6.0.

The interface is subject to minor changes with each version. Deprecation warnings will be issued where possible.

Defaults

The class constructor checks that an LSM303D is present on the I2C bus, then enables all sensors. The accelerometer and magnetometer update rates are both set to 50Hz, and the scales are left at their device defaults of +-2g for the accelerometer and +-4gauss for the magnetometer.

Basic usage

Some usage examples

#include "lsm303d.h"

LSM303D lsm303d(D14, D15);  // SDA and SCL pins for I2C

lsm303d.setAccelScale(LSM303D::AccelScale::scale_4g); // set +-4g range

lsm303d.INT1_enable_DRDY_A(); // set DRDY_A bit in CTRL3 register (enable INT1 on accel data ready)

short rawX = lsm303d.getAccelX(); // returns 16-bit signed result, unscaled

float x, y, z;
lsm303d.getAccelInto(x, y, z); // overwrites parameters, values in g

float mX = lsm303d.getMagX(); // returns value in gauss
Committer:
ajp109
Date:
Tue Jan 26 17:02:51 2021 +0000
Revision:
1:a74f8c175f6c
Parent:
0:b07c3d3e3d9c
Child:
2:27d2a1082572
RC1

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ajp109 0:b07c3d3e3d9c 1 #include "mbed.h"
ajp109 0:b07c3d3e3d9c 2
ajp109 0:b07c3d3e3d9c 3 typedef unsigned char u8;
ajp109 0:b07c3d3e3d9c 4 typedef signed short i16;
ajp109 0:b07c3d3e3d9c 5 typedef unsigned short u16;
ajp109 0:b07c3d3e3d9c 6
ajp109 0:b07c3d3e3d9c 7 #pragma pack(push)
ajp109 0:b07c3d3e3d9c 8 #pragma pack(1)
ajp109 0:b07c3d3e3d9c 9 typedef struct {
ajp109 0:b07c3d3e3d9c 10 u8 x;
ajp109 0:b07c3d3e3d9c 11 u8 y;
ajp109 0:b07c3d3e3d9c 12 u8 z;
ajp109 0:b07c3d3e3d9c 13 } u8_3;
ajp109 0:b07c3d3e3d9c 14 typedef struct {
ajp109 0:b07c3d3e3d9c 15 i16 x;
ajp109 0:b07c3d3e3d9c 16 i16 y;
ajp109 0:b07c3d3e3d9c 17 i16 z;
ajp109 0:b07c3d3e3d9c 18 } i16_3;
ajp109 0:b07c3d3e3d9c 19 #pragma pack(pop)
ajp109 0:b07c3d3e3d9c 20
ajp109 0:b07c3d3e3d9c 21 class LSM303D {
ajp109 0:b07c3d3e3d9c 22
ajp109 1:a74f8c175f6c 23 friend class AccelScaleOption;
ajp109 1:a74f8c175f6c 24 friend class MagScaleOption;
ajp109 0:b07c3d3e3d9c 25
ajp109 0:b07c3d3e3d9c 26 unsigned char const addr_8bit_;
ajp109 0:b07c3d3e3d9c 27 unsigned char accel_scale_;
ajp109 0:b07c3d3e3d9c 28 unsigned char mag_scale_;
ajp109 0:b07c3d3e3d9c 29 I2C i2c_;
ajp109 0:b07c3d3e3d9c 30
ajp109 0:b07c3d3e3d9c 31 template <class T>
ajp109 0:b07c3d3e3d9c 32 class Register {
ajp109 1:a74f8c175f6c 33 friend class LSM303D;
ajp109 0:b07c3d3e3d9c 34 protected:
ajp109 0:b07c3d3e3d9c 35 unsigned char addr_;
ajp109 1:a74f8c175f6c 36 LSM303D &parent_;
ajp109 0:b07c3d3e3d9c 37 Register(LSM303D &parent, unsigned char addr) :
ajp109 1:a74f8c175f6c 38 parent_(parent),
ajp109 1:a74f8c175f6c 39 addr_(addr | (sizeof(T)>1 ? 0x80 : 0x00)) {}
ajp109 0:b07c3d3e3d9c 40 virtual T read() const {
ajp109 0:b07c3d3e3d9c 41 T result;
ajp109 1:a74f8c175f6c 42 parent_.i2c_.lock();
ajp109 0:b07c3d3e3d9c 43 parent_.i2c_.write(parent_.addr_8bit_, (char *)&addr_, 1);
ajp109 0:b07c3d3e3d9c 44 parent_.i2c_.read(parent_.addr_8bit_, (char *)&result, sizeof(T));
ajp109 1:a74f8c175f6c 45 parent_.i2c_.unlock();
ajp109 0:b07c3d3e3d9c 46 return result;
ajp109 0:b07c3d3e3d9c 47 }
ajp109 1:a74f8c175f6c 48 inline operator T() const {
ajp109 0:b07c3d3e3d9c 49 return read();
ajp109 0:b07c3d3e3d9c 50 }
ajp109 0:b07c3d3e3d9c 51 };
ajp109 0:b07c3d3e3d9c 52
ajp109 0:b07c3d3e3d9c 53 template<class T>
ajp109 0:b07c3d3e3d9c 54 class RWRegister : public Register<T> {
ajp109 1:a74f8c175f6c 55 friend class LSM303D;
ajp109 0:b07c3d3e3d9c 56 using Register<T>::parent_;
ajp109 0:b07c3d3e3d9c 57 using Register<T>::addr_;
ajp109 1:a74f8c175f6c 58 private:
ajp109 0:b07c3d3e3d9c 59 mutable T cache_;
ajp109 0:b07c3d3e3d9c 60 mutable bool cached_;
ajp109 1:a74f8c175f6c 61 protected:
ajp109 0:b07c3d3e3d9c 62 RWRegister(LSM303D &parent, unsigned char addr) :
ajp109 0:b07c3d3e3d9c 63 Register<T>(parent, addr), cached_(false) {}
ajp109 1:a74f8c175f6c 64 void write(T const &data) {
ajp109 0:b07c3d3e3d9c 65 char packet[sizeof(T)+1];
ajp109 0:b07c3d3e3d9c 66 packet[0] = addr_;
ajp109 0:b07c3d3e3d9c 67 memcpy(&packet[1], &data, sizeof(T));
ajp109 1:a74f8c175f6c 68 cache_ = data;
ajp109 1:a74f8c175f6c 69 cached_ = true;
ajp109 1:a74f8c175f6c 70 parent_.i2c_.lock();
ajp109 0:b07c3d3e3d9c 71 parent_.i2c_.write(parent_.addr_8bit_, packet, sizeof(T)+1);
ajp109 1:a74f8c175f6c 72 parent_.i2c_.unlock();
ajp109 0:b07c3d3e3d9c 73 }
ajp109 0:b07c3d3e3d9c 74 virtual T read() const {
ajp109 0:b07c3d3e3d9c 75 if (!cached_) {
ajp109 0:b07c3d3e3d9c 76 cache_ = Register<T>::read();
ajp109 0:b07c3d3e3d9c 77 cached_ = true;
ajp109 0:b07c3d3e3d9c 78 }
ajp109 0:b07c3d3e3d9c 79 return cache_;
ajp109 0:b07c3d3e3d9c 80 }
ajp109 1:a74f8c175f6c 81 inline RWRegister & operator= (T const &data) {
ajp109 0:b07c3d3e3d9c 82 write(data);
ajp109 0:b07c3d3e3d9c 83 return *this;
ajp109 0:b07c3d3e3d9c 84 }
ajp109 1:a74f8c175f6c 85 inline RWRegister & operator= (int const &data) {
ajp109 1:a74f8c175f6c 86 write(T(data));
ajp109 1:a74f8c175f6c 87 return *this;
ajp109 1:a74f8c175f6c 88 }
ajp109 1:a74f8c175f6c 89 inline RWRegister & operator|= (T const &data) {
ajp109 1:a74f8c175f6c 90 write(cache_ | data);
ajp109 1:a74f8c175f6c 91 return *this;
ajp109 1:a74f8c175f6c 92 }
ajp109 1:a74f8c175f6c 93 inline RWRegister & operator|= (int const &data) {
ajp109 1:a74f8c175f6c 94 write(cache_ | T(data));
ajp109 1:a74f8c175f6c 95 return *this;
ajp109 1:a74f8c175f6c 96 }
ajp109 1:a74f8c175f6c 97 inline RWRegister & operator&= (T const &data) {
ajp109 1:a74f8c175f6c 98 write(cache_ & data);
ajp109 1:a74f8c175f6c 99 return *this;
ajp109 1:a74f8c175f6c 100 }
ajp109 1:a74f8c175f6c 101 inline RWRegister & operator&= (int const &data) {
ajp109 1:a74f8c175f6c 102 write(cache_ & T(data));
ajp109 0:b07c3d3e3d9c 103 return *this;
ajp109 0:b07c3d3e3d9c 104 }
ajp109 0:b07c3d3e3d9c 105 };
ajp109 0:b07c3d3e3d9c 106
ajp109 1:a74f8c175f6c 107 template <class T>
ajp109 1:a74f8c175f6c 108 class Option {
ajp109 1:a74f8c175f6c 109 friend class LSM303D;
ajp109 1:a74f8c175f6c 110 protected:
ajp109 1:a74f8c175f6c 111 T const bits_;
ajp109 1:a74f8c175f6c 112 RWRegister<T> & reg_;
ajp109 1:a74f8c175f6c 113 Option(RWRegister<T> & reg, int bits) :
ajp109 1:a74f8c175f6c 114 reg_(reg), bits_(T(bits)) {}
ajp109 1:a74f8c175f6c 115 public:
ajp109 1:a74f8c175f6c 116 inline void operator() () const { reg_ |= bits_; };
ajp109 1:a74f8c175f6c 117 inline void operator() (bool sr) const
ajp109 1:a74f8c175f6c 118 { if (sr) reg_ |= bits_; else reg_ &= ~bits_; };
ajp109 1:a74f8c175f6c 119 };
ajp109 1:a74f8c175f6c 120
ajp109 1:a74f8c175f6c 121 protected:
ajp109 1:a74f8c175f6c 122 const Register <i16_3> OUT_M;
ajp109 1:a74f8c175f6c 123 const Register <i16_3> OFFSET_M;
ajp109 1:a74f8c175f6c 124 const Register <u8_3> REFERENCE;
ajp109 1:a74f8c175f6c 125 const Register <i16_3> OUT_A;
ajp109 1:a74f8c175f6c 126
ajp109 0:b07c3d3e3d9c 127 public:
ajp109 1:a74f8c175f6c 128 const Register <i16> TEMP_OUT;
ajp109 1:a74f8c175f6c 129 const Register <u8> STATUS_M;
ajp109 1:a74f8c175f6c 130 const Register <i16> OUT_X_M;
ajp109 1:a74f8c175f6c 131 const Register <i16> OUT_Y_M;
ajp109 1:a74f8c175f6c 132 const Register <i16> OUT_Z_M;
ajp109 1:a74f8c175f6c 133 const Register <u8> WHO_AM_I;
ajp109 1:a74f8c175f6c 134 const Register <u8> INT_SRC_M;
ajp109 1:a74f8c175f6c 135 const Register <i16> OFFSET_X_M;
ajp109 1:a74f8c175f6c 136 const Register <i16> OFFSET_Y_M;
ajp109 1:a74f8c175f6c 137 const Register <i16> OFFSET_Z_M;
ajp109 1:a74f8c175f6c 138 const Register <u8> STATUS_A;
ajp109 1:a74f8c175f6c 139 const Register <i16> OUT_X_A;
ajp109 1:a74f8c175f6c 140 const Register <i16> OUT_Y_A;
ajp109 1:a74f8c175f6c 141 const Register <i16> OUT_Z_A;
ajp109 1:a74f8c175f6c 142 const Register <u8> FIFO_SRC;
ajp109 1:a74f8c175f6c 143 const Register <u8> IG_SRC1;
ajp109 1:a74f8c175f6c 144 const Register <u8> IG_SRC2;
ajp109 1:a74f8c175f6c 145 const Register <u8> CLICK_SRC;
ajp109 1:a74f8c175f6c 146
ajp109 1:a74f8c175f6c 147 RWRegister <u8> INT_CTRL_M;
ajp109 1:a74f8c175f6c 148 RWRegister <u16> INT_THS_M;
ajp109 1:a74f8c175f6c 149 RWRegister <u8> REFERENCE_X;
ajp109 1:a74f8c175f6c 150 RWRegister <u8> REFERENCE_Y;
ajp109 1:a74f8c175f6c 151 RWRegister <u8> REFERENCE_Z;
ajp109 1:a74f8c175f6c 152 RWRegister <u8> CTRL0;
ajp109 1:a74f8c175f6c 153 RWRegister <u8> CTRL1;
ajp109 1:a74f8c175f6c 154 RWRegister <u8> CTRL2;
ajp109 1:a74f8c175f6c 155 RWRegister <u8> CTRL3;
ajp109 1:a74f8c175f6c 156 RWRegister <u8> CTRL4;
ajp109 1:a74f8c175f6c 157 RWRegister <u8> CTRL5;
ajp109 1:a74f8c175f6c 158 RWRegister <u8> CTRL6;
ajp109 1:a74f8c175f6c 159 RWRegister <u8> CTRL7;
ajp109 1:a74f8c175f6c 160 RWRegister <u8> FIFO_CTRL;
ajp109 1:a74f8c175f6c 161 RWRegister <u8> IG_CFG1;
ajp109 1:a74f8c175f6c 162 RWRegister <u8> IG_THS1;
ajp109 1:a74f8c175f6c 163 RWRegister <u8> IG_DUR1;
ajp109 1:a74f8c175f6c 164 RWRegister <u8> IG_CFG2;
ajp109 1:a74f8c175f6c 165 RWRegister <u8> IG_THS2;
ajp109 1:a74f8c175f6c 166 RWRegister <u8> IG_DUR2;
ajp109 1:a74f8c175f6c 167 RWRegister <u8> CLICK_CFG;
ajp109 1:a74f8c175f6c 168 RWRegister <u8> CLICK_THS;
ajp109 1:a74f8c175f6c 169 RWRegister <u8> TIME_LIMIT;
ajp109 1:a74f8c175f6c 170 RWRegister <u8> TIME_LATENCY;
ajp109 1:a74f8c175f6c 171 RWRegister <u8> TIME_WINDOW;
ajp109 1:a74f8c175f6c 172 RWRegister <u8> Act_THS;
ajp109 1:a74f8c175f6c 173 RWRegister <u8> Act_DUR;
ajp109 1:a74f8c175f6c 174
ajp109 1:a74f8c175f6c 175 // CTRL1
ajp109 1:a74f8c175f6c 176 enum class AccelRate {
ajp109 1:a74f8c175f6c 177 rate_3_125Hz = 0x10,
ajp109 1:a74f8c175f6c 178 rate_6_25Hz = 0x20,
ajp109 1:a74f8c175f6c 179 rate_12_5Hz = 0x30,
ajp109 1:a74f8c175f6c 180 rate_25Hz = 0x40,
ajp109 1:a74f8c175f6c 181 rate_50Hz = 0x50,
ajp109 1:a74f8c175f6c 182 rate_100Hz = 0x60,
ajp109 1:a74f8c175f6c 183 rate_200Hz = 0x70,
ajp109 1:a74f8c175f6c 184 rate_400Hz = 0x80,
ajp109 1:a74f8c175f6c 185 rate_800Hz = 0x90,
ajp109 1:a74f8c175f6c 186 rate_1600Hz = 0xA0
ajp109 1:a74f8c175f6c 187 };
ajp109 1:a74f8c175f6c 188 void setAccelRate(AccelRate const &rate);
ajp109 1:a74f8c175f6c 189
ajp109 1:a74f8c175f6c 190 const Option<u8> accel_enableX;
ajp109 1:a74f8c175f6c 191 const Option<u8> accel_enableY;
ajp109 1:a74f8c175f6c 192 const Option<u8> accel_enableZ;
ajp109 1:a74f8c175f6c 193 const Option<u8> accel_enableAll;
ajp109 1:a74f8c175f6c 194
ajp109 1:a74f8c175f6c 195 // CTRL2
ajp109 1:a74f8c175f6c 196 enum class AccelScale {
ajp109 1:a74f8c175f6c 197 scale_2g = 0x00,
ajp109 1:a74f8c175f6c 198 scale_4g = 0x08,
ajp109 1:a74f8c175f6c 199 scale_6g = 0x10,
ajp109 1:a74f8c175f6c 200 scale_8g = 0x18,
ajp109 1:a74f8c175f6c 201 scale_16g = 0x20
ajp109 1:a74f8c175f6c 202 };
ajp109 1:a74f8c175f6c 203 void setAccelScale(AccelScale const &scale);
ajp109 1:a74f8c175f6c 204
ajp109 1:a74f8c175f6c 205 // CTRL3
ajp109 1:a74f8c175f6c 206 const Option<u8> INT1_enable_BOOT;
ajp109 1:a74f8c175f6c 207 const Option<u8> INT1_enable_CLICK;
ajp109 1:a74f8c175f6c 208 const Option<u8> INT1_enable_IG1;
ajp109 1:a74f8c175f6c 209 const Option<u8> INT1_enable_IG2;
ajp109 1:a74f8c175f6c 210 const Option<u8> INT1_enable_IGM;
ajp109 1:a74f8c175f6c 211 const Option<u8> INT1_enable_DRDY_A;
ajp109 1:a74f8c175f6c 212 const Option<u8> INT1_enable_DRDY_M;
ajp109 1:a74f8c175f6c 213 const Option<u8> INT1_enable_EMPTY;
ajp109 1:a74f8c175f6c 214
ajp109 1:a74f8c175f6c 215 // CTRL4 concerns INT2 which is not broken out on the Pimoroni board
ajp109 1:a74f8c175f6c 216
ajp109 1:a74f8c175f6c 217 // CTRL5
ajp109 1:a74f8c175f6c 218 const Option<u8> temp_enable;
ajp109 1:a74f8c175f6c 219 const Option<u8> LIR1_enable;
ajp109 1:a74f8c175f6c 220
ajp109 1:a74f8c175f6c 221 enum class MagRes {
ajp109 1:a74f8c175f6c 222 high = 0x60,
ajp109 1:a74f8c175f6c 223 low = 0x00,
ajp109 1:a74f8c175f6c 224 };
ajp109 1:a74f8c175f6c 225 void setMagRes(MagRes const &res);
ajp109 1:a74f8c175f6c 226
ajp109 1:a74f8c175f6c 227 enum class MagRate {
ajp109 1:a74f8c175f6c 228 rate_3_125Hz = 0x00,
ajp109 1:a74f8c175f6c 229 rate_6_25Hz = 0x04,
ajp109 1:a74f8c175f6c 230 rate_12_5Hz = 0x08,
ajp109 1:a74f8c175f6c 231 rate_25Hz = 0x0C,
ajp109 1:a74f8c175f6c 232 rate_50Hz = 0x10,
ajp109 1:a74f8c175f6c 233 rate_100Hz = 0x14
ajp109 1:a74f8c175f6c 234 };
ajp109 1:a74f8c175f6c 235 void setMagRate(MagRate const &rate);
ajp109 1:a74f8c175f6c 236
ajp109 1:a74f8c175f6c 237 // CTRL6
ajp109 1:a74f8c175f6c 238 enum class MagScale {
ajp109 1:a74f8c175f6c 239 scale_2gauss = 0x00,
ajp109 1:a74f8c175f6c 240 scale_4gauss = 0x20,
ajp109 1:a74f8c175f6c 241 scale_8gauss = 0x40,
ajp109 1:a74f8c175f6c 242 scale_12gauss = 0x60
ajp109 1:a74f8c175f6c 243 };
ajp109 1:a74f8c175f6c 244 void setMagScale(MagScale const &scale);
ajp109 1:a74f8c175f6c 245
ajp109 1:a74f8c175f6c 246 // CTRL7
ajp109 1:a74f8c175f6c 247 enum class MagMode {
ajp109 1:a74f8c175f6c 248 continuous = 0x00,
ajp109 1:a74f8c175f6c 249 single = 0x01,
ajp109 1:a74f8c175f6c 250 off = 0x02
ajp109 1:a74f8c175f6c 251 };
ajp109 1:a74f8c175f6c 252 void setMagMode(MagMode const &mode);
ajp109 0:b07c3d3e3d9c 253
ajp109 0:b07c3d3e3d9c 254 LSM303D(PinName sda, PinName scl, unsigned char i2c_addr = 0x1D);
ajp109 0:b07c3d3e3d9c 255
ajp109 1:a74f8c175f6c 256 inline i16 getRawAccelX() { return OUT_X_A; };
ajp109 1:a74f8c175f6c 257 inline i16 getRawAccelY() { return OUT_Y_A; };
ajp109 1:a74f8c175f6c 258 inline i16 getRawAccelZ() { return OUT_Z_A; };
ajp109 1:a74f8c175f6c 259 inline float getAccelX() { return (float)OUT_X_A / accel_scale_ / 32768; };
ajp109 1:a74f8c175f6c 260 inline float getAccelY() { return (float)OUT_Y_A / accel_scale_ / 32768; };
ajp109 1:a74f8c175f6c 261 inline float getAccelZ() { return (float)OUT_Z_A / accel_scale_ / 32768; };
ajp109 0:b07c3d3e3d9c 262 void getRawAccelInto(short &x, short &y, short &z);
ajp109 0:b07c3d3e3d9c 263 void getAccelInto(float &x, float &y, float &z);
ajp109 0:b07c3d3e3d9c 264
ajp109 1:a74f8c175f6c 265 inline i16 getRawMagX() { return OUT_X_M; };
ajp109 1:a74f8c175f6c 266 inline i16 getRawMagY() { return OUT_Y_M; };
ajp109 1:a74f8c175f6c 267 inline i16 getRawMagZ() { return OUT_Z_M; };
ajp109 1:a74f8c175f6c 268 inline float getMagX() { return (float)OUT_X_M / mag_scale_ / 32768; };
ajp109 1:a74f8c175f6c 269 inline float getMagY() { return (float)OUT_Y_M / mag_scale_ / 32768; };
ajp109 1:a74f8c175f6c 270 inline float getMagZ() { return (float)OUT_Z_M / mag_scale_ / 32768; };
ajp109 0:b07c3d3e3d9c 271 void getRawMagInto(short &x, short &y, short &z);
ajp109 0:b07c3d3e3d9c 272 void getMagInto(float &x, float &y, float &z);
ajp109 0:b07c3d3e3d9c 273
ajp109 1:a74f8c175f6c 274 inline float getTemp() { return TEMP_OUT / 8.0 + 25; };
ajp109 0:b07c3d3e3d9c 275
ajp109 0:b07c3d3e3d9c 276 };
ajp109 0:b07c3d3e3d9c 277