You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
9.6 KiB

  1. # The MIT License (MIT)
  2. #
  3. # Copyright (c) 2017 Dave Astels for Adafruit Industries
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a copy
  6. # of this software and associated documentation files (the "Software"), to deal
  7. # in the Software without restriction, including without limitation the rights
  8. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. # copies of the Software, and to permit persons to whom the Software is
  10. # furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. # THE SOFTWARE.
  22. """
  23. `adafruit_LSM303`
  24. ====================================================
  25. CircuitPython driver for the LSM303 accelerometer + magnetometer.
  26. * Author(s): Dave Astels
  27. """
  28. try:
  29. import struct
  30. except ImportError:
  31. import ustruct as struct
  32. from micropython import const
  33. from adafruit_bus_device.i2c_device import I2CDevice
  34. __version__ = "1.1.0"
  35. __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_LSM303.git"
  36. # pylint: disable=bad-whitespace
  37. _ADDRESS_ACCEL = const(0x19) # (0x32 >> 1) // 0011001x
  38. _ADDRESS_MAG = const(0x1E) # (0x3C >> 1) // 0011110x
  39. _ID = const(0xD4) # (0b11010100)
  40. # Accelerometer registers
  41. _REG_ACCEL_CTRL_REG1_A = const(0x20)
  42. _REG_ACCEL_CTRL_REG2_A = const(0x21)
  43. _REG_ACCEL_CTRL_REG3_A = const(0x22)
  44. _REG_ACCEL_CTRL_REG4_A = const(0x23)
  45. _REG_ACCEL_CTRL_REG5_A = const(0x24)
  46. _REG_ACCEL_CTRL_REG6_A = const(0x25)
  47. _REG_ACCEL_REFERENCE_A = const(0x26)
  48. _REG_ACCEL_STATUS_REG_A = const(0x27)
  49. _REG_ACCEL_OUT_X_L_A = const(0x28)
  50. _REG_ACCEL_OUT_X_H_A = const(0x29)
  51. _REG_ACCEL_OUT_Y_L_A = const(0x2A)
  52. _REG_ACCEL_OUT_Y_H_A = const(0x2B)
  53. _REG_ACCEL_OUT_Z_L_A = const(0x2C)
  54. _REG_ACCEL_OUT_Z_H_A = const(0x2D)
  55. _REG_ACCEL_FIFO_CTRL_REG_A = const(0x2E)
  56. _REG_ACCEL_FIFO_SRC_REG_A = const(0x2F)
  57. _REG_ACCEL_INT1_CFG_A = const(0x30)
  58. _REG_ACCEL_INT1_SOURCE_A = const(0x31)
  59. _REG_ACCEL_INT1_THS_A = const(0x32)
  60. _REG_ACCEL_INT1_DURATION_A = const(0x33)
  61. _REG_ACCEL_INT2_CFG_A = const(0x34)
  62. _REG_ACCEL_INT2_SOURCE_A = const(0x35)
  63. _REG_ACCEL_INT2_THS_A = const(0x36)
  64. _REG_ACCEL_INT2_DURATION_A = const(0x37)
  65. _REG_ACCEL_CLICK_CFG_A = const(0x38)
  66. _REG_ACCEL_CLICK_SRC_A = const(0x39)
  67. _REG_ACCEL_CLICK_THS_A = const(0x3A)
  68. _REG_ACCEL_TIME_LIMIT_A = const(0x3B)
  69. _REG_ACCEL_TIME_LATENCY_A = const(0x3C)
  70. _REG_ACCEL_TIME_WINDOW_A = const(0x3D)
  71. # Magnetometer registers
  72. _REG_MAG_CRA_REG_M = const(0x00)
  73. _REG_MAG_CRB_REG_M = const(0x01)
  74. _REG_MAG_MR_REG_M = const(0x02)
  75. _REG_MAG_OUT_X_H_M = const(0x03)
  76. _REG_MAG_OUT_X_L_M = const(0x04)
  77. _REG_MAG_OUT_Z_H_M = const(0x05)
  78. _REG_MAG_OUT_Z_L_M = const(0x06)
  79. _REG_MAG_OUT_Y_H_M = const(0x07)
  80. _REG_MAG_OUT_Y_L_M = const(0x08)
  81. _REG_MAG_SR_REG_M = const(0x09)
  82. _REG_MAG_IRA_REG_M = const(0x0A)
  83. _REG_MAG_IRB_REG_M = const(0x0B)
  84. _REG_MAG_IRC_REG_M = const(0x0C)
  85. _REG_MAG_TEMP_OUT_H_M = const(0x31)
  86. _REG_MAG_TEMP_OUT_L_M = const(0x32)
  87. # Magnetometer gains
  88. MAGGAIN_1_3 = const(0x20) # +/- 1.3
  89. MAGGAIN_1_9 = const(0x40) # +/- 1.9
  90. MAGGAIN_2_5 = const(0x60) # +/- 2.5
  91. MAGGAIN_4_0 = const(0x80) # +/- 4.0
  92. MAGGAIN_4_7 = const(0xA0) # +/- 4.7
  93. MAGGAIN_5_6 = const(0xC0) # +/- 5.6
  94. MAGGAIN_8_1 = const(0xE0) # +/- 8.1
  95. # Magentometer rates
  96. MAGRATE_0_7 = const(0x00) # 0.75 Hz
  97. MAGRATE_1_5 = const(0x01) # 1.5 Hz
  98. MAGRATE_3_0 = const(0x62) # 3.0 Hz
  99. MAGRATE_7_5 = const(0x03) # 7.5 Hz
  100. MAGRATE_15 = const(0x04) # 15 Hz
  101. MAGRATE_30 = const(0x05) # 30 Hz
  102. MAGRATE_75 = const(0x06) # 75 Hz
  103. MAGRATE_220 = const(0x07) # 200 Hz
  104. # Conversion constants
  105. _LSM303ACCEL_MG_LSB = 16704.0
  106. _GRAVITY_STANDARD = 9.80665 # Earth's gravity in m/s^2
  107. _GAUSS_TO_MICROTESLA = 100.0 # Gauss to micro-Tesla multiplier
  108. # pylint: enable=bad-whitespace
  109. class LSM303(object):
  110. """Driver for the LSM303 accelerometer/magnetometer."""
  111. # Class-level buffer for reading and writing data with the sensor.
  112. # This reduces memory allocations but means the code is not re-entrant or
  113. # thread safe!
  114. _BUFFER = bytearray(6)
  115. def __init__(self, i2c):
  116. self._accel_device = I2CDevice(i2c, _ADDRESS_ACCEL)
  117. self._mag_device = I2CDevice(i2c, _ADDRESS_MAG)
  118. self._write_u8(self._accel_device, _REG_ACCEL_CTRL_REG1_A, 0x27) # Enable the accelerometer
  119. self._write_u8(self._mag_device, _REG_MAG_MR_REG_M, 0x00) # Enable the magnetometer
  120. self._lsm303mag_gauss_lsb_xy = 1100.0
  121. self._lsm303mag_gauss_lsb_z = 980.0
  122. self._mag_gain = MAGGAIN_1_3
  123. self._mag_rate = MAGRATE_0_7
  124. @property
  125. def raw_acceleration(self):
  126. """The raw accelerometer sensor values.
  127. A 3-tuple of X, Y, Z axis values that are 16-bit signed integers.
  128. """
  129. self._read_bytes(self._accel_device, _REG_ACCEL_OUT_X_L_A | 0x80, 6, self._BUFFER)
  130. return struct.unpack_from('<hhh', self._BUFFER[0:6])
  131. @property
  132. def acceleration(self):
  133. """The processed accelerometer sensor values.
  134. A 3-tuple of X, Y, Z axis values in meters per second squared that are signed floats.
  135. """
  136. raw_accel_data = self.raw_acceleration
  137. return tuple([n / _LSM303ACCEL_MG_LSB * _GRAVITY_STANDARD for n in raw_accel_data])
  138. @property
  139. def raw_magnetic(self):
  140. """The raw magnetometer sensor values.
  141. A 3-tuple of X, Y, Z axis values that are 16-bit signed integers.
  142. """
  143. self._read_bytes(self._mag_device, _REG_MAG_OUT_X_H_M, 6, self._BUFFER)
  144. raw_values = struct.unpack_from('>hhh', self._BUFFER[0:6])
  145. return tuple([n >> 4 for n in raw_values])
  146. @property
  147. def magnetic(self):
  148. """The processed magnetometer sensor values.
  149. A 3-tuple of X, Y, Z axis values in microteslas that are signed floats.
  150. """
  151. mag_x, mag_y, mag_z = self.raw_magnetic
  152. return (mag_x / self._lsm303mag_gauss_lsb_xy * _GAUSS_TO_MICROTESLA,
  153. mag_y / self._lsm303mag_gauss_lsb_xy * _GAUSS_TO_MICROTESLA,
  154. mag_z / self._lsm303mag_gauss_lsb_z * _GAUSS_TO_MICROTESLA)
  155. @property
  156. def mag_gain(self):
  157. """The magnetometer's gain."""
  158. return self._mag_gain
  159. @mag_gain.setter
  160. def mag_gain(self, value):
  161. assert value in (MAGGAIN_1_3, MAGGAIN_1_9, MAGGAIN_2_5, MAGGAIN_4_0, MAGGAIN_4_7,
  162. MAGGAIN_5_6, MAGGAIN_8_1)
  163. self._mag_gain = value
  164. self._write_u8(self._mag_device, _REG_MAG_CRB_REG_M, self._mag_gain)
  165. if self._mag_gain == MAGGAIN_1_3:
  166. self._lsm303mag_gauss_lsb_xy = 1100.0
  167. self._lsm303mag_gauss_lsb_z = 980.0
  168. elif self._mag_gain == MAGGAIN_1_9:
  169. self._lsm303mag_gauss_lsb_xy = 855.0
  170. self._lsm303mag_gauss_lsb_z = 760.0
  171. elif self._mag_gain == MAGGAIN_2_5:
  172. self._lsm303mag_gauss_lsb_xy = 670.0
  173. self._lsm303mag_gauss_lsb_z = 600.0
  174. elif self._mag_gain == MAGGAIN_4_0:
  175. self._lsm303mag_gauss_lsb_xy = 450.0
  176. self._lsm303mag_gauss_lsb_z = 400.0
  177. elif self._mag_gain == MAGGAIN_4_7:
  178. self._lsm303mag_gauss_lsb_xy = 400.0
  179. self._lsm303mag_gauss_lsb_z = 355.0
  180. elif self._mag_gain == MAGGAIN_5_6:
  181. self._lsm303mag_gauss_lsb_xy = 330.0
  182. self._lsm303mag_gauss_lsb_z = 295.0
  183. elif self._mag_gain == MAGGAIN_8_1:
  184. self._lsm303mag_gauss_lsb_xy = 230.0
  185. self._lsm303mag_gauss_lsb_z = 205.0
  186. @property
  187. def mag_rate(self):
  188. """The magnetometer update rate."""
  189. return self._mag_rate
  190. @mag_rate.setter
  191. def mag_rate(self, value):
  192. assert value in (MAGRATE_0_7, MAGRATE_1_5, MAGRATE_3_0, MAGRATE_7_5, MAGRATE_15, MAGRATE_30,
  193. MAGRATE_75, MAGRATE_220)
  194. self._mag_rate = value
  195. reg_m = ((value & 0x07) << 2) & 0xFF
  196. self._write_u8(self._mag_device, _REG_MAG_CRA_REG_M, reg_m)
  197. def _read_u8(self, device, address):
  198. with device as i2c:
  199. self._BUFFER[0] = address & 0xFF
  200. i2c.write(self._BUFFER, end=1, stop=False)
  201. i2c.readinto(self._BUFFER, end=1)
  202. return self._BUFFER[0]
  203. def _write_u8(self, device, address, val):
  204. with device as i2c:
  205. self._BUFFER[0] = address & 0xFF
  206. self._BUFFER[1] = val & 0xFF
  207. i2c.write(self._BUFFER, end=2)
  208. @staticmethod
  209. def _read_bytes(device, address, count, buf):
  210. with device as i2c:
  211. buf[0] = address & 0xFF
  212. i2c.write(buf, end=1, stop=False)
  213. i2c.readinto(buf, end=count)