bmm150.cpp 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926
  1. /**\mainpage
  2. * Copyright (C) 2015 - 2016 Bosch Sensortec GmbH
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. *
  7. * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. *
  10. * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * Neither the name of the copyright holder nor the names of the
  15. * contributors may be used to endorse or promote products derived from
  16. * this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  19. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  20. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22. * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
  23. * OR CONTRIBUTORS BE LIABLE FOR ANY
  24. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  25. * OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
  26. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  27. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  29. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS
  32. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
  33. *
  34. * The information provided is believed to be accurate and reliable.
  35. * The copyright holder assumes no responsibility
  36. * for the consequences of use
  37. * of such information nor for any infringement of patents or
  38. * other rights of third parties which may result from its use.
  39. * No license is granted by implication or otherwise under any patent or
  40. * patent rights of the copyright holder.
  41. *
  42. * File bmm150.c
  43. * Date 12 Sep 2017
  44. * Version 1.0.0
  45. *
  46. */
  47. /*! @file bmm150.c
  48. @brief Sensor driver for BMM150 sensor */
  49. #include "bmm150.h"
  50. /************************** Internal macros *******************************/
  51. /* Sensor ODR, Repetition and axes enable/disable settings */
  52. #define MODE_SETTING_SEL UINT16_C(0x000F)
  53. /* Interrupt pin settings like polarity,latch and int_pin enable */
  54. #define INTERRUPT_PIN_SETTING_SEL UINT16_C(0x01F0)
  55. /* Settings to enable/disable interrupts */
  56. #define INTERRUPT_CONFIG_SEL UINT16_C(0x1E00)
  57. /* Interrupt settings for configuring threshold values */
  58. #define INTERRUPT_THRESHOLD_CONFIG_SEL UINT16_C(0x6000)
  59. /********************** Static function declarations ************************/
  60. /*!
  61. * @brief This internal API is used to validate the device pointer for
  62. * null conditions.
  63. *
  64. * @param[in] dev : Structure instance of bmm150_dev.
  65. *
  66. * @return Result of API execution status
  67. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error
  68. */
  69. static int8_t null_ptr_check(const struct bmm150_dev *dev);
  70. /*!
  71. * @brief This internal API sets/resets the power control bit of 0x4B register.
  72. *
  73. * @param[in] pwrcntrl_bit : Variable used to select/deselect the suspend mode.
  74. * @param[in,out] dev : Structure instance of bmm150_dev
  75. *
  76. * pwrcntrl_bit | power mode
  77. * -----------------|-------------------------
  78. * 0x00 | Suspend mode
  79. * 0x01 | Sleep/Active modes
  80. *
  81. * @return Result of API execution status
  82. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
  83. */
  84. static int8_t set_power_control_bit(uint8_t pwrcntrl_bit, struct bmm150_dev *dev);
  85. /*!
  86. * @brief This internal API reads the trim registers of the sensor and stores
  87. * the trim values in the "trim_data" of device structure.
  88. *
  89. * @param[in,out] dev : Structure instance of bmm150_dev
  90. *
  91. * @return Result of API execution status
  92. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
  93. */
  94. static int8_t read_trim_registers(struct bmm150_dev *dev);
  95. /*!
  96. * @brief This internal API writes the op_mode value in the Opmode bits
  97. * (bits 1 and 2) of 0x4C register.
  98. *
  99. * op_mode | Power mode
  100. * ------------|-----------------------
  101. * 0x00 | BMM150_NORMAL_MODE
  102. * 0x01 | BMM150_FORCED_MODE
  103. * 0x03 | BMM150_SLEEP_MODE
  104. *
  105. * @param[in,out] dev : Structure instance of bmm150_dev
  106. *
  107. * @return Result of API execution status
  108. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
  109. */
  110. static int8_t write_op_mode(uint8_t op_mode, const struct bmm150_dev *dev);
  111. /*!
  112. * @brief This internal API sets the device from suspend to sleep mode
  113. * by setting the power control bit to '1' of 0x4B register
  114. *
  115. * @param[in,out] dev : Structure instance of bmm150_dev
  116. *
  117. * @return Result of API execution status
  118. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
  119. */
  120. static int8_t suspend_to_sleep_mode(struct bmm150_dev *dev);
  121. /*!
  122. * @brief This internal API sets the xy repetition value in the 0x51 register.
  123. *
  124. * @param[in,out] dev : Structure instance of bmm150_dev
  125. *
  126. * dev->settings.xy_rep | nXY(XY Repetitions)
  127. * -------------------------|-----------------------
  128. * 0x00 | 1
  129. * 0x01 | 3
  130. * 0x02 | 5
  131. * . | .
  132. * . | .
  133. * 0xFF | 511
  134. *
  135. * @note number of XY Repetitions nXY = 1+2(dev->settings.xy_rep)
  136. *
  137. * @return Result of API execution status
  138. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
  139. */
  140. static int8_t set_xy_rep(const struct bmm150_dev *dev);
  141. /*!
  142. * @brief This internal API sets the z repetition value in the 0x52 register.
  143. *
  144. * @param[in,out] dev : Structure instance of bmm150_dev
  145. *
  146. * dev->settings.z_rep | nZ(Z Repetitions)
  147. * -------------------------|-----------------------
  148. * 0x00 | 1
  149. * 0x01 | 2
  150. * 0x02 | 3
  151. * . | .
  152. * . | .
  153. * 0xFF | 256
  154. *
  155. * @note number of Z Repetitions nZ = 1+(dev->settings.z_rep)
  156. *
  157. * @return Result of API execution status
  158. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
  159. */
  160. static int8_t set_z_rep(const struct bmm150_dev *dev);
  161. /*!
  162. * @brief This internal API is used to set the output data rate of the sensor
  163. *
  164. * @param[in] dev : Structure instance of bmm150_dev.
  165. *
  166. * dev->settings.data_rate | Data rate (ODR)
  167. * -------------------------|-----------------------
  168. * 0x00 | BMM150_DATA_RATE_10HZ
  169. * 0x01 | BMM150_DATA_RATE_02HZ
  170. * 0x02 | BMM150_DATA_RATE_06HZ
  171. * 0x03 | BMM150_DATA_RATE_08HZ
  172. * 0x04 | BMM150_DATA_RATE_15HZ
  173. * 0x05 | BMM150_DATA_RATE_20HZ
  174. * 0x06 | BMM150_DATA_RATE_25HZ
  175. * 0x07 | BMM150_DATA_RATE_30HZ
  176. *
  177. * @return Result of API execution status
  178. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error
  179. */
  180. static int8_t set_odr(const struct bmm150_dev *dev);
  181. /*!
  182. * @brief This internal API sets the preset mode ODR and repetition settings.
  183. * @param[in] dev : Structure instance of bmm150_dev
  184. *
  185. * API settings | Representation
  186. * -------------------------|------------------------------
  187. * dev->settings.data_rate | Output Data Rate (ODR)
  188. * dev->settings.xy_rep | XY repetition value
  189. * dev->settings.z_rep | Z-repetition value
  190. *
  191. *
  192. * @return Result of API execution status
  193. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
  194. */
  195. static int8_t set_odr_xyz_rep(const struct bmm150_dev *dev);
  196. /*!
  197. * @brief This internal API is used to enable or disable the magnetic
  198. * measurement of x,y,z axes based on the value of xyz_axes_control.
  199. *
  200. * @param[in] dev : Structure instance of bmm150_dev.
  201. *
  202. * dev->settings.xyz_axes_control | Measurement axes/channel
  203. * -------------------------------|--------------------------
  204. * Bit 0 | X - Channel
  205. * Bit 1 | Y - Channel
  206. * Bit 2 | Z - Channel
  207. *
  208. * @note Setting 1 - Disables Channel measurement
  209. * @note Setting 0 - Enables Channel measurement
  210. *
  211. * dev->settings.xyz_axes_control | Measurement axes Enabled/disabled
  212. * -------------------------------|------------------------------------
  213. * 0x01 | Disables X axis (Y,Z axes enabled)
  214. * 0x02 | Disables Y axis (X,Z axes enabled)
  215. * 0x04 | Disables Z axis (X,Y axes enabled)
  216. * 0x07 | Disables all X,Y,Z axes measurement
  217. *
  218. * @return Result of API execution status
  219. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error
  220. */
  221. static int8_t set_control_measurement_xyz(const struct bmm150_dev *dev);
  222. /*!
  223. * @brief This internal API is used to identify the settings which the user
  224. * wants to modify in the sensor.
  225. *
  226. * @param[in] sub_settings : Contains the settings subset to identify particular
  227. * group of settings which the user is interested to change.
  228. * @param[in] settings : Contains the user specified settings.
  229. *
  230. * @return Indicates whether user is interested to modify the settings which
  231. * are related to sub_settings.
  232. * @retval True -> User wants to modify this group of settings
  233. * @retval False -> User does not want to modify this group of settings
  234. */
  235. static uint8_t are_settings_changed(uint16_t sub_settings, uint16_t settings);
  236. /*!
  237. * @brief This API sets the ODR , measurement axes control ,
  238. * repetition values of xy,z.
  239. *
  240. * @param[in] desired_settings : Contains the settings which user wants to
  241. * change.
  242. * @param[in] dev : Structure instance of bmm150_dev.
  243. *
  244. * @return Result of API execution status
  245. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error
  246. */
  247. static int8_t mode_settings(uint16_t desired_settings, const struct bmm150_dev *dev);
  248. /*!
  249. * @brief This internal API is used to parse and store the sensor
  250. * settings in the device structure
  251. *
  252. * @param[in] reg_data : Pointer of an array consisting all sensor
  253. * setting data from 0x4B to 0x52 registers.
  254. * @param[in] dev : Structure instance of bmm150_dev.
  255. *
  256. * @return Result of API execution status
  257. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error
  258. */
  259. static void parse_setting(const uint8_t *reg_data, struct bmm150_dev *dev);
  260. /*!
  261. * @brief This API is used to enable the interrupts and map them to the
  262. * corresponding interrupt pins and specify the pin characteristics like the
  263. * polarity , latch settings for the interrupt pins.
  264. *
  265. * @note The other interrupts can be latched or non-latched but,
  266. * Data ready interrupt is always cleared after reading out the data
  267. *
  268. * @param[in] desired_settings : Contains the settings which user wants to
  269. * change.
  270. * @param[in] dev : Structure instance of bmm150_dev.
  271. *
  272. * @return Result of API execution status
  273. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error
  274. */
  275. static int8_t interrupt_pin_settings(uint16_t desired_settings, const struct bmm150_dev *dev);
  276. /*!
  277. * @brief This API is used to enable data overrun , overflow interrupts and
  278. * enable/disable high/low threshold interrupts for x,y,z axis based on the
  279. * threshold values set by the user in the High threshold (0x50) and
  280. * Low threshold (0x4F) registers.
  281. *
  282. * @param[in] desired_settings : Contains the settings which user wants to
  283. * change.
  284. * @param[in] dev : Structure instance of bmm150_dev.
  285. *
  286. * @return Result of API execution status
  287. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error
  288. */
  289. static int8_t interrupt_config(uint16_t desired_settings, const struct bmm150_dev *dev);
  290. /*!
  291. * @brief This API is used to write the user specified High/Low threshold value
  292. * as a reference to generate the high/low threshold interrupt.
  293. *
  294. * @param[in] desired_settings : Contains the settings which user wants to
  295. * change.
  296. * @param[in] dev : Structure instance of bmm150_dev.
  297. *
  298. * @return Result of API execution status
  299. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error
  300. */
  301. static int8_t interrupt_threshold_settings(uint16_t desired_settings, const struct bmm150_dev *dev);
  302. #ifdef BMM150_USE_FLOATING_POINT
  303. /*!
  304. * @brief This internal API is used to obtain the compensated
  305. * magnetometer X axis data in float.
  306. *
  307. * @param[in] mag_data_x : The value of raw X data
  308. * @param[in] data_rhall : The value of raw RHALL data
  309. * @param[in] dev : Structure instance of bmm150_dev.
  310. *
  311. * @return Result of compensated X data value in float
  312. */
  313. static float compensate_x(int16_t mag_data_x, uint16_t data_rhall, const struct bmm150_dev *dev);
  314. /*!
  315. * @brief This internal API is used to obtain the compensated
  316. * magnetometer Y axis data in float.
  317. *
  318. * @param[in] mag_data_y : The value of raw Y data
  319. * @param[in] data_rhall : The value of raw RHALL data
  320. * @param[in] dev : Structure instance of bmm150_dev.
  321. *
  322. * @return Result of compensated Y data value in float
  323. */
  324. static float compensate_y(int16_t mag_data_y, uint16_t data_rhall, const struct bmm150_dev *dev);
  325. /*!
  326. * @brief This internal API is used to obtain the compensated
  327. * magnetometer Z axis data in float.
  328. *
  329. * @param[in] mag_data_z : The value of raw Z data
  330. * @param[in] data_rhall : The value of raw RHALL data
  331. * @param[in] dev : Structure instance of bmm150_dev.
  332. *
  333. * @return Result of compensated Z data value in float
  334. */
  335. static float compensate_z(int16_t mag_data_z, uint16_t data_rhall, const struct bmm150_dev *dev);
  336. #else
  337. /*!
  338. * @brief This internal API is used to obtain the compensated
  339. * magnetometer X axis data in int16_t.
  340. *
  341. * @param[in] mag_data_x : The value of raw X data
  342. * @param[in] data_rhall : The value of raw RHALL data
  343. * @param[in] dev : Structure instance of bmm150_dev.
  344. *
  345. * @return Result of compensated X data value in int16_t format
  346. */
  347. static int16_t compensate_x(int16_t mag_data_x, uint16_t data_rhall, const struct bmm150_dev *dev);
  348. /*!
  349. * @brief This internal API is used to obtain the compensated
  350. * magnetometer Y axis data in int16_t.
  351. *
  352. * @param[in] mag_data_y : The value of raw Y data
  353. * @param[in] data_rhall : The value of raw RHALL data
  354. * @param[in] dev : Structure instance of bmm150_dev.
  355. *
  356. * @return Result of compensated Y data value in int16_t format
  357. */
  358. static int16_t compensate_y(int16_t mag_data_y, uint16_t data_rhall, const struct bmm150_dev *dev);
  359. /*!
  360. * @brief This internal API is used to obtain the compensated
  361. * magnetometer Z axis data in int16_t.
  362. *
  363. * @param[in] mag_data_z : The value of raw Z data
  364. * @param[in] data_rhall : The value of raw RHALL data
  365. * @param[in] dev : Structure instance of bmm150_dev.
  366. *
  367. * @return Result of compensated Z data value in int16_t format
  368. */
  369. static int16_t compensate_z(int16_t mag_data_z, uint16_t data_rhall, const struct bmm150_dev *dev);
  370. #endif
  371. /*!
  372. * @brief This internal API is used to perform the normal self test
  373. * of the sensor and return the self test result as return value
  374. *
  375. * @param[in] dev : Structure instance of bmm150_dev.
  376. *
  377. * @return Result of API execution status
  378. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error
  379. */
  380. static int8_t perform_normal_self_test(const struct bmm150_dev *dev);
  381. /*!
  382. * @brief This internal API is used to enable the normal self test by setting
  383. * the Self Test bit (bit0) of the 0x4C register,
  384. * which triggers the start of self test
  385. *
  386. * @param[out] self_test_enable : The value of self test bit0 in 0x4C register
  387. * @param[in] dev : Structure instance of bmm150_dev.
  388. *
  389. * @return Result of API execution status
  390. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error
  391. */
  392. static int8_t enable_normal_self_test(uint8_t *self_test_enable, const struct bmm150_dev *dev);
  393. /*!
  394. * @brief This internal API is used to validate the results of normal self test
  395. * by using the self test status available in the bit0 of registers 0x42,0x44
  396. * and 0x46.
  397. *
  398. * @param[in] dev : Structure instance of bmm150_dev
  399. *
  400. * @return Result of API execution status
  401. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error
  402. */
  403. static int8_t validate_normal_self_test(const struct bmm150_dev *dev);
  404. /*!
  405. * @brief This internal API is used to perform advanced self test for Z axis
  406. *
  407. * @param[in] dev : Structure instance of bmm150_dev
  408. *
  409. * @return Result of API execution status
  410. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error
  411. *
  412. * Return value | Status of self-test
  413. *----------------------|---------------------------
  414. * 0 | BMM150_OK
  415. * 8 | BMM150_W_ADV_SELF_TEST_FAIL
  416. */
  417. static int8_t perform_adv_self_test(struct bmm150_dev *dev);
  418. /*!
  419. * @brief This internal API is used to set the desired power mode ,
  420. * axes control and repetition settings for advanced self test
  421. *
  422. * @param[in] dev : Structure instance of bmm150_dev
  423. *
  424. * @return Result of API execution status
  425. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error
  426. */
  427. static int8_t adv_self_test_settings(struct bmm150_dev *dev);
  428. /*!
  429. * @brief This internal API is used to set the positive or negative value of
  430. * self-test current and obtain the corresponding magnetometer z axis data
  431. *
  432. * @param[in] self_test_current : Self test current either positive/negative
  433. * @param[out] data_z : Z-axis Magnetometer data
  434. * @param[in] dev : Structure instance of bmm150_dev
  435. *
  436. * self_test_current | Self-test current Direction
  437. *-------------------------|------------------------------
  438. * 0x03 | BMM150_ENABLE_POSITIVE_CURRENT
  439. * 0x02 | BMM150_ENABLE_NEGATIVE_CURRENT
  440. *
  441. * @return Result of API execution status
  442. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error
  443. */
  444. static int8_t adv_self_test_measurement(uint8_t self_test_current, int16_t *data_z, struct bmm150_dev *dev);
  445. /*!
  446. * @brief This internal API is used to get the difference between the
  447. * Z axis mag data obtained by positive and negative self-test current
  448. * and validate whether the advanced self test is done successfully or not.
  449. *
  450. * @param[in] positive_data_z : Z-axis Mag data by positive self-test current
  451. * @param[in] negative_data_z : Z-axis Mag data by negative self-test current
  452. *
  453. *
  454. * @return Result of API execution status
  455. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error
  456. *
  457. * Return value | Status of self-test
  458. *----------------------|---------------------------
  459. * 0 | BMM150_OK
  460. * 8 | BMM150_W_ADV_SELF_TEST_FAIL
  461. */
  462. static int8_t validate_adv_self_test(int16_t positive_data_z, int16_t negative_data_z);
  463. /*!
  464. * @brief This internal API is used to set the self test current value in
  465. * the Adv. ST bits (bit6 and bit7) of 0x4C register
  466. *
  467. * @param[in] self_test_current : Self test current value (+ve/-ve)
  468. * @param[in] dev : Structure instance of bmm150_dev
  469. *
  470. * self_test_current | Self-test current Direction
  471. *-------------------------|------------------------------
  472. * 0x00 | BMM150_DISABLE_SELF_TEST_CURRENT
  473. * 0x02 | BMM150_ENABLE_NEGATIVE_CURRENT
  474. * 0x03 | BMM150_ENABLE_POSITIVE_CURRENT
  475. *
  476. * @return Result of API execution status
  477. * @retval zero -> Success / +ve value -> Warning / -ve value -> Error
  478. */
  479. static int8_t set_adv_self_test_current(uint8_t self_test_current, const struct bmm150_dev *dev);
  480. /********************** Global function definitions ************************/
  481. /*!
  482. * @brief This API is the entry point, Call this API before using other APIs.
  483. * This API reads the chip-id of the sensor which is the first step to
  484. * verify the sensor and updates the trim parameters of the sensor.
  485. */
  486. int8_t bmm150_init(struct bmm150_dev *dev)
  487. {
  488. int8_t rslt;
  489. uint8_t chip_id = 0;
  490. /* Check for null pointer in the device structure*/
  491. rslt = null_ptr_check(dev);
  492. /* Proceed if null check is fine */
  493. if (rslt == BMM150_OK) {
  494. /* Power up the sensor from suspend to sleep mode */
  495. rslt = set_power_control_bit(BMM150_POWER_CNTRL_ENABLE, dev);
  496. /* Start-up time delay of 3ms*/
  497. dev->delay_ms(BMM150_START_UP_TIME);
  498. if (rslt == BMM150_OK) {
  499. /* Chip ID of the sensor is read */
  500. rslt = bmm150_get_regs(BMM150_CHIP_ID_ADDR, &chip_id, 1, dev);
  501. /* Proceed if everything is fine until now */
  502. if (rslt == BMM150_OK) {
  503. /* Check for chip id validity */
  504. if (chip_id == BMM150_CHIP_ID) {
  505. dev->chip_id = chip_id;
  506. /* Function to update trim values */
  507. rslt = read_trim_registers(dev);
  508. } else {
  509. rslt = BMM150_E_DEV_NOT_FOUND;
  510. }
  511. }
  512. }
  513. }
  514. return rslt;
  515. }
  516. /*!
  517. * @brief This API writes the given data to the register address
  518. * of the sensor.
  519. */
  520. int8_t bmm150_set_regs(uint8_t reg_addr, uint8_t *reg_data, uint8_t len, const struct bmm150_dev *dev)
  521. {
  522. int8_t rslt;
  523. /* Check for null pointer in the device structure*/
  524. rslt = null_ptr_check(dev);
  525. /* Proceed if null check is fine */
  526. if ((rslt == BMM150_OK) && (reg_data != NULL) && (len != 0)) {
  527. /* Write the data to the reg_addr */
  528. /* SPI write requires to set The MSB of reg_addr as 0
  529. but in default the MSB is always 0 */
  530. rslt = dev->write(dev->dev_id, reg_addr, reg_data, len);
  531. } else {
  532. rslt = BMM150_E_NULL_PTR;
  533. }
  534. return rslt;
  535. }
  536. /*!
  537. * @brief This API reads the data from the given register address of the sensor.
  538. */
  539. int8_t bmm150_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint8_t len, const struct bmm150_dev *dev)
  540. {
  541. int8_t rslt;
  542. /* Check for null pointer in the device structure*/
  543. rslt = null_ptr_check(dev);
  544. /* Proceed if null check is fine */
  545. if ((rslt == BMM150_OK) && (reg_data != NULL)) {
  546. if (dev->intf != BMM150_I2C_INTF) {
  547. /* If interface selected is SPI */
  548. reg_addr = reg_addr | 0x80;
  549. }
  550. /* Read the data from the reg_addr */
  551. rslt = dev->read(dev->dev_id, reg_addr, reg_data, len);
  552. } else {
  553. rslt = BMM150_E_NULL_PTR;
  554. }
  555. return rslt;
  556. }
  557. /*!
  558. * @brief This API is used to perform soft-reset of the sensor
  559. * where all the registers are reset to their default values except 0x4B.
  560. */
  561. int8_t bmm150_soft_reset(const struct bmm150_dev *dev)
  562. {
  563. int8_t rslt;
  564. uint8_t reg_data;
  565. /* Check for null pointer in the device structure*/
  566. rslt = null_ptr_check(dev);
  567. /* Proceed if null check is fine */
  568. if (rslt == BMM150_OK) {
  569. rslt = bmm150_get_regs(BMM150_POWER_CONTROL_ADDR, &reg_data, 1, dev);
  570. if (rslt == BMM150_OK) {
  571. reg_data = reg_data | BMM150_SET_SOFT_RESET;
  572. rslt = bmm150_set_regs(BMM150_POWER_CONTROL_ADDR, &reg_data, 1, dev);
  573. dev->delay_ms(BMM150_SOFT_RESET_DELAY);
  574. }
  575. }
  576. return rslt;
  577. }
  578. /*!
  579. * @brief This API is used to set the power mode of the sensor.
  580. */
  581. int8_t bmm150_set_op_mode(struct bmm150_dev *dev)
  582. {
  583. int8_t rslt;
  584. uint8_t pwr_mode = dev->settings.pwr_mode;
  585. /* Check for null pointer in the device structure*/
  586. rslt = null_ptr_check(dev);
  587. /* Proceed if null check is fine */
  588. if (rslt == BMM150_OK) {
  589. /* Select the power mode to set */
  590. switch (pwr_mode) {
  591. case BMM150_NORMAL_MODE:
  592. /* If the sensor is in suspend mode
  593. put the device to sleep mode */
  594. rslt = suspend_to_sleep_mode(dev);
  595. if (rslt == BMM150_OK) {
  596. /* write the op mode */
  597. rslt = write_op_mode(pwr_mode, dev);
  598. }
  599. break;
  600. case BMM150_FORCED_MODE:
  601. /* If the sensor is in suspend mode
  602. put the device to sleep mode */
  603. rslt = suspend_to_sleep_mode(dev);
  604. if (rslt == BMM150_OK) {
  605. /* write the op mode */
  606. rslt = write_op_mode(pwr_mode, dev);
  607. }
  608. break;
  609. case BMM150_SLEEP_MODE:
  610. /* If the sensor is in suspend mode
  611. put the device to sleep mode */
  612. rslt = suspend_to_sleep_mode(dev);
  613. if (rslt == BMM150_OK) {
  614. /* write the op mode */
  615. rslt = write_op_mode(pwr_mode, dev);
  616. }
  617. break;
  618. case BMM150_SUSPEND_MODE:
  619. /* Set the power control bit to zero */
  620. rslt = set_power_control_bit(BMM150_POWER_CNTRL_DISABLE, dev);
  621. break;
  622. default:
  623. rslt = BMM150_E_INVALID_CONFIG;
  624. break;
  625. }
  626. }
  627. return rslt;
  628. }
  629. /*!
  630. * @brief This API is used to get the power mode of the sensor.
  631. */
  632. int8_t bmm150_get_op_mode(uint8_t *op_mode, const struct bmm150_dev *dev)
  633. {
  634. int8_t rslt;
  635. uint8_t reg_data;
  636. /* Check for null pointer in the device structure*/
  637. rslt = null_ptr_check(dev);
  638. /* Proceed if null check is fine */
  639. if (rslt == BMM150_OK) {
  640. if (dev->settings.pwr_cntrl_bit == BMM150_POWER_CNTRL_DISABLE) {
  641. /* Power mode set is suspend mode*/
  642. *op_mode = BMM150_SUSPEND_MODE;
  643. } else {
  644. /*Power mode set is stored in the op_mode */
  645. rslt = bmm150_get_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
  646. *op_mode = BMM150_GET_BITS(reg_data, BMM150_OP_MODE);
  647. }
  648. }
  649. return rslt;
  650. }
  651. /*!
  652. * @brief This API is used to set the preset mode of the sensor.
  653. */
  654. int8_t bmm150_set_presetmode(struct bmm150_dev *dev)
  655. {
  656. int8_t rslt;
  657. uint8_t preset_mode;
  658. /* Check for null pointer in the device structure*/
  659. rslt = null_ptr_check(dev);
  660. /* Proceed if null check is fine */
  661. if (rslt == BMM150_OK) {
  662. preset_mode = dev->settings.preset_mode;
  663. switch (preset_mode) {
  664. case BMM150_PRESETMODE_LOWPOWER:
  665. /* Set the data rate x,y,z repetition
  666. for Low Power mode */
  667. dev->settings.data_rate = BMM150_DATA_RATE_10HZ;
  668. dev->settings.xy_rep = BMM150_LOWPOWER_REPXY;
  669. dev->settings.z_rep = BMM150_LOWPOWER_REPZ;
  670. rslt = set_odr_xyz_rep(dev);
  671. break;
  672. case BMM150_PRESETMODE_REGULAR:
  673. /* Set the data rate x,y,z repetition
  674. for Regular mode */
  675. dev->settings.data_rate = BMM150_DATA_RATE_10HZ;
  676. dev->settings.xy_rep = BMM150_REGULAR_REPXY;
  677. dev->settings.z_rep = BMM150_REGULAR_REPZ;
  678. rslt = set_odr_xyz_rep(dev);
  679. break;
  680. case BMM150_PRESETMODE_HIGHACCURACY:
  681. /* Set the data rate x,y,z repetition
  682. for High Accuracy mode */
  683. dev->settings.data_rate = BMM150_DATA_RATE_20HZ;
  684. dev->settings.xy_rep = BMM150_HIGHACCURACY_REPXY;
  685. dev->settings.z_rep = BMM150_HIGHACCURACY_REPZ;
  686. rslt = set_odr_xyz_rep(dev);
  687. break;
  688. case BMM150_PRESETMODE_ENHANCED:
  689. /* Set the data rate x,y,z repetition
  690. for Enhanced Accuracy mode */
  691. dev->settings.data_rate = BMM150_DATA_RATE_10HZ;
  692. dev->settings.xy_rep = BMM150_ENHANCED_REPXY;
  693. dev->settings.z_rep = BMM150_ENHANCED_REPZ;
  694. rslt = set_odr_xyz_rep(dev);
  695. break;
  696. default:
  697. rslt = BMM150_E_INVALID_CONFIG;
  698. break;
  699. }
  700. }
  701. return rslt;
  702. }
  703. /*!
  704. * @brief This API sets the sensor settings based on the desired_settings
  705. * and the dev structure configuration
  706. */
  707. int8_t bmm150_set_sensor_settings(uint16_t desired_settings, const struct bmm150_dev *dev)
  708. {
  709. int8_t rslt;
  710. /* Check for null pointer in the device structure*/
  711. rslt = null_ptr_check(dev);
  712. /* Proceed if null check is fine */
  713. if (rslt == BMM150_OK) {
  714. if (are_settings_changed(MODE_SETTING_SEL, desired_settings)) {
  715. /* ODR, Control measurement, XY,Z repetition values*/
  716. rslt = mode_settings(desired_settings, dev);
  717. }
  718. if ((!rslt) && are_settings_changed(INTERRUPT_PIN_SETTING_SEL, desired_settings)) {
  719. /* Interrupt pin settings */
  720. rslt = interrupt_pin_settings(desired_settings, dev);
  721. }
  722. if ((!rslt) && are_settings_changed(INTERRUPT_CONFIG_SEL, desired_settings)) {
  723. /* Interrupt configuration settings */
  724. rslt = interrupt_config(desired_settings, dev);
  725. }
  726. if ((!rslt) && are_settings_changed(INTERRUPT_THRESHOLD_CONFIG_SEL, desired_settings)) {
  727. /* Interrupt threshold settings */
  728. rslt = interrupt_threshold_settings(desired_settings, dev);
  729. }
  730. }
  731. return rslt;
  732. }
  733. /*!
  734. * @brief This API gets the sensor settings and updates the dev structure
  735. */
  736. int8_t bmm150_get_sensor_settings(struct bmm150_dev *dev)
  737. {
  738. int8_t rslt;
  739. uint8_t setting[BMM150_SETTING_DATA_LEN] = {0};
  740. /* Check for null pointer in the device structure*/
  741. rslt = null_ptr_check(dev);
  742. /* Proceed if null check is fine */
  743. if (rslt == BMM150_OK) {
  744. /*Read the entire sensor settings */
  745. rslt = bmm150_get_regs(BMM150_POWER_CONTROL_ADDR, setting, BMM150_SETTING_DATA_LEN, dev);
  746. if (rslt == BMM150_OK) {
  747. /*Parse and store the settings */
  748. parse_setting(setting, dev);
  749. }
  750. }
  751. return rslt;
  752. }
  753. /*!
  754. * @brief This API is used to read the magnetometer data from registers
  755. * 0x42 to 0x49 and update the dev structure with the
  756. * compensated mag data in micro-tesla.
  757. */
  758. int8_t bmm150_read_mag_data(struct bmm150_dev *dev)
  759. {
  760. int8_t rslt;
  761. int16_t msb_data;
  762. uint8_t reg_data[BMM150_XYZR_DATA_LEN] = {0};
  763. struct bmm150_raw_mag_data raw_mag_data;
  764. /* Check for null pointer in the device structure*/
  765. rslt = null_ptr_check(dev);
  766. /* Proceed if null check is fine */
  767. if (rslt == BMM150_OK) {
  768. /*Read the mag data registers */
  769. rslt = bmm150_get_regs(BMM150_DATA_X_LSB, reg_data, BMM150_XYZR_DATA_LEN, dev);
  770. if (rslt == BMM150_OK) {
  771. /* Mag X axis data */
  772. reg_data[0] = BMM150_GET_BITS(reg_data[0], BMM150_DATA_X);
  773. /* Shift the MSB data to left by 5 bits */
  774. /* Multiply by 32 to get the shift left by 5 value */
  775. msb_data = ((int16_t)((int8_t)reg_data[1])) * 32;
  776. /* Raw mag X axis data */
  777. raw_mag_data.raw_datax = (int16_t)(msb_data | reg_data[0]);
  778. /* Mag Y axis data */
  779. reg_data[2] = BMM150_GET_BITS(reg_data[2], BMM150_DATA_Y);
  780. /* Shift the MSB data to left by 5 bits */
  781. /* Multiply by 32 to get the shift left by 5 value */
  782. msb_data = ((int16_t)((int8_t)reg_data[3])) * 32;
  783. /* Raw mag Y axis data */
  784. raw_mag_data.raw_datay = (int16_t)(msb_data | reg_data[2]);
  785. /* Mag Z axis data */
  786. reg_data[4] = BMM150_GET_BITS(reg_data[4], BMM150_DATA_Z);
  787. /* Shift the MSB data to left by 7 bits */
  788. /* Multiply by 128 to get the shift left by 7 value */
  789. msb_data = ((int16_t)((int8_t)reg_data[5])) * 128;
  790. /* Raw mag Z axis data */
  791. raw_mag_data.raw_dataz = (int16_t)(msb_data | reg_data[4]);
  792. /* Mag R-HALL data */
  793. reg_data[6] = BMM150_GET_BITS(reg_data[6], BMM150_DATA_RHALL);
  794. raw_mag_data.raw_data_r = (uint16_t)(((uint16_t)reg_data[7] << 6) | reg_data[6]);
  795. /* Compensated Mag X data in int16_t format */
  796. dev->data.x = compensate_x(raw_mag_data.raw_datax, raw_mag_data.raw_data_r, dev);
  797. /* Compensated Mag Y data in int16_t format */
  798. dev->data.y = compensate_y(raw_mag_data.raw_datay, raw_mag_data.raw_data_r, dev);
  799. /* Compensated Mag Z data in int16_t format */
  800. dev->data.z = compensate_z(raw_mag_data.raw_dataz, raw_mag_data.raw_data_r, dev);
  801. }
  802. }
  803. return rslt;
  804. }
  805. /*!
  806. * @brief This API is used to perform the complete self test
  807. * (both normal and advanced) for the BMM150 sensor
  808. */
  809. int8_t bmm150_perform_self_test(uint8_t self_test_mode, struct bmm150_dev *dev)
  810. {
  811. int8_t rslt;
  812. int8_t self_test_rslt = 0;
  813. /* Check for null pointer in the device structure*/
  814. rslt = null_ptr_check(dev);
  815. /* Proceed if null check is fine */
  816. if (rslt == BMM150_OK) {
  817. switch (self_test_mode) {
  818. case BMM150_NORMAL_SELF_TEST:
  819. /* Set the sensor in sleep mode */
  820. dev->settings.pwr_mode = BMM150_SLEEP_MODE;
  821. rslt = bmm150_set_op_mode(dev);
  822. if (rslt == BMM150_OK) {
  823. /* Perform the normal self test */
  824. rslt = perform_normal_self_test(dev);
  825. }
  826. break;
  827. case BMM150_ADVANCED_SELF_TEST:
  828. /* Perform the advanced self test */
  829. rslt = perform_adv_self_test(dev);
  830. /* Check to ensure bus error does not occur */
  831. if (rslt >= BMM150_OK) {
  832. /* Store the status of self test result */
  833. self_test_rslt = rslt;
  834. /* Perform soft reset */
  835. rslt = bmm150_soft_reset(dev);
  836. }
  837. /* Check to ensure bus operations are success */
  838. if (rslt == BMM150_OK) {
  839. /* Restore self_test_rslt as return value */
  840. rslt = self_test_rslt;
  841. }
  842. break;
  843. default:
  844. rslt = BMM150_E_INVALID_CONFIG;
  845. break;
  846. }
  847. }
  848. return rslt;
  849. }
  850. /*!
  851. * @brief This API is used to get the status flags of all interrupt
  852. * which is used to check for the assertion of interrupts
  853. */
  854. int8_t bmm150_get_interrupt_status(struct bmm150_dev *dev)
  855. {
  856. int8_t rslt;
  857. uint8_t interrupt_status;
  858. uint8_t data_ready_status;
  859. /* Check for null pointer in the device structure*/
  860. rslt = null_ptr_check(dev);
  861. /* Proceed if null check is fine */
  862. if (rslt == BMM150_OK) {
  863. /* Read the data ready status from the register 0x48 */
  864. rslt = bmm150_get_regs(BMM150_DATA_READY_STATUS, &data_ready_status, 1, dev);
  865. if (rslt == BMM150_OK) {
  866. /* Read the interrupt status from the register 0x50 */
  867. rslt = bmm150_get_regs(BMM150_INTERRUPT_STATUS, &interrupt_status, 1, dev);
  868. if (rslt == BMM150_OK) {
  869. /* Mask and store the data ready status bit*/
  870. data_ready_status = BMM150_GET_BITS_POS_0(data_ready_status, BMM150_DRDY_STATUS);
  871. /* store the entire interrupt status in dev */
  872. dev->int_status = (data_ready_status << 8) | interrupt_status;
  873. }
  874. }
  875. }
  876. return rslt;
  877. }
  878. /****************************************************************************/
  879. /**\name BMM150 as Auxiliary Mag */
  880. /*!
  881. * @brief This API is used to compensate the raw mag data
  882. */
  883. int8_t bmm150_aux_mag_data(uint8_t *aux_data, struct bmm150_dev *dev)
  884. {
  885. int8_t rslt;
  886. int16_t msb_data;
  887. struct bmm150_raw_mag_data raw_mag_data;
  888. /* Check for null pointer in the device structure*/
  889. rslt = null_ptr_check(dev);
  890. /* Proceed if null check is fine */
  891. if ((rslt == BMM150_OK) && (aux_data != NULL)) {
  892. /* Mag X axis data */
  893. aux_data[0] = BMM150_GET_BITS(aux_data[0], BMM150_DATA_X);
  894. /* Shift the MSB data to left by 5 bits */
  895. /* Multiply by 32 to get the shift left by 5 value */
  896. msb_data = ((int16_t)((int8_t)aux_data[1])) * 32;
  897. /* Raw mag X axis data */
  898. raw_mag_data.raw_datax = (int16_t)(msb_data | aux_data[0]);
  899. /* Mag Y axis data */
  900. aux_data[2] = BMM150_GET_BITS(aux_data[2], BMM150_DATA_Y);
  901. /* Shift the MSB data to left by 5 bits */
  902. /* Multiply by 32 to get the shift left by 5 value */
  903. msb_data = ((int16_t)((int8_t)aux_data[3])) * 32;
  904. /* Raw mag Y axis data */
  905. raw_mag_data.raw_datay = (int16_t)(msb_data | aux_data[2]);
  906. /* Mag Z axis data */
  907. aux_data[4] = BMM150_GET_BITS(aux_data[4], BMM150_DATA_Z);
  908. /* Shift the MSB data to left by 7 bits */
  909. /* Multiply by 128 to get the shift left by 7 value */
  910. msb_data = ((int16_t)((int8_t)aux_data[5])) * 128;
  911. /* Raw mag Z axis data */
  912. raw_mag_data.raw_dataz = (int16_t)(msb_data | aux_data[4]);
  913. /* Mag R-HALL data */
  914. aux_data[6] = BMM150_GET_BITS(aux_data[6], BMM150_DATA_RHALL);
  915. raw_mag_data.raw_data_r = (uint16_t)(((uint16_t)aux_data[7] << 6) | aux_data[6]);
  916. /* Compensated Mag X data in int16_t format */
  917. dev->data.x = compensate_x(raw_mag_data.raw_datax, raw_mag_data.raw_data_r, dev);
  918. /* Compensated Mag Y data in int16_t format */
  919. dev->data.y = compensate_y(raw_mag_data.raw_datay, raw_mag_data.raw_data_r, dev);
  920. /* Compensated Mag Z data in int16_t format */
  921. dev->data.z = compensate_z(raw_mag_data.raw_dataz, raw_mag_data.raw_data_r, dev);
  922. }
  923. return rslt;
  924. }
  925. /****************************************************************************/
  926. /**\name INTERNAL APIs */
  927. /*!
  928. * @brief This internal API is used to validate the device structure pointer for
  929. * null conditions.
  930. */
  931. static int8_t null_ptr_check(const struct bmm150_dev *dev)
  932. {
  933. int8_t rslt;
  934. if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_ms == NULL)) {
  935. /* Device structure pointer is not valid */
  936. rslt = BMM150_E_NULL_PTR;
  937. } else {
  938. /* Device structure is fine */
  939. rslt = BMM150_OK;
  940. }
  941. return rslt;
  942. }
  943. /*!
  944. * @brief This internal API sets/resets the power control bit of 0x4B register.
  945. */
  946. static int8_t set_power_control_bit(uint8_t pwrcntrl_bit, struct bmm150_dev *dev)
  947. {
  948. int8_t rslt;
  949. uint8_t reg_data = 0;
  950. /* Check for null pointer in the device structure*/
  951. rslt = null_ptr_check(dev);
  952. /* Proceed if null check is fine */
  953. if (rslt == BMM150_OK) {
  954. /* Power control register 0x4B is read */
  955. rslt = bmm150_get_regs(BMM150_POWER_CONTROL_ADDR, &reg_data, 1, dev);
  956. /* Proceed if everything is fine until now */
  957. if (rslt == BMM150_OK) {
  958. /* Sets the value of power control bit */
  959. reg_data = BMM150_SET_BITS_POS_0(reg_data, BMM150_PWR_CNTRL, pwrcntrl_bit);
  960. rslt = bmm150_set_regs(BMM150_POWER_CONTROL_ADDR, &reg_data, 1, dev);
  961. if (rslt == BMM150_OK) {
  962. /*Store the power control bit
  963. value in dev structure*/
  964. dev->settings.pwr_cntrl_bit = pwrcntrl_bit;
  965. }
  966. }
  967. }
  968. return rslt;
  969. }
  970. /*!
  971. * @brief This internal API reads the trim registers of the sensor and stores
  972. * the trim values in the "trim_data" of device structure.
  973. */
  974. static int8_t read_trim_registers(struct bmm150_dev *dev)
  975. {
  976. int8_t rslt;
  977. uint8_t trim_x1y1[2] = {0};
  978. uint8_t trim_xyz_data[4] = {0};
  979. uint8_t trim_xy1xy2[10] = {0};
  980. uint16_t temp_msb = 0;
  981. /* Trim register value is read */
  982. rslt = bmm150_get_regs(BMM150_DIG_X1, trim_x1y1, 2, dev);
  983. if (rslt == BMM150_OK) {
  984. rslt = bmm150_get_regs(BMM150_DIG_Z4_LSB, trim_xyz_data, 4, dev);
  985. if (rslt == BMM150_OK) {
  986. rslt = bmm150_get_regs(BMM150_DIG_Z2_LSB, trim_xy1xy2, 10, dev);
  987. if (rslt == BMM150_OK) {
  988. /* Trim data which is read is updated
  989. in the device structure */
  990. dev->trim_data.dig_x1 = (int8_t)trim_x1y1[0];
  991. dev->trim_data.dig_y1 = (int8_t)trim_x1y1[1];
  992. dev->trim_data.dig_x2 = (int8_t)trim_xyz_data[2];
  993. dev->trim_data.dig_y2 = (int8_t)trim_xyz_data[3];
  994. temp_msb = ((uint16_t)trim_xy1xy2[3]) << 8;
  995. dev->trim_data.dig_z1 = (uint16_t)(temp_msb | trim_xy1xy2[2]);
  996. temp_msb = ((uint16_t)trim_xy1xy2[1]) << 8;
  997. dev->trim_data.dig_z2 = (int16_t)(temp_msb | trim_xy1xy2[0]);
  998. temp_msb = ((uint16_t)trim_xy1xy2[7]) << 8;
  999. dev->trim_data.dig_z3 = (int16_t)(temp_msb | trim_xy1xy2[6]);
  1000. temp_msb = ((uint16_t)trim_xyz_data[1]) << 8;
  1001. dev->trim_data.dig_z4 = (int16_t)(temp_msb | trim_xyz_data[0]);
  1002. dev->trim_data.dig_xy1 = trim_xy1xy2[9];
  1003. dev->trim_data.dig_xy2 = (int8_t)trim_xy1xy2[8];
  1004. temp_msb = ((uint16_t)(trim_xy1xy2[5] & 0x7F)) << 8;
  1005. dev->trim_data.dig_xyz1 = (uint16_t)(temp_msb | trim_xy1xy2[4]);
  1006. }
  1007. }
  1008. }
  1009. return rslt;
  1010. }
  1011. /*!
  1012. * @brief This internal API writes the op_mode value in the Opmode bits
  1013. * (bits 1 and 2) of 0x4C register.
  1014. */
  1015. static int8_t write_op_mode(uint8_t op_mode, const struct bmm150_dev *dev)
  1016. {
  1017. int8_t rslt;
  1018. uint8_t reg_data;
  1019. /* Check for null pointer in the device structure*/
  1020. rslt = null_ptr_check(dev);
  1021. /* Proceed if null check is fine */
  1022. if (rslt == BMM150_OK) {
  1023. /* Read the 0x4C register */
  1024. rslt = bmm150_get_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
  1025. if (rslt == BMM150_OK) {
  1026. /* Set the op_mode value in Opmode bits of 0x4C */
  1027. reg_data = BMM150_SET_BITS(reg_data, BMM150_OP_MODE, op_mode);
  1028. rslt = bmm150_set_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
  1029. }
  1030. }
  1031. return rslt;
  1032. }
  1033. /*!
  1034. * @brief This internal API sets the device from suspend to sleep mode
  1035. * by setting the power control bit to '1' of 0x4B register
  1036. */
  1037. static int8_t suspend_to_sleep_mode(struct bmm150_dev *dev)
  1038. {
  1039. int8_t rslt;
  1040. /* Check for null pointer in the device structure*/
  1041. rslt = null_ptr_check(dev);
  1042. /* Proceed if null check is fine */
  1043. if (rslt == BMM150_OK) {
  1044. if (dev->settings.pwr_cntrl_bit == BMM150_POWER_CNTRL_DISABLE) {
  1045. rslt = set_power_control_bit(BMM150_POWER_CNTRL_ENABLE, dev);
  1046. /* Start-up time delay of 3ms*/
  1047. dev->delay_ms(BMM150_START_UP_TIME);
  1048. }
  1049. }
  1050. return rslt;
  1051. }
  1052. /*!
  1053. * @brief This internal API sets the xy repetition value in the 0x51 register.
  1054. */
  1055. static int8_t set_xy_rep(const struct bmm150_dev *dev)
  1056. {
  1057. int8_t rslt;
  1058. uint8_t rep_xy;
  1059. /* Check for null pointer in the device structure*/
  1060. rslt = null_ptr_check(dev);
  1061. /* Proceed if null check is fine */
  1062. if (rslt == BMM150_OK) {
  1063. /* set the xy repetition */
  1064. rep_xy = dev->settings.xy_rep;
  1065. rslt = bmm150_set_regs(BMM150_REP_XY_ADDR, &rep_xy, 1, dev);
  1066. }
  1067. return rslt;
  1068. }
  1069. /*!
  1070. * @brief This internal API sets the z repetition value in the 0x52 register.
  1071. */
  1072. static int8_t set_z_rep(const struct bmm150_dev *dev)
  1073. {
  1074. int8_t rslt;
  1075. uint8_t rep_z;
  1076. /* Check for null pointer in the device structure*/
  1077. rslt = null_ptr_check(dev);
  1078. /* Proceed if null check is fine */
  1079. if (rslt == BMM150_OK) {
  1080. /* set the z repetition */
  1081. rep_z = dev->settings.z_rep;
  1082. rslt = bmm150_set_regs(BMM150_REP_Z_ADDR, &rep_z, 1, dev);
  1083. }
  1084. return rslt;
  1085. }
  1086. /*!
  1087. * @brief This internal API is used to set the output data rate of the sensor.
  1088. */
  1089. static int8_t set_odr(const struct bmm150_dev *dev)
  1090. {
  1091. int8_t rslt;
  1092. uint8_t reg_data;
  1093. /* Check for null pointer in the device structure*/
  1094. rslt = null_ptr_check(dev);
  1095. /* Proceed if null check is fine */
  1096. if (rslt == BMM150_OK) {
  1097. /*Read the 0x4C register */
  1098. rslt = bmm150_get_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
  1099. if (rslt == BMM150_OK) {
  1100. /*Set the ODR value */
  1101. reg_data = BMM150_SET_BITS(reg_data, BMM150_ODR, dev->settings.data_rate);
  1102. rslt = bmm150_set_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
  1103. }
  1104. }
  1105. return rslt;
  1106. }
  1107. /*!
  1108. * @brief This internal API sets the preset mode ODR and repetition settings.
  1109. */
  1110. static int8_t set_odr_xyz_rep(const struct bmm150_dev *dev)
  1111. {
  1112. int8_t rslt;
  1113. /* Set the ODR */
  1114. rslt = set_odr(dev);
  1115. if (rslt == BMM150_OK) {
  1116. /* Set the XY-repetitions number */
  1117. rslt = set_xy_rep(dev);
  1118. if (rslt == BMM150_OK) {
  1119. /* Set the Z-repetitions number */
  1120. rslt = set_z_rep(dev);
  1121. }
  1122. }
  1123. return rslt;
  1124. }
  1125. /*!
  1126. * @brief This internal API is used to enable or disable the magnetic
  1127. * measurement of x,y,z axes based on the value of xyz_axes_control.
  1128. */
  1129. static int8_t set_control_measurement_xyz(const struct bmm150_dev *dev)
  1130. {
  1131. int8_t rslt;
  1132. uint8_t reg_data;
  1133. /* Check for null pointer in the device structure*/
  1134. rslt = null_ptr_check(dev);
  1135. /* Proceed if null check is fine */
  1136. if (rslt == BMM150_OK) {
  1137. rslt = bmm150_get_regs(BMM150_AXES_ENABLE_ADDR, &reg_data, 1, dev);
  1138. if (rslt == BMM150_OK) {
  1139. /* Set the axes to be enabled/disabled*/
  1140. reg_data = BMM150_SET_BITS(reg_data, BMM150_CONTROL_MEASURE, dev->settings.xyz_axes_control);
  1141. rslt = bmm150_set_regs(BMM150_AXES_ENABLE_ADDR, &reg_data, 1, dev);
  1142. }
  1143. }
  1144. return rslt;
  1145. }
  1146. /*!
  1147. * @brief This internal API is used to identify the settings which the user
  1148. * wants to modify in the sensor.
  1149. */
  1150. static uint8_t are_settings_changed(uint16_t sub_settings, uint16_t desired_settings)
  1151. {
  1152. uint8_t settings_changed = FALSE;
  1153. if (sub_settings & desired_settings) {
  1154. /* User wants to modify this particular settings */
  1155. settings_changed = TRUE;
  1156. } else {
  1157. /* User don't want to modify this particular settings */
  1158. settings_changed = FALSE;
  1159. }
  1160. return settings_changed;
  1161. }
  1162. /*!
  1163. * @brief This API sets the ODR , measurement axes control ,
  1164. * repetition values of xy,z.
  1165. */
  1166. static int8_t mode_settings(uint16_t desired_settings, const struct bmm150_dev *dev)
  1167. {
  1168. int8_t rslt = BMM150_E_INVALID_CONFIG;
  1169. if (desired_settings & BMM150_DATA_RATE_SEL) {
  1170. /* Sets the ODR */
  1171. rslt = set_odr(dev);
  1172. }
  1173. if (desired_settings & BMM150_CONTROL_MEASURE_SEL) {
  1174. /* Enables/Disables the control measurement axes */
  1175. rslt = set_control_measurement_xyz(dev);
  1176. }
  1177. if (desired_settings & BMM150_XY_REP_SEL) {
  1178. /* Sets the XY repetition */
  1179. rslt = set_xy_rep(dev);
  1180. }
  1181. if (desired_settings & BMM150_Z_REP_SEL) {
  1182. /* Sets the Z repetition */
  1183. rslt = set_z_rep(dev);
  1184. }
  1185. return rslt;
  1186. }
  1187. /*!
  1188. * @brief This internal API is used to parse and store the sensor
  1189. * settings in the device structure
  1190. */
  1191. static void parse_setting(const uint8_t *reg_data, struct bmm150_dev *dev)
  1192. {
  1193. /* Parse all the w/r registers and update the
  1194. current sensor settings in the dev structure*/
  1195. dev->settings.z_rep = reg_data[7];
  1196. dev->settings.xy_rep = reg_data[6];
  1197. dev->settings.int_settings.high_threshold = reg_data[5];
  1198. dev->settings.int_settings.low_threshold = reg_data[4];
  1199. dev->settings.xyz_axes_control = BMM150_GET_BITS(reg_data[3], BMM150_CONTROL_MEASURE);
  1200. dev->settings.int_settings.drdy_pin_en = BMM150_GET_BITS(reg_data[3], BMM150_DRDY_EN);
  1201. dev->settings.int_settings.int_pin_en = BMM150_GET_BITS(reg_data[3], BMM150_INT_PIN_EN);
  1202. dev->settings.int_settings.drdy_polarity = BMM150_GET_BITS(reg_data[3], BMM150_DRDY_POLARITY);
  1203. dev->settings.int_settings.int_latch = BMM150_GET_BITS(reg_data[3], BMM150_INT_LATCH);
  1204. dev->settings.int_settings.int_polarity = BMM150_GET_BITS_POS_0(reg_data[3], BMM150_INT_POLARITY);
  1205. dev->settings.int_settings.data_overrun_en = BMM150_GET_BITS(reg_data[2], BMM150_DATA_OVERRUN_INT);
  1206. dev->settings.int_settings.overflow_int_en = BMM150_GET_BITS(reg_data[2], BMM150_OVERFLOW_INT);
  1207. dev->settings.int_settings.high_int_en = BMM150_GET_BITS(reg_data[2], BMM150_HIGH_THRESHOLD_INT);
  1208. dev->settings.int_settings.low_int_en = BMM150_GET_BITS_POS_0(reg_data[2], BMM150_LOW_THRESHOLD_INT);
  1209. dev->settings.data_rate = BMM150_GET_BITS(reg_data[1], BMM150_ODR);
  1210. }
  1211. /*!
  1212. * @brief This API is used to enable the interrupts and map them to the
  1213. * corresponding interrupt pins and specify the pin characteristics like the
  1214. * polarity , latch settings for the interrupt pins.
  1215. */
  1216. static int8_t interrupt_pin_settings(uint16_t desired_settings, const struct bmm150_dev *dev)
  1217. {
  1218. int8_t rslt;
  1219. uint8_t reg_data;
  1220. struct bmm150_int_ctrl_settings int_settings;
  1221. rslt = bmm150_get_regs(BMM150_AXES_ENABLE_ADDR, &reg_data, 1, dev);
  1222. if (rslt == BMM150_OK) {
  1223. int_settings = dev->settings.int_settings;
  1224. if (desired_settings & BMM150_DRDY_PIN_EN_SEL) {
  1225. /* Enables the Data ready interrupt and
  1226. maps it to the DRDY pin of the sensor */
  1227. reg_data = BMM150_SET_BITS(reg_data, BMM150_DRDY_EN, int_settings.drdy_pin_en);
  1228. }
  1229. if (desired_settings & BMM150_INT_PIN_EN_SEL) {
  1230. /* Sets interrupt pin enable */
  1231. reg_data = BMM150_SET_BITS(reg_data, BMM150_INT_PIN_EN, int_settings.int_pin_en);
  1232. }
  1233. if (desired_settings & BMM150_DRDY_POLARITY_SEL) {
  1234. /* Sets Data ready pin's polarity */
  1235. reg_data = BMM150_SET_BITS(reg_data, BMM150_DRDY_POLARITY, int_settings.drdy_polarity);
  1236. }
  1237. if (desired_settings & BMM150_INT_LATCH_SEL) {
  1238. /* Sets Interrupt in latched or non-latched mode */
  1239. reg_data = BMM150_SET_BITS(reg_data, BMM150_INT_LATCH, int_settings.int_latch);
  1240. }
  1241. if (desired_settings & BMM150_INT_POLARITY_SEL) {
  1242. /* Sets Interrupt pin's polarity */
  1243. reg_data = BMM150_SET_BITS_POS_0(reg_data, BMM150_INT_POLARITY, int_settings.int_polarity);
  1244. }
  1245. /* Set the interrupt configurations in the 0x4E register */
  1246. rslt = bmm150_set_regs(BMM150_AXES_ENABLE_ADDR, &reg_data, 1, dev);
  1247. }
  1248. return rslt;
  1249. }
  1250. /*!
  1251. * @brief This API is used to enable data overrun , overflow interrupts and
  1252. * enable/disable high/low threshold interrupts for x,y,z axis based on the
  1253. * threshold values set by the user in the High threshold (0x50) and
  1254. * Low threshold (0x4F) registers.
  1255. */
  1256. static int8_t interrupt_config(uint16_t desired_settings, const struct bmm150_dev *dev)
  1257. {
  1258. int8_t rslt;
  1259. uint8_t reg_data;
  1260. struct bmm150_int_ctrl_settings int_settings;
  1261. rslt = bmm150_get_regs(BMM150_INT_CONFIG_ADDR, &reg_data, 1, dev);
  1262. if (rslt == BMM150_OK) {
  1263. int_settings = dev->settings.int_settings;
  1264. if (desired_settings & BMM150_DATA_OVERRUN_INT_SEL) {
  1265. /* Sets Data overrun interrupt */
  1266. reg_data = BMM150_SET_BITS(reg_data, BMM150_DATA_OVERRUN_INT, int_settings.data_overrun_en);
  1267. }
  1268. if (desired_settings & BMM150_OVERFLOW_INT_SEL) {
  1269. /* Sets Data overflow interrupt */
  1270. reg_data = BMM150_SET_BITS(reg_data, BMM150_OVERFLOW_INT, int_settings.overflow_int_en);
  1271. }
  1272. if (desired_settings & BMM150_HIGH_THRESHOLD_INT_SEL) {
  1273. /* Sets high threshold interrupt */
  1274. reg_data = BMM150_SET_BITS(reg_data, BMM150_HIGH_THRESHOLD_INT, int_settings.high_int_en);
  1275. }
  1276. if (desired_settings & BMM150_LOW_THRESHOLD_INT_SEL) {
  1277. /* Sets low threshold interrupt */
  1278. reg_data = BMM150_SET_BITS_POS_0(reg_data, BMM150_LOW_THRESHOLD_INT, int_settings.low_int_en);
  1279. }
  1280. /* Set the interrupt configurations in the 0x4D register */
  1281. rslt = bmm150_set_regs(BMM150_INT_CONFIG_ADDR, &reg_data, 1, dev);
  1282. }
  1283. return rslt;
  1284. }
  1285. /*!
  1286. * @brief This API is used to write the user specified High/Low threshold value
  1287. * as a reference to generate the high/low threshold interrupt.
  1288. */
  1289. static int8_t interrupt_threshold_settings(uint16_t desired_settings, const struct bmm150_dev *dev)
  1290. {
  1291. int8_t rslt = BMM150_E_INVALID_CONFIG;
  1292. uint8_t reg_data;
  1293. if (desired_settings & BMM150_LOW_THRESHOLD_SETTING_SEL) {
  1294. /* Sets the Low threshold value to trigger interrupt */
  1295. reg_data = dev->settings.int_settings.low_threshold;
  1296. rslt = bmm150_set_regs(BMM150_LOW_THRESHOLD_ADDR, &reg_data, 1, dev);
  1297. }
  1298. if (desired_settings & BMM150_HIGH_THRESHOLD_SETTING_SEL) {
  1299. /* Sets the High threshold value to trigger interrupt */
  1300. reg_data = dev->settings.int_settings.high_threshold;
  1301. rslt = bmm150_set_regs(BMM150_HIGH_THRESHOLD_ADDR, &reg_data, 1, dev);
  1302. }
  1303. return rslt;
  1304. }
  1305. #ifdef BMM150_USE_FLOATING_POINT
  1306. /*!
  1307. * @brief This internal API is used to obtain the compensated
  1308. * magnetometer x axis data(micro-tesla) in float.
  1309. */
  1310. static float compensate_x(int16_t mag_data_x, uint16_t data_rhall, const struct bmm150_dev *dev)
  1311. {
  1312. float retval = 0;
  1313. float process_comp_x0;
  1314. float process_comp_x1;
  1315. float process_comp_x2;
  1316. float process_comp_x3;
  1317. float process_comp_x4;
  1318. /* Overflow condition check */
  1319. if ((mag_data_x != BMM150_XYAXES_FLIP_OVERFLOW_ADCVAL) &&
  1320. (data_rhall != 0) && (dev->trim_data.dig_xyz1 != 0)) {
  1321. /*Processing compensation equations*/
  1322. process_comp_x0 = (((float)dev->trim_data.dig_xyz1) * 16384.0f / data_rhall);
  1323. retval = (process_comp_x0 - 16384.0f);
  1324. process_comp_x1 = ((float)dev->trim_data.dig_xy2) * (retval * retval / 268435456.0f);
  1325. process_comp_x2 = process_comp_x1 + retval * ((float)dev->trim_data.dig_xy1) / 16384.0f;
  1326. process_comp_x3 = ((float)dev->trim_data.dig_x2) + 160.0f;
  1327. process_comp_x4 = mag_data_x * ((process_comp_x2 + 256.0f) * process_comp_x3);
  1328. retval = ((process_comp_x4 / 8192.0f) + (((float)dev->trim_data.dig_x1) * 8.0f)) / 16.0f;
  1329. } else {
  1330. /* overflow, set output to 0.0f */
  1331. retval = BMM150_OVERFLOW_OUTPUT_FLOAT;
  1332. }
  1333. return retval;
  1334. }
  1335. /*!
  1336. * @brief This internal API is used to obtain the compensated
  1337. * magnetometer y axis data(micro-tesla) in float.
  1338. */
  1339. static float compensate_y(int16_t mag_data_y, uint16_t data_rhall, const struct bmm150_dev *dev)
  1340. {
  1341. float retval = 0;
  1342. float process_comp_y0;
  1343. float process_comp_y1;
  1344. float process_comp_y2;
  1345. float process_comp_y3;
  1346. float process_comp_y4;
  1347. /* Overflow condition check */
  1348. if ((mag_data_y != BMM150_XYAXES_FLIP_OVERFLOW_ADCVAL)
  1349. && (data_rhall != 0) && (dev->trim_data.dig_xyz1 != 0)) {
  1350. /*Processing compensation equations*/
  1351. process_comp_y0 = ((float)dev->trim_data.dig_xyz1) * 16384.0f / data_rhall;
  1352. retval = process_comp_y0 - 16384.0f;
  1353. process_comp_y1 = ((float)dev->trim_data.dig_xy2) * (retval * retval / 268435456.0f);
  1354. process_comp_y2 = process_comp_y1 + retval * ((float)dev->trim_data.dig_xy1) / 16384.0f;
  1355. process_comp_y3 = ((float)dev->trim_data.dig_y2) + 160.0f;
  1356. process_comp_y4 = mag_data_y * (((process_comp_y2) + 256.0f) * process_comp_y3);
  1357. retval = ((process_comp_y4 / 8192.0f) + (((float)dev->trim_data.dig_y1) * 8.0f)) / 16.0f;
  1358. } else {
  1359. /* overflow, set output to 0.0f */
  1360. retval = BMM150_OVERFLOW_OUTPUT_FLOAT;
  1361. }
  1362. return retval;
  1363. }
  1364. /*!
  1365. * @brief This internal API is used to obtain the compensated
  1366. * magnetometer z axis data(micro-tesla) in float.
  1367. */
  1368. static float compensate_z(int16_t mag_data_z, uint16_t data_rhall, const struct bmm150_dev *dev)
  1369. {
  1370. float retval = 0;
  1371. float process_comp_z0;
  1372. float process_comp_z1;
  1373. float process_comp_z2;
  1374. float process_comp_z3;
  1375. float process_comp_z4;
  1376. float process_comp_z5;
  1377. /* Overflow condition check */
  1378. if ((mag_data_z != BMM150_ZAXIS_HALL_OVERFLOW_ADCVAL) &&
  1379. (dev->trim_data.dig_z2 != 0) && (dev->trim_data.dig_z1 != 0)
  1380. && (dev->trim_data.dig_xyz1 != 0) && (data_rhall != 0)) {
  1381. /* Processing compensation equations */
  1382. process_comp_z0 = ((float)mag_data_z) - ((float)dev->trim_data.dig_z4);
  1383. process_comp_z1 = ((float)data_rhall) - ((float)dev->trim_data.dig_xyz1);
  1384. process_comp_z2 = (((float)dev->trim_data.dig_z3) * process_comp_z1);
  1385. process_comp_z3 = ((float)dev->trim_data.dig_z1) * ((float)data_rhall) / 32768.0f;
  1386. process_comp_z4 = ((float)dev->trim_data.dig_z2) + process_comp_z3;
  1387. process_comp_z5 = (process_comp_z0 * 131072.0f) - process_comp_z2;
  1388. retval = (process_comp_z5 / ((process_comp_z4) * 4.0f)) / 16.0f;
  1389. } else {
  1390. /* overflow, set output to 0.0f */
  1391. retval = BMM150_OVERFLOW_OUTPUT_FLOAT;
  1392. }
  1393. return retval;
  1394. }
  1395. #else
  1396. /*!
  1397. * @brief This internal API is used to obtain the compensated
  1398. * magnetometer X axis data(micro-tesla) in int16_t.
  1399. */
  1400. static int16_t compensate_x(int16_t mag_data_x, uint16_t data_rhall, const struct bmm150_dev *dev)
  1401. {
  1402. int16_t retval;
  1403. uint16_t process_comp_x0 = 0;
  1404. int32_t process_comp_x1;
  1405. uint16_t process_comp_x2;
  1406. int32_t process_comp_x3;
  1407. int32_t process_comp_x4;
  1408. int32_t process_comp_x5;
  1409. int32_t process_comp_x6;
  1410. int32_t process_comp_x7;
  1411. int32_t process_comp_x8;
  1412. int32_t process_comp_x9;
  1413. int32_t process_comp_x10;
  1414. /* Overflow condition check */
  1415. if (mag_data_x != BMM150_XYAXES_FLIP_OVERFLOW_ADCVAL) {
  1416. if (data_rhall != 0) {
  1417. /* Availability of valid data*/
  1418. process_comp_x0 = data_rhall;
  1419. } else if (dev->trim_data.dig_xyz1 != 0) {
  1420. process_comp_x0 = dev->trim_data.dig_xyz1;
  1421. } else {
  1422. process_comp_x0 = 0;
  1423. }
  1424. if (process_comp_x0 != 0) {
  1425. /* Processing compensation equations*/
  1426. process_comp_x1 = ((int32_t)dev->trim_data.dig_xyz1) * 16384;
  1427. process_comp_x2 = ((uint16_t)(process_comp_x1 / process_comp_x0)) - ((uint16_t)0x4000);
  1428. retval = ((int16_t)process_comp_x2);
  1429. process_comp_x3 = (((int32_t)retval) * ((int32_t)retval));
  1430. process_comp_x4 = (((int32_t)dev->trim_data.dig_xy2) * (process_comp_x3 / 128));
  1431. process_comp_x5 = (int32_t)(((int16_t)dev->trim_data.dig_xy1) * 128);
  1432. process_comp_x6 = ((int32_t)retval) * process_comp_x5;
  1433. process_comp_x7 = (((process_comp_x4 + process_comp_x6) / 512) + ((int32_t)0x100000));
  1434. process_comp_x8 = ((int32_t)(((int16_t)dev->trim_data.dig_x2) + ((int16_t)0xA0)));
  1435. process_comp_x9 = ((process_comp_x7 * process_comp_x8) / 4096);
  1436. process_comp_x10 = ((int32_t)mag_data_x) * process_comp_x9;
  1437. retval = ((int16_t)(process_comp_x10 / 8192));
  1438. retval = (retval + (((int16_t)dev->trim_data.dig_x1) * 8)) / 16;
  1439. } else {
  1440. retval = BMM150_OVERFLOW_OUTPUT;
  1441. }
  1442. } else {
  1443. /* Overflow condition */
  1444. retval = BMM150_OVERFLOW_OUTPUT;
  1445. }
  1446. return retval;
  1447. }
  1448. /*!
  1449. * @brief This internal API is used to obtain the compensated
  1450. * magnetometer Y axis data(micro-tesla) in int16_t.
  1451. */
  1452. static int16_t compensate_y(int16_t mag_data_y, uint16_t data_rhall, const struct bmm150_dev *dev)
  1453. {
  1454. int16_t retval;
  1455. uint16_t process_comp_y0 = 0;
  1456. int32_t process_comp_y1;
  1457. uint16_t process_comp_y2;
  1458. int32_t process_comp_y3;
  1459. int32_t process_comp_y4;
  1460. int32_t process_comp_y5;
  1461. int32_t process_comp_y6;
  1462. int32_t process_comp_y7;
  1463. int32_t process_comp_y8;
  1464. int32_t process_comp_y9;
  1465. /* Overflow condition check */
  1466. if (mag_data_y != BMM150_XYAXES_FLIP_OVERFLOW_ADCVAL) {
  1467. if (data_rhall != 0) {
  1468. /* Availability of valid data*/
  1469. process_comp_y0 = data_rhall;
  1470. } else if (dev->trim_data.dig_xyz1 != 0) {
  1471. process_comp_y0 = dev->trim_data.dig_xyz1;
  1472. } else {
  1473. process_comp_y0 = 0;
  1474. }
  1475. if (process_comp_y0 != 0) {
  1476. /*Processing compensation equations*/
  1477. process_comp_y1 = (((int32_t)dev->trim_data.dig_xyz1) * 16384) / process_comp_y0;
  1478. process_comp_y2 = ((uint16_t)process_comp_y1) - ((uint16_t)0x4000);
  1479. retval = ((int16_t)process_comp_y2);
  1480. process_comp_y3 = ((int32_t) retval) * ((int32_t)retval);
  1481. process_comp_y4 = ((int32_t)dev->trim_data.dig_xy2) * (process_comp_y3 / 128);
  1482. process_comp_y5 = ((int32_t)(((int16_t)dev->trim_data.dig_xy1) * 128));
  1483. process_comp_y6 = ((process_comp_y4 + (((int32_t)retval) * process_comp_y5)) / 512);
  1484. process_comp_y7 = ((int32_t)(((int16_t)dev->trim_data.dig_y2) + ((int16_t)0xA0)));
  1485. process_comp_y8 = (((process_comp_y6 + ((int32_t)0x100000)) * process_comp_y7) / 4096);
  1486. process_comp_y9 = (((int32_t)mag_data_y) * process_comp_y8);
  1487. retval = (int16_t)(process_comp_y9 / 8192);
  1488. retval = (retval + (((int16_t)dev->trim_data.dig_y1) * 8)) / 16;
  1489. } else {
  1490. retval = BMM150_OVERFLOW_OUTPUT;
  1491. }
  1492. } else {
  1493. /* Overflow condition*/
  1494. retval = BMM150_OVERFLOW_OUTPUT;
  1495. }
  1496. return retval;
  1497. }
  1498. /*!
  1499. * @brief This internal API is used to obtain the compensated
  1500. * magnetometer Z axis data(micro-tesla) in int16_t.
  1501. */
  1502. static int16_t compensate_z(int16_t mag_data_z, uint16_t data_rhall, const struct bmm150_dev *dev)
  1503. {
  1504. int32_t retval;
  1505. int16_t process_comp_z0;
  1506. int32_t process_comp_z1;
  1507. int32_t process_comp_z2;
  1508. int32_t process_comp_z3;
  1509. int16_t process_comp_z4;
  1510. if (mag_data_z != BMM150_ZAXIS_HALL_OVERFLOW_ADCVAL) {
  1511. if ((dev->trim_data.dig_z2 != 0) && (dev->trim_data.dig_z1 != 0)
  1512. && (data_rhall != 0) && (dev->trim_data.dig_xyz1 != 0)) {
  1513. /*Processing compensation equations*/
  1514. process_comp_z0 = ((int16_t)data_rhall) - ((int16_t) dev->trim_data.dig_xyz1);
  1515. process_comp_z1 = (((int32_t)dev->trim_data.dig_z3) * ((int32_t)(process_comp_z0))) / 4;
  1516. process_comp_z2 = (((int32_t)(mag_data_z - dev->trim_data.dig_z4)) * 32768);
  1517. process_comp_z3 = ((int32_t)dev->trim_data.dig_z1) * (((int16_t)data_rhall) * 2);
  1518. process_comp_z4 = (int16_t)((process_comp_z3 + (32768)) / 65536);
  1519. retval = ((process_comp_z2 - process_comp_z1) / (dev->trim_data.dig_z2 + process_comp_z4));
  1520. /* saturate result to +/- 2 micro-tesla */
  1521. if (retval > BMM150_POSITIVE_SATURATION_Z) {
  1522. retval = BMM150_POSITIVE_SATURATION_Z;
  1523. } else {
  1524. if (retval < BMM150_NEGATIVE_SATURATION_Z)
  1525. retval = BMM150_NEGATIVE_SATURATION_Z;
  1526. }
  1527. /* Conversion of LSB to micro-tesla*/
  1528. retval = retval / 16;
  1529. } else {
  1530. retval = BMM150_OVERFLOW_OUTPUT;
  1531. }
  1532. } else {
  1533. /* Overflow condition*/
  1534. retval = BMM150_OVERFLOW_OUTPUT;
  1535. }
  1536. return (int16_t)retval;
  1537. }
  1538. #endif
  1539. /*!
  1540. * @brief This internal API is used to perform the normal self test
  1541. * of the sensor and return the self test result as return value
  1542. */
  1543. static int8_t perform_normal_self_test(const struct bmm150_dev *dev)
  1544. {
  1545. int8_t rslt;
  1546. uint8_t self_test_bit;
  1547. /* Triggers the start of normal self test */
  1548. rslt = enable_normal_self_test(&self_test_bit, dev);
  1549. /* Check for self test completion status */
  1550. if ((rslt == BMM150_OK) && (self_test_bit == 0)) {
  1551. /* Validates the self test results for all 3 axes */
  1552. rslt = validate_normal_self_test(dev);
  1553. }
  1554. return rslt;
  1555. }
  1556. /*!
  1557. * @brief This internal API is used to enable the normal self test by setting
  1558. * the Self Test bit (bit0) of the 0x4C register,
  1559. * which triggers the start of self test
  1560. */
  1561. static int8_t enable_normal_self_test(uint8_t *self_test_enable, const struct bmm150_dev *dev)
  1562. {
  1563. int8_t rslt;
  1564. uint8_t reg_data;
  1565. uint8_t self_test_val;
  1566. /* Read the data from register 0x4C */
  1567. rslt = bmm150_get_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
  1568. if (rslt == BMM150_OK) {
  1569. /* Set the Self Test bit(bit0) of the 0x4C register */
  1570. self_test_val = 1;
  1571. reg_data = BMM150_SET_BITS_POS_0(reg_data, BMM150_SELF_TEST, self_test_val);
  1572. /* Write the data to 0x4C register to trigger self test */
  1573. rslt = bmm150_set_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
  1574. dev->delay_ms(BMM150_NORMAL_SELF_TEST_DELAY);
  1575. if (rslt == BMM150_OK) {
  1576. /* Read the data from register 0x4C */
  1577. rslt = bmm150_get_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
  1578. /* Self Test bit(bit0) is stored in self_test_enable,
  1579. It will be reset to zero after the self test is over */
  1580. *self_test_enable = BMM150_GET_BITS_POS_0(reg_data, BMM150_SELF_TEST);
  1581. }
  1582. }
  1583. return rslt;
  1584. }
  1585. /*!
  1586. * @brief This internal API is used to validate the results of normal self test
  1587. * by using the self test status available in the bit0 of registers 0x42,0x44
  1588. * and 0x46.
  1589. */
  1590. static int8_t validate_normal_self_test(const struct bmm150_dev *dev)
  1591. {
  1592. int8_t rslt;
  1593. uint8_t status;
  1594. uint8_t self_test_rslt[5];
  1595. /* Read the data from register 0x42 to 0x46 */
  1596. rslt = bmm150_get_regs(BMM150_DATA_X_LSB, self_test_rslt, BMM150_SELF_TEST_LEN, dev);
  1597. if (rslt == BMM150_OK) {
  1598. /* Parse and get the self test status bits */
  1599. /* X-Self-Test (bit0) of 0x42 register is stored*/
  1600. self_test_rslt[0] = BMM150_GET_BITS_POS_0(self_test_rslt[0], BMM150_SELF_TEST);
  1601. /* Y-Self-Test (bit0) of 0x44 register is stored */
  1602. self_test_rslt[2] = BMM150_GET_BITS_POS_0(self_test_rslt[2], BMM150_SELF_TEST);
  1603. /* Z-Self-Test (bit0) of 0x46 register is stored */
  1604. self_test_rslt[4] = BMM150_GET_BITS_POS_0(self_test_rslt[4], BMM150_SELF_TEST);
  1605. /* Combine the self test status and store it in the first
  1606. 3 bits of the status variable for processing*/
  1607. status = (uint8_t)((self_test_rslt[4] << 2) | (self_test_rslt[2] << 1) | self_test_rslt[0]);
  1608. /* Validate status and store Self test result in "rslt" */
  1609. if (status == BMM150_SELF_TEST_STATUS_SUCCESS) {
  1610. /* Self test is success when all status bits are set */
  1611. rslt = BMM150_OK;
  1612. } else {
  1613. if (status == BMM150_SELF_TEST_STATUS_XYZ_FAIL) {
  1614. /* Self test - all axis fail condition */
  1615. rslt = BMM150_W_NORMAL_SELF_TEST_XYZ_FAIL;
  1616. } else {
  1617. /* Self test - some axis fail condition */
  1618. rslt = (int8_t)status;
  1619. }
  1620. }
  1621. }
  1622. return rslt;
  1623. }
  1624. /*!
  1625. * @brief This internal API is used to perform advanced self test for Z axis
  1626. */
  1627. static int8_t perform_adv_self_test(struct bmm150_dev *dev)
  1628. {
  1629. int8_t rslt;
  1630. uint8_t self_test_current;
  1631. int16_t positive_data_z;
  1632. int16_t negative_data_z;
  1633. /* Set the desired power mode ,axes control and repetition settings */
  1634. rslt = adv_self_test_settings(dev);
  1635. if (rslt == BMM150_OK) {
  1636. /* Measure the Z axes data with positive self-test current */
  1637. self_test_current = BMM150_ENABLE_POSITIVE_CURRENT;
  1638. rslt = adv_self_test_measurement(self_test_current, &positive_data_z, dev);
  1639. if (rslt == BMM150_OK) {
  1640. /* Measure the Z axes data with
  1641. negative self-test current */
  1642. self_test_current = BMM150_ENABLE_NEGATIVE_CURRENT;
  1643. rslt = adv_self_test_measurement(self_test_current, &negative_data_z, dev);
  1644. if (rslt == BMM150_OK) {
  1645. /* Disable self-test current */
  1646. self_test_current = BMM150_DISABLE_SELF_TEST_CURRENT;
  1647. rslt = set_adv_self_test_current(self_test_current, dev);
  1648. if (rslt == BMM150_OK) {
  1649. /* Validate the advanced self test */
  1650. rslt = validate_adv_self_test(positive_data_z, negative_data_z);
  1651. }
  1652. }
  1653. }
  1654. }
  1655. return rslt;
  1656. }
  1657. /*!
  1658. * @brief This internal API is used to set the desired power mode ,
  1659. * axes control and repetition settings for advanced self test
  1660. */
  1661. static int8_t adv_self_test_settings(struct bmm150_dev *dev)
  1662. {
  1663. int8_t rslt;
  1664. /* Set the power mode as sleep mode */
  1665. dev->settings.pwr_mode = BMM150_SLEEP_MODE;
  1666. rslt = bmm150_set_op_mode(dev);
  1667. if (rslt == BMM150_OK) {
  1668. /* Disable XY-axis measurement */
  1669. dev->settings.xyz_axes_control = BMM150_DISABLE_XY_AXIS;
  1670. rslt = set_control_measurement_xyz(dev);
  1671. if (rslt == BMM150_OK) {
  1672. /* Repetition value is set as 0x04 */
  1673. dev->settings.z_rep = BMM150_SELF_TEST_REP_Z;
  1674. rslt = set_z_rep(dev);
  1675. }
  1676. }
  1677. return rslt;
  1678. }
  1679. /*!
  1680. * @brief This internal API is used to set the positive or negative value of
  1681. * self-test current and obtain the corresponding magnetometer z axis data
  1682. */
  1683. static int8_t adv_self_test_measurement(uint8_t self_test_current, int16_t *data_z, struct bmm150_dev *dev)
  1684. {
  1685. int8_t rslt;
  1686. /* Set the advanced self test current as positive or
  1687. negative based on the value of parameter "self_test_current" */
  1688. rslt = set_adv_self_test_current(self_test_current, dev);
  1689. if (rslt == BMM150_OK) {
  1690. /* Set the device in forced mode*/
  1691. dev->settings.pwr_mode = BMM150_FORCED_MODE;
  1692. rslt = bmm150_set_op_mode(dev);
  1693. /* Delay to ensure measurement is complete */
  1694. dev->delay_ms(BMM150_ADV_SELF_TEST_DELAY);
  1695. if (rslt == BMM150_OK) {
  1696. /* Read Mag data and store the value of Z axis data */
  1697. rslt = bmm150_read_mag_data(dev);
  1698. if (rslt == BMM150_OK) {
  1699. /* Mag Z axis data is stored */
  1700. *data_z = dev->data.z;
  1701. }
  1702. }
  1703. }
  1704. return rslt;
  1705. }
  1706. /*!
  1707. * @brief This internal API is used to get the difference between the
  1708. * Z axis mag data obtained by positive and negative self-test current
  1709. * and validate whether the advanced self test is done successfully or not.
  1710. */
  1711. static int8_t validate_adv_self_test(int16_t positive_data_z, int16_t negative_data_z)
  1712. {
  1713. int32_t adv_self_test_rslt;
  1714. int8_t rslt;
  1715. /* Advanced self test difference between the Z axis mag data
  1716. obtained by the positive and negative self-test current */
  1717. adv_self_test_rslt = positive_data_z - negative_data_z;
  1718. /* Advanced self test validation */
  1719. /*Value of adv_self_test_rslt should be in between 180-240 micro-tesla*/
  1720. if ((adv_self_test_rslt > 180) && (adv_self_test_rslt < 240)) {
  1721. /* Advanced self test success */
  1722. rslt = BMM150_OK;
  1723. } else {
  1724. /* Advanced self test fail */
  1725. rslt = BMM150_W_ADV_SELF_TEST_FAIL;
  1726. }
  1727. return rslt;
  1728. }
  1729. /*!
  1730. * @brief This internal API is used to set the self test current value in
  1731. * the Adv. ST bits (bit6 and bit7) of 0x4C register
  1732. */
  1733. static int8_t set_adv_self_test_current(uint8_t self_test_current, const struct bmm150_dev *dev)
  1734. {
  1735. int8_t rslt;
  1736. uint8_t reg_data;
  1737. /* Read the 0x4C register */
  1738. rslt = bmm150_get_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
  1739. if (rslt == BMM150_OK) {
  1740. /* Set the self test current value in the Adv. ST bits
  1741. (bit6 and bit7) of 0x4c register */
  1742. reg_data = BMM150_SET_BITS(reg_data, BMM150_ADV_SELF_TEST, self_test_current);
  1743. rslt = bmm150_set_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
  1744. }
  1745. return rslt;
  1746. }