VL6180_ATY.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153
  1. /**
  2. * @file VL6180_ATY.c
  3. *
  4. * @param Project DEVICE_GENERAL_ATY_LIB
  5. *
  6. * @author ATY
  7. *
  8. * @copyright
  9. * - Copyright 2017 - 2026 MZ-ATY
  10. * - This code follows:
  11. * - MZ-ATY Various Contents Joint Statement -
  12. * <a href="https://mengze.top/MZ-ATY_VCJS">
  13. * https://mengze.top/MZ-ATY_VCJS</a>
  14. * - CC 4.0 BY-NC-SA -
  15. * <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">
  16. * https://creativecommons.org/licenses/by-nc-sa/4.0/</a>
  17. * - Your use will be deemed to have accepted the terms of this statement.
  18. *
  19. * @brief functions of VL6180 proximity and ambient light sensor for all embedded device
  20. *
  21. * @version
  22. * - 1_00_250101 > ATY
  23. * -# Initial version, support I2C communication, range and ALS measurement
  24. ********************************************************************************
  25. */
  26. #include "VL6180_ATY.h"
  27. /******************************* Private Functions *****************************/
  28. /**
  29. * @brief Check if device is initialized, auto-initialize if not
  30. * @param dev Pointer to VL6180 device structure
  31. * @return VL6180_STATUS_OK if successful
  32. */
  33. static uint8_t VL6180_CheckAndAutoInit(struct VL6180_ATY_Dev *dev)
  34. {
  35. if (!dev->initialized) {
  36. if (dev->debugEnable && dev->LOG) {
  37. dev->LOG("VL6180: Auto-initializing device...\n");
  38. }
  39. return VL6180_Init(dev);
  40. }
  41. return VL6180_STATUS_OK;
  42. }
  43. /**
  44. * @brief VL6180 default initialization settings
  45. * @param dev Pointer to VL6180 device structure
  46. * @return VL6180_STATUS_OK if successful
  47. */
  48. static uint8_t VL6180_ApplyDefaultSettings(struct VL6180_ATY_Dev *dev)
  49. {
  50. // Mandatory: Private registers
  51. VL6180_WriteRegister8(dev, 0x0207, 0x01);
  52. VL6180_WriteRegister8(dev, 0x0208, 0x01);
  53. VL6180_WriteRegister8(dev, 0x0096, 0x00);
  54. VL6180_WriteRegister8(dev, 0x0097, 0xfd);
  55. VL6180_WriteRegister8(dev, 0x00e3, 0x00);
  56. VL6180_WriteRegister8(dev, 0x00e4, 0x04);
  57. VL6180_WriteRegister8(dev, 0x00e5, 0x02);
  58. VL6180_WriteRegister8(dev, 0x00e6, 0x01);
  59. VL6180_WriteRegister8(dev, 0x00e7, 0x03);
  60. VL6180_WriteRegister8(dev, 0x00f5, 0x02);
  61. VL6180_WriteRegister8(dev, 0x00d9, 0x05);
  62. VL6180_WriteRegister8(dev, 0x00db, 0xce);
  63. VL6180_WriteRegister8(dev, 0x00dc, 0x03);
  64. VL6180_WriteRegister8(dev, 0x00dd, 0xf8);
  65. VL6180_WriteRegister8(dev, 0x009f, 0x00);
  66. VL6180_WriteRegister8(dev, 0x00a3, 0x3c);
  67. VL6180_WriteRegister8(dev, 0x00b7, 0x00);
  68. VL6180_WriteRegister8(dev, 0x00bb, 0x3c);
  69. VL6180_WriteRegister8(dev, 0x00b2, 0x09);
  70. VL6180_WriteRegister8(dev, 0x00ca, 0x09);
  71. VL6180_WriteRegister8(dev, 0x0198, 0x01);
  72. VL6180_WriteRegister8(dev, 0x01b0, 0x17);
  73. VL6180_WriteRegister8(dev, 0x01ad, 0x00);
  74. VL6180_WriteRegister8(dev, 0x00ff, 0x05);
  75. VL6180_WriteRegister8(dev, 0x0100, 0x05);
  76. VL6180_WriteRegister8(dev, 0x0199, 0x05);
  77. VL6180_WriteRegister8(dev, 0x01a6, 0x1b);
  78. VL6180_WriteRegister8(dev, 0x01ac, 0x3e);
  79. VL6180_WriteRegister8(dev, 0x01a7, 0x1f);
  80. VL6180_WriteRegister8(dev, 0x0030, 0x00);
  81. // Recommended: Public registers - See data sheet for more detail
  82. VL6180_WriteRegister8(dev, VL6180_REG_SYSTEM_MODE_GPIO1, 0x10); // Enables polling for 'New Sample ready'
  83. VL6180_WriteRegister8(dev, VL6180_REG_READOUT_AVERAGING_SAMPLE_PERIOD, 0x30); // Set the averaging sample period
  84. VL6180_WriteRegister8(dev, VL6180_REG_SYSALS_ANALOGUE_GAIN, 0x46); // Light sensor gain settings
  85. VL6180_WriteRegister8(dev, VL6180_REG_SYSRANGE_VHV_REPEAT_RATE, 0xFF); // Set auto calibration period
  86. VL6180_WriteRegister8(dev, VL6180_REG_SYSALS_INTEGRATION_PERIOD, 0x63); // ALS integration time
  87. VL6180_WriteRegister8(dev, VL6180_REG_SYSRANGE_VHV_RECALIBRATE, 0x01); // perform a single temperature calibration
  88. VL6180_WriteRegister8(dev, VL6180_REG_SYSRANGE_INTERMEASUREMENT_PERIOD, 0x09); // Set default ranging inter-measurement period to 100ms
  89. VL6180_WriteRegister8(dev, VL6180_REG_SYSALS_INTERMEASUREMENT_PERIOD, 0x31); // Set default ALS inter-measurement period to 500ms
  90. VL6180_WriteRegister8(dev, VL6180_REG_SYSTEM_INTERRUPT_CONFIG_GPIO, 0x24); // Configures interrupt on 'New Sample Ready threshold event'
  91. // Clear fresh out of reset flag
  92. VL6180_WriteRegister8(dev, VL6180_REG_SYSTEM_FRESH_OUT_OF_RESET, 0x00);
  93. return VL6180_STATUS_OK;
  94. }
  95. /******************************* Public Functions *****************************/
  96. /**
  97. * @brief Initialize VL6180 device
  98. * @param dev Pointer to VL6180 device structure
  99. * @return VL6180_STATUS_OK if successful
  100. */
  101. uint8_t VL6180_Init(struct VL6180_ATY_Dev *dev)
  102. {
  103. if (!dev) {
  104. return VL6180_STATUS_ERROR;
  105. }
  106. if (dev->debugEnable && dev->LOG) {
  107. dev->LOG("VL6180: Initializing device...\n");
  108. }
  109. // Set default I2C address if not set
  110. if (dev->i2cAddress == 0) {
  111. dev->i2cAddress = VL6180_I2C_ADDR_DEFAULT;
  112. }
  113. // Check if device is present
  114. uint8_t modelId;
  115. if (VL6180_ReadRegister8(dev, VL6180_REG_IDENTIFICATION_MODEL_ID, &modelId) != VL6180_STATUS_OK) {
  116. dev->devicePresent = 0;
  117. dev->lastStatus = VL6180_STATUS_NO_DEVICE;
  118. if (dev->debugEnable && dev->LOG) {
  119. dev->LOG("VL6180: Device not found!\n");
  120. }
  121. return VL6180_STATUS_NO_DEVICE;
  122. }
  123. if (modelId != 0xB4) {
  124. dev->devicePresent = 0;
  125. dev->lastStatus = VL6180_STATUS_NO_DEVICE;
  126. if (dev->debugEnable && dev->LOG) {
  127. dev->LOG("VL6180: Invalid model ID: 0x%02X\n", modelId);
  128. }
  129. return VL6180_STATUS_NO_DEVICE;
  130. }
  131. dev->devicePresent = 1;
  132. dev->modelId = modelId;
  133. // Read device identification
  134. VL6180_ReadDeviceID(dev);
  135. // Check if fresh out of reset
  136. uint8_t freshOutOfReset;
  137. VL6180_ReadRegister8(dev, VL6180_REG_SYSTEM_FRESH_OUT_OF_RESET, &freshOutOfReset);
  138. dev->freshOutOfReset = freshOutOfReset;
  139. if (freshOutOfReset == 0x01) {
  140. // Apply default settings
  141. VL6180_ApplyDefaultSettings(dev);
  142. if (dev->debugEnable && dev->LOG) {
  143. dev->LOG("VL6180: Applied default settings\n");
  144. }
  145. }
  146. // Set default configuration
  147. dev->alsGain = VL6180_ALS_GAIN_1;
  148. dev->alsIntegrationPeriod = 100;
  149. dev->rangeMaxConvergenceTime = 50;
  150. dev->rangeOffset = 0;
  151. dev->crosstalkCompensationRate = 0;
  152. dev->initialized = 1;
  153. dev->lastStatus = VL6180_STATUS_OK;
  154. if (dev->debugEnable && dev->LOG) {
  155. dev->LOG("VL6180: Initialization completed successfully\n");
  156. }
  157. return VL6180_STATUS_OK;
  158. }
  159. /**
  160. * @brief Reset VL6180 device
  161. * @param dev Pointer to VL6180 device structure
  162. * @return VL6180_STATUS_OK if successful
  163. */
  164. uint8_t VL6180_Reset(struct VL6180_ATY_Dev *dev)
  165. {
  166. if (!dev) {
  167. return VL6180_STATUS_ERROR;
  168. }
  169. if (dev->debugEnable && dev->LOG) {
  170. dev->LOG("VL6180: Resetting device...\n");
  171. }
  172. // Clear all interrupt flags
  173. VL6180_WriteRegister8(dev, VL6180_REG_SYSTEM_INTERRUPT_CLEAR, 0x07);
  174. // Reset device state
  175. dev->initialized = 0;
  176. dev->devicePresent = 0;
  177. dev->rangeValue = 0;
  178. dev->alsValue = 0;
  179. dev->rangeStatus = 0;
  180. dev->alsStatus = 0;
  181. dev->lastStatus = VL6180_STATUS_OK;
  182. return VL6180_STATUS_OK;
  183. }
  184. /**
  185. * @brief Read device identification information
  186. * @param dev Pointer to VL6180 device structure
  187. * @return VL6180_STATUS_OK if successful
  188. */
  189. uint8_t VL6180_ReadDeviceID(struct VL6180_ATY_Dev *dev)
  190. {
  191. if (!dev) {
  192. return VL6180_STATUS_ERROR;
  193. }
  194. VL6180_ReadRegister8(dev, VL6180_REG_IDENTIFICATION_MODEL_ID, &dev->modelId);
  195. VL6180_ReadRegister8(dev, VL6180_REG_IDENTIFICATION_MODEL_REV_MAJOR, &dev->modelRevMajor);
  196. VL6180_ReadRegister8(dev, VL6180_REG_IDENTIFICATION_MODEL_REV_MINOR, &dev->modelRevMinor);
  197. VL6180_ReadRegister8(dev, VL6180_REG_IDENTIFICATION_MODULE_REV_MAJOR, &dev->moduleRevMajor);
  198. VL6180_ReadRegister8(dev, VL6180_REG_IDENTIFICATION_MODULE_REV_MINOR, &dev->moduleRevMinor);
  199. if (dev->debugEnable && dev->LOG) {
  200. dev->LOG("VL6180: Model ID: 0x%02X, Rev: %d.%d, Module Rev: %d.%d\n",
  201. dev->modelId, dev->modelRevMajor, dev->modelRevMinor,
  202. dev->moduleRevMajor, dev->moduleRevMinor);
  203. }
  204. return VL6180_STATUS_OK;
  205. }
  206. /**
  207. * @brief Load default settings to VL6180
  208. * @param dev Pointer to VL6180 device structure
  209. * @return VL6180_STATUS_OK if successful
  210. */
  211. uint8_t VL6180_LoadDefaultSettings(struct VL6180_ATY_Dev *dev)
  212. {
  213. if (!dev) {
  214. return VL6180_STATUS_ERROR;
  215. }
  216. return VL6180_ApplyDefaultSettings(dev);
  217. }
  218. /******************************* Range Measurement Functions *****************/
  219. /**
  220. * @brief Start range measurement
  221. * @param dev Pointer to VL6180 device structure
  222. * @param mode Measurement mode (single shot or continuous)
  223. * @return VL6180_STATUS_OK if successful
  224. */
  225. uint8_t VL6180_StartRangeMeasurement(struct VL6180_ATY_Dev *dev, uint8_t mode)
  226. {
  227. if (!dev) {
  228. return VL6180_STATUS_ERROR;
  229. }
  230. // Auto-initialize if not initialized
  231. uint8_t status = VL6180_CheckAndAutoInit(dev);
  232. if (status != VL6180_STATUS_OK) {
  233. return status;
  234. }
  235. if (dev->lock) {
  236. if (dev->debugEnable && dev->LOG) {
  237. dev->LOG("VL6180: Device is locked\n");
  238. }
  239. return VL6180_STATUS_ERROR;
  240. }
  241. dev->lock = 1;
  242. if (dev->debugEnable && dev->LOG) {
  243. dev->LOG("VL6180: Starting range measurement (mode: %d)\n", mode);
  244. }
  245. // Clear any existing interrupts
  246. VL6180_ClearRangeInterrupt(dev);
  247. // Start measurement
  248. status = VL6180_WriteRegister8(dev, VL6180_REG_SYSRANGE_START, mode);
  249. dev->lock = 0;
  250. dev->lastStatus = status;
  251. return status;
  252. }
  253. /**
  254. * @brief Read range measurement result
  255. * @param dev Pointer to VL6180 device structure
  256. * @return VL6180_STATUS_OK if successful
  257. */
  258. uint8_t VL6180_ReadRangeResult(struct VL6180_ATY_Dev *dev)
  259. {
  260. if (!dev) {
  261. return VL6180_STATUS_ERROR;
  262. }
  263. // Auto-initialize if not initialized
  264. uint8_t status = VL6180_CheckAndAutoInit(dev);
  265. if (status != VL6180_STATUS_OK) {
  266. return status;
  267. }
  268. if (dev->lock) {
  269. return VL6180_STATUS_ERROR;
  270. }
  271. dev->lock = 1;
  272. // Read range value
  273. VL6180_ReadRegister8(dev, VL6180_REG_RESULT_RANGE_VAL, &dev->rangeValue);
  274. // Read range status
  275. VL6180_ReadRegister8(dev, VL6180_REG_RESULT_RANGE_STATUS, &dev->rangeStatus);
  276. // Read additional range data
  277. VL6180_ReadRegister16(dev, VL6180_REG_RESULT_RANGE_RAW, &dev->rangeRaw);
  278. VL6180_ReadRegister16(dev, VL6180_REG_RESULT_RANGE_RETURN_RATE, &dev->rangeRate);
  279. VL6180_ReadRegister32(dev, VL6180_REG_RESULT_RANGE_RETURN_SIGNAL_COUNT, &dev->rangeSignalCount);
  280. VL6180_ReadRegister32(dev, VL6180_REG_RESULT_RANGE_RETURN_AMB_COUNT, &dev->rangeAmbientCount);
  281. VL6180_ReadRegister16(dev, VL6180_REG_RESULT_RANGE_RETURN_CONV_TIME, &dev->rangeConvergenceTime);
  282. if (dev->debugEnable && dev->LOG) {
  283. dev->LOG("VL6180: Range: %dmm, Status: 0x%02X, Rate: %d\n",
  284. dev->rangeValue, dev->rangeStatus, dev->rangeRate);
  285. }
  286. dev->lock = 0;
  287. dev->lastStatus = VL6180_STATUS_OK;
  288. return VL6180_STATUS_OK;
  289. }
  290. /**
  291. * @brief Get range measurement value
  292. * @param dev Pointer to VL6180 device structure
  293. * @return Range value in millimeters
  294. */
  295. uint8_t VL6180_GetRangeValue(struct VL6180_ATY_Dev *dev)
  296. {
  297. if (!dev) {
  298. return 0;
  299. }
  300. return dev->rangeValue;
  301. }
  302. /**
  303. * @brief Check if range measurement is ready
  304. * @param dev Pointer to VL6180 device structure
  305. * @return 1 if ready, 0 if not ready
  306. */
  307. uint8_t VL6180_IsRangeReady(struct VL6180_ATY_Dev *dev)
  308. {
  309. if (!dev) {
  310. return 0;
  311. }
  312. uint8_t status;
  313. VL6180_ReadRegister8(dev, VL6180_REG_RESULT_INTERRUPT_STATUS_GPIO, &status);
  314. return (status & 0x04) ? 1 : 0;
  315. }
  316. /**
  317. * @brief Clear range interrupt
  318. * @param dev Pointer to VL6180 device structure
  319. * @return VL6180_STATUS_OK if successful
  320. */
  321. uint8_t VL6180_ClearRangeInterrupt(struct VL6180_ATY_Dev *dev)
  322. {
  323. if (!dev) {
  324. return VL6180_STATUS_ERROR;
  325. }
  326. return VL6180_WriteRegister8(dev, VL6180_REG_SYSTEM_INTERRUPT_CLEAR, 0x01);
  327. }
  328. /******************************* ALS Measurement Functions *******************/
  329. /**
  330. * @brief Start ALS measurement
  331. * @param dev Pointer to VL6180 device structure
  332. * @param mode Measurement mode (single shot or continuous)
  333. * @return VL6180_STATUS_OK if successful
  334. */
  335. uint8_t VL6180_StartALSMeasurement(struct VL6180_ATY_Dev *dev, uint8_t mode)
  336. {
  337. if (!dev) {
  338. return VL6180_STATUS_ERROR;
  339. }
  340. // Auto-initialize if not initialized
  341. uint8_t status = VL6180_CheckAndAutoInit(dev);
  342. if (status != VL6180_STATUS_OK) {
  343. return status;
  344. }
  345. if (dev->lock) {
  346. if (dev->debugEnable && dev->LOG) {
  347. dev->LOG("VL6180: Device is locked\n");
  348. }
  349. return VL6180_STATUS_ERROR;
  350. }
  351. dev->lock = 1;
  352. if (dev->debugEnable && dev->LOG) {
  353. dev->LOG("VL6180: Starting ALS measurement (mode: %d)\n", mode);
  354. }
  355. // Clear any existing interrupts
  356. VL6180_ClearALSInterrupt(dev);
  357. // Start measurement
  358. status = VL6180_WriteRegister8(dev, VL6180_REG_SYSALS_START, mode);
  359. dev->lock = 0;
  360. dev->lastStatus = status;
  361. return status;
  362. }
  363. /**
  364. * @brief Read ALS measurement result
  365. * @param dev Pointer to VL6180 device structure
  366. * @return VL6180_STATUS_OK if successful
  367. */
  368. uint8_t VL6180_ReadALSResult(struct VL6180_ATY_Dev *dev)
  369. {
  370. if (!dev) {
  371. return VL6180_STATUS_ERROR;
  372. }
  373. // Auto-initialize if not initialized
  374. uint8_t status = VL6180_CheckAndAutoInit(dev);
  375. if (status != VL6180_STATUS_OK) {
  376. return status;
  377. }
  378. if (dev->lock) {
  379. return VL6180_STATUS_ERROR;
  380. }
  381. dev->lock = 1;
  382. // Read ALS value
  383. VL6180_ReadRegister16(dev, VL6180_REG_RESULT_ALS_VAL, &dev->alsValue);
  384. // Read ALS status
  385. VL6180_ReadRegister8(dev, VL6180_REG_RESULT_ALS_STATUS, &dev->alsStatus);
  386. if (dev->debugEnable && dev->LOG) {
  387. dev->LOG("VL6180: ALS: %d counts, Status: 0x%02X\n",
  388. dev->alsValue, dev->alsStatus);
  389. }
  390. dev->lock = 0;
  391. dev->lastStatus = VL6180_STATUS_OK;
  392. return VL6180_STATUS_OK;
  393. }
  394. /**
  395. * @brief Get ALS measurement value
  396. * @param dev Pointer to VL6180 device structure
  397. * @return ALS value in counts
  398. */
  399. uint16_t VL6180_GetALSValue(struct VL6180_ATY_Dev *dev)
  400. {
  401. if (!dev) {
  402. return 0;
  403. }
  404. return dev->alsValue;
  405. }
  406. /**
  407. * @brief Check if ALS measurement is ready
  408. * @param dev Pointer to VL6180 device structure
  409. * @return 1 if ready, 0 if not ready
  410. */
  411. uint8_t VL6180_IsALSReady(struct VL6180_ATY_Dev *dev)
  412. {
  413. if (!dev) {
  414. return 0;
  415. }
  416. uint8_t status;
  417. VL6180_ReadRegister8(dev, VL6180_REG_RESULT_INTERRUPT_STATUS_GPIO, &status);
  418. return (status & 0x20) ? 1 : 0;
  419. }
  420. /**
  421. * @brief Clear ALS interrupt
  422. * @param dev Pointer to VL6180 device structure
  423. * @return VL6180_STATUS_OK if successful
  424. */
  425. uint8_t VL6180_ClearALSInterrupt(struct VL6180_ATY_Dev *dev)
  426. {
  427. if (!dev) {
  428. return VL6180_STATUS_ERROR;
  429. }
  430. return VL6180_WriteRegister8(dev, VL6180_REG_SYSTEM_INTERRUPT_CLEAR, 0x02);
  431. }
  432. /******************************* Configuration Functions *********************/
  433. /**
  434. * @brief Set range measurement thresholds
  435. * @param dev Pointer to VL6180 device structure
  436. * @param low Low threshold in mm
  437. * @param high High threshold in mm
  438. * @return VL6180_STATUS_OK if successful
  439. */
  440. uint8_t VL6180_SetRangeThresholds(struct VL6180_ATY_Dev *dev, uint8_t low, uint8_t high)
  441. {
  442. if (!dev) {
  443. return VL6180_STATUS_ERROR;
  444. }
  445. dev->rangeThresholdLow = low;
  446. dev->rangeThresholdHigh = high;
  447. VL6180_WriteRegister8(dev, VL6180_REG_SYSRANGE_THRESH_LOW, low);
  448. VL6180_WriteRegister8(dev, VL6180_REG_SYSRANGE_THRESH_HIGH, high);
  449. return VL6180_STATUS_OK;
  450. }
  451. /**
  452. * @brief Set ALS measurement thresholds
  453. * @param dev Pointer to VL6180 device structure
  454. * @param low Low threshold in counts
  455. * @param high High threshold in counts
  456. * @return VL6180_STATUS_OK if successful
  457. */
  458. uint8_t VL6180_SetALSThresholds(struct VL6180_ATY_Dev *dev, uint16_t low, uint16_t high)
  459. {
  460. if (!dev) {
  461. return VL6180_STATUS_ERROR;
  462. }
  463. dev->alsThresholdLow = low;
  464. dev->alsThresholdHigh = high;
  465. VL6180_WriteRegister16(dev, VL6180_REG_SYSALS_THRESH_LOW, low);
  466. VL6180_WriteRegister16(dev, VL6180_REG_SYSALS_THRESH_HIGH, high);
  467. return VL6180_STATUS_OK;
  468. }
  469. /**
  470. * @brief Set ALS gain
  471. * @param dev Pointer to VL6180 device structure
  472. * @param gain ALS gain setting
  473. * @return VL6180_STATUS_OK if successful
  474. */
  475. uint8_t VL6180_SetALSGain(struct VL6180_ATY_Dev *dev, uint8_t gain)
  476. {
  477. if (!dev) {
  478. return VL6180_STATUS_ERROR;
  479. }
  480. if (gain > VL6180_ALS_GAIN_40) {
  481. return VL6180_STATUS_ERROR;
  482. }
  483. dev->alsGain = gain;
  484. return VL6180_WriteRegister8(dev, VL6180_REG_SYSALS_ANALOGUE_GAIN, (0x40 | gain));
  485. }
  486. /**
  487. * @brief Set ALS integration period
  488. * @param dev Pointer to VL6180 device structure
  489. * @param period Integration period in ms (1-512ms)
  490. * @return VL6180_STATUS_OK if successful
  491. */
  492. uint8_t VL6180_SetALSIntegrationPeriod(struct VL6180_ATY_Dev *dev, uint16_t period)
  493. {
  494. if (!dev) {
  495. return VL6180_STATUS_ERROR;
  496. }
  497. if (period < 1 || period > 512) {
  498. return VL6180_STATUS_ERROR;
  499. }
  500. dev->alsIntegrationPeriod = period;
  501. return VL6180_WriteRegister16(dev, VL6180_REG_SYSALS_INTEGRATION_PERIOD, period - 1);
  502. }
  503. /**
  504. * @brief Set range offset calibration
  505. * @param dev Pointer to VL6180 device structure
  506. * @param offset Offset value in mm (-128 to +127)
  507. * @return VL6180_STATUS_OK if successful
  508. */
  509. uint8_t VL6180_SetRangeOffset(struct VL6180_ATY_Dev *dev, int8_t offset)
  510. {
  511. if (!dev) {
  512. return VL6180_STATUS_ERROR;
  513. }
  514. dev->rangeOffset = offset;
  515. return VL6180_WriteRegister8(dev, VL6180_REG_SYSRANGE_PART_TO_PART_RANGE_OFFSET, (uint8_t)offset);
  516. }
  517. /**
  518. * @brief Set crosstalk compensation
  519. * @param dev Pointer to VL6180 device structure
  520. * @param rate Crosstalk compensation rate
  521. * @return VL6180_STATUS_OK if successful
  522. */
  523. uint8_t VL6180_SetCrosstalkCompensation(struct VL6180_ATY_Dev *dev, uint16_t rate)
  524. {
  525. if (!dev) {
  526. return VL6180_STATUS_ERROR;
  527. }
  528. dev->crosstalkCompensationRate = rate;
  529. return VL6180_WriteRegister16(dev, VL6180_REG_SYSRANGE_CROSSTALK_COMPENSATION_RATE, rate);
  530. }
  531. /******************************* I2C Register Access Functions ***************/
  532. /**
  533. * @brief Write 8-bit register
  534. * @param dev Pointer to VL6180 device structure
  535. * @param reg Register address
  536. * @param data Data to write
  537. * @return VL6180_STATUS_OK if successful
  538. */
  539. uint8_t VL6180_WriteRegister8(struct VL6180_ATY_Dev *dev, uint16_t reg, uint8_t data)
  540. {
  541. if (!dev || !dev->i2cStart || !dev->i2cStop || !dev->i2cWriteByte) {
  542. return VL6180_STATUS_ERROR;
  543. }
  544. // Start I2C transaction
  545. if (dev->i2cStart() != 0) {
  546. return VL6180_STATUS_ERROR;
  547. }
  548. // Send device address with write bit
  549. if (dev->i2cWriteByte((dev->i2cAddress << 1) | 0x00) != 0) {
  550. dev->i2cStop();
  551. return VL6180_STATUS_ERROR;
  552. }
  553. // Send register address (16-bit, MSB first)
  554. if (dev->i2cWriteByte((reg >> 8) & 0xFF) != 0) {
  555. dev->i2cStop();
  556. return VL6180_STATUS_ERROR;
  557. }
  558. if (dev->i2cWriteByte(reg & 0xFF) != 0) {
  559. dev->i2cStop();
  560. return VL6180_STATUS_ERROR;
  561. }
  562. // Send data
  563. if (dev->i2cWriteByte(data) != 0) {
  564. dev->i2cStop();
  565. return VL6180_STATUS_ERROR;
  566. }
  567. // Stop I2C transaction
  568. dev->i2cStop();
  569. return VL6180_STATUS_OK;
  570. }
  571. /**
  572. * @brief Write 16-bit register
  573. * @param dev Pointer to VL6180 device structure
  574. * @param reg Register address
  575. * @param data Data to write
  576. * @return VL6180_STATUS_OK if successful
  577. */
  578. uint8_t VL6180_WriteRegister16(struct VL6180_ATY_Dev *dev, uint16_t reg, uint16_t data)
  579. {
  580. if (!dev || !dev->i2cStart || !dev->i2cStop || !dev->i2cWriteByte) {
  581. return VL6180_STATUS_ERROR;
  582. }
  583. // Start I2C transaction
  584. if (dev->i2cStart() != 0) {
  585. return VL6180_STATUS_ERROR;
  586. }
  587. // Send device address with write bit
  588. if (dev->i2cWriteByte((dev->i2cAddress << 1) | 0x00) != 0) {
  589. dev->i2cStop();
  590. return VL6180_STATUS_ERROR;
  591. }
  592. // Send register address (16-bit, MSB first)
  593. if (dev->i2cWriteByte((reg >> 8) & 0xFF) != 0) {
  594. dev->i2cStop();
  595. return VL6180_STATUS_ERROR;
  596. }
  597. if (dev->i2cWriteByte(reg & 0xFF) != 0) {
  598. dev->i2cStop();
  599. return VL6180_STATUS_ERROR;
  600. }
  601. // Send data (16-bit, MSB first)
  602. if (dev->i2cWriteByte((data >> 8) & 0xFF) != 0) {
  603. dev->i2cStop();
  604. return VL6180_STATUS_ERROR;
  605. }
  606. if (dev->i2cWriteByte(data & 0xFF) != 0) {
  607. dev->i2cStop();
  608. return VL6180_STATUS_ERROR;
  609. }
  610. // Stop I2C transaction
  611. dev->i2cStop();
  612. return VL6180_STATUS_OK;
  613. }
  614. /**
  615. * @brief Write 32-bit register
  616. * @param dev Pointer to VL6180 device structure
  617. * @param reg Register address
  618. * @param data Data to write
  619. * @return VL6180_STATUS_OK if successful
  620. */
  621. uint8_t VL6180_WriteRegister32(struct VL6180_ATY_Dev *dev, uint16_t reg, uint32_t data)
  622. {
  623. if (!dev || !dev->i2cStart || !dev->i2cStop || !dev->i2cWriteByte) {
  624. return VL6180_STATUS_ERROR;
  625. }
  626. // Start I2C transaction
  627. if (dev->i2cStart() != 0) {
  628. return VL6180_STATUS_ERROR;
  629. }
  630. // Send device address with write bit
  631. if (dev->i2cWriteByte((dev->i2cAddress << 1) | 0x00) != 0) {
  632. dev->i2cStop();
  633. return VL6180_STATUS_ERROR;
  634. }
  635. // Send register address (16-bit, MSB first)
  636. if (dev->i2cWriteByte((reg >> 8) & 0xFF) != 0) {
  637. dev->i2cStop();
  638. return VL6180_STATUS_ERROR;
  639. }
  640. if (dev->i2cWriteByte(reg & 0xFF) != 0) {
  641. dev->i2cStop();
  642. return VL6180_STATUS_ERROR;
  643. }
  644. // Send data (32-bit, MSB first)
  645. if (dev->i2cWriteByte((data >> 24) & 0xFF) != 0) {
  646. dev->i2cStop();
  647. return VL6180_STATUS_ERROR;
  648. }
  649. if (dev->i2cWriteByte((data >> 16) & 0xFF) != 0) {
  650. dev->i2cStop();
  651. return VL6180_STATUS_ERROR;
  652. }
  653. if (dev->i2cWriteByte((data >> 8) & 0xFF) != 0) {
  654. dev->i2cStop();
  655. return VL6180_STATUS_ERROR;
  656. }
  657. if (dev->i2cWriteByte(data & 0xFF) != 0) {
  658. dev->i2cStop();
  659. return VL6180_STATUS_ERROR;
  660. }
  661. // Stop I2C transaction
  662. dev->i2cStop();
  663. return VL6180_STATUS_OK;
  664. }
  665. /**
  666. * @brief Read 8-bit register
  667. * @param dev Pointer to VL6180 device structure
  668. * @param reg Register address
  669. * @param data Pointer to store read data
  670. * @return VL6180_STATUS_OK if successful
  671. */
  672. uint8_t VL6180_ReadRegister8(struct VL6180_ATY_Dev *dev, uint16_t reg, uint8_t *data)
  673. {
  674. if (!dev || !data || !dev->i2cStart || !dev->i2cStop || !dev->i2cWriteByte || !dev->i2cReadByte) {
  675. return VL6180_STATUS_ERROR;
  676. }
  677. // Start I2C transaction for write
  678. if (dev->i2cStart() != 0) {
  679. return VL6180_STATUS_ERROR;
  680. }
  681. // Send device address with write bit
  682. if (dev->i2cWriteByte((dev->i2cAddress << 1) | 0x00) != 0) {
  683. dev->i2cStop();
  684. return VL6180_STATUS_ERROR;
  685. }
  686. // Send register address (16-bit, MSB first)
  687. if (dev->i2cWriteByte((reg >> 8) & 0xFF) != 0) {
  688. dev->i2cStop();
  689. return VL6180_STATUS_ERROR;
  690. }
  691. if (dev->i2cWriteByte(reg & 0xFF) != 0) {
  692. dev->i2cStop();
  693. return VL6180_STATUS_ERROR;
  694. }
  695. // Restart for read
  696. if (dev->i2cStart() != 0) {
  697. dev->i2cStop();
  698. return VL6180_STATUS_ERROR;
  699. }
  700. // Send device address with read bit
  701. if (dev->i2cWriteByte((dev->i2cAddress << 1) | 0x01) != 0) {
  702. dev->i2cStop();
  703. return VL6180_STATUS_ERROR;
  704. }
  705. // Read data
  706. *data = dev->i2cReadByte(0); // NACK for last byte
  707. // Stop I2C transaction
  708. dev->i2cStop();
  709. return VL6180_STATUS_OK;
  710. }
  711. /**
  712. * @brief Read 16-bit register
  713. * @param dev Pointer to VL6180 device structure
  714. * @param reg Register address
  715. * @param data Pointer to store read data
  716. * @return VL6180_STATUS_OK if successful
  717. */
  718. uint8_t VL6180_ReadRegister16(struct VL6180_ATY_Dev *dev, uint16_t reg, uint16_t *data)
  719. {
  720. if (!dev || !data || !dev->i2cStart || !dev->i2cStop || !dev->i2cWriteByte || !dev->i2cReadByte) {
  721. return VL6180_STATUS_ERROR;
  722. }
  723. // Start I2C transaction for write
  724. if (dev->i2cStart() != 0) {
  725. return VL6180_STATUS_ERROR;
  726. }
  727. // Send device address with write bit
  728. if (dev->i2cWriteByte((dev->i2cAddress << 1) | 0x00) != 0) {
  729. dev->i2cStop();
  730. return VL6180_STATUS_ERROR;
  731. }
  732. // Send register address (16-bit, MSB first)
  733. if (dev->i2cWriteByte((reg >> 8) & 0xFF) != 0) {
  734. dev->i2cStop();
  735. return VL6180_STATUS_ERROR;
  736. }
  737. if (dev->i2cWriteByte(reg & 0xFF) != 0) {
  738. dev->i2cStop();
  739. return VL6180_STATUS_ERROR;
  740. }
  741. // Restart for read
  742. if (dev->i2cStart() != 0) {
  743. dev->i2cStop();
  744. return VL6180_STATUS_ERROR;
  745. }
  746. // Send device address with read bit
  747. if (dev->i2cWriteByte((dev->i2cAddress << 1) | 0x01) != 0) {
  748. dev->i2cStop();
  749. return VL6180_STATUS_ERROR;
  750. }
  751. // Read data (16-bit, MSB first)
  752. uint8_t msb = dev->i2cReadByte(1); // ACK for first byte
  753. uint8_t lsb = dev->i2cReadByte(0); // NACK for last byte
  754. *data = (msb << 8) | lsb;
  755. // Stop I2C transaction
  756. dev->i2cStop();
  757. return VL6180_STATUS_OK;
  758. }
  759. /**
  760. * @brief Read 32-bit register
  761. * @param dev Pointer to VL6180 device structure
  762. * @param reg Register address
  763. * @param data Pointer to store read data
  764. * @return VL6180_STATUS_OK if successful
  765. */
  766. uint8_t VL6180_ReadRegister32(struct VL6180_ATY_Dev *dev, uint16_t reg, uint32_t *data)
  767. {
  768. if (!dev || !data || !dev->i2cStart || !dev->i2cStop || !dev->i2cWriteByte || !dev->i2cReadByte) {
  769. return VL6180_STATUS_ERROR;
  770. }
  771. // Start I2C transaction for write
  772. if (dev->i2cStart() != 0) {
  773. return VL6180_STATUS_ERROR;
  774. }
  775. // Send device address with write bit
  776. if (dev->i2cWriteByte((dev->i2cAddress << 1) | 0x00) != 0) {
  777. dev->i2cStop();
  778. return VL6180_STATUS_ERROR;
  779. }
  780. // Send register address (16-bit, MSB first)
  781. if (dev->i2cWriteByte((reg >> 8) & 0xFF) != 0) {
  782. dev->i2cStop();
  783. return VL6180_STATUS_ERROR;
  784. }
  785. if (dev->i2cWriteByte(reg & 0xFF) != 0) {
  786. dev->i2cStop();
  787. return VL6180_STATUS_ERROR;
  788. }
  789. // Restart for read
  790. if (dev->i2cStart() != 0) {
  791. dev->i2cStop();
  792. return VL6180_STATUS_ERROR;
  793. }
  794. // Send device address with read bit
  795. if (dev->i2cWriteByte((dev->i2cAddress << 1) | 0x01) != 0) {
  796. dev->i2cStop();
  797. return VL6180_STATUS_ERROR;
  798. }
  799. // Read data (32-bit, MSB first)
  800. uint8_t byte3 = dev->i2cReadByte(1); // ACK
  801. uint8_t byte2 = dev->i2cReadByte(1); // ACK
  802. uint8_t byte1 = dev->i2cReadByte(1); // ACK
  803. uint8_t byte0 = dev->i2cReadByte(0); // NACK for last byte
  804. *data = (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0;
  805. // Stop I2C transaction
  806. dev->i2cStop();
  807. return VL6180_STATUS_OK;
  808. }
  809. /******************************* Utility Functions ***************************/
  810. /**
  811. * @brief Get device status
  812. * @param dev Pointer to VL6180 device structure
  813. * @return Device status
  814. */
  815. uint8_t VL6180_GetDeviceStatus(struct VL6180_ATY_Dev *dev)
  816. {
  817. if (!dev) {
  818. return VL6180_STATUS_ERROR;
  819. }
  820. return dev->lastStatus;
  821. }
  822. /**
  823. * @brief Set I2C address
  824. * @param dev Pointer to VL6180 device structure
  825. * @param address New I2C address
  826. */
  827. void VL6180_SetI2CAddress(struct VL6180_ATY_Dev *dev, uint8_t address)
  828. {
  829. if (dev) {
  830. dev->i2cAddress = address;
  831. }
  832. }
  833. /**
  834. * @brief Convert ALS counts to lux
  835. * @param dev Pointer to VL6180 device structure
  836. * @param alsValue ALS value in counts
  837. * @return Lux value
  838. */
  839. float VL6180_ConvertALSToLux(struct VL6180_ATY_Dev *dev, uint16_t alsValue)
  840. {
  841. if (!dev) {
  842. return 0.0f;
  843. }
  844. // Gain factors for different ALS gain settings
  845. float gainFactors[] = {20.0f, 10.32f, 5.21f, 2.60f, 1.72f, 1.28f, 1.01f, 40.0f};
  846. if (dev->alsGain > VL6180_ALS_GAIN_40) {
  847. return 0.0f;
  848. }
  849. float gain = gainFactors[dev->alsGain];
  850. float integrationTime = dev->alsIntegrationPeriod / 100.0f; // Convert to seconds
  851. // Calculate lux using the formula from datasheet
  852. float lux = (float)alsValue * 0.32f / (gain * integrationTime);
  853. return lux;
  854. }
  855. /**
  856. * @brief Get error string description
  857. * @param errorCode Error code
  858. * @return Error string
  859. */
  860. const char* VL6180_GetErrorString(uint8_t errorCode)
  861. {
  862. switch (errorCode) {
  863. case VL6180_ERROR_NONE:
  864. return "No error";
  865. case VL6180_ERROR_SYSERR_1:
  866. return "System error 1";
  867. case VL6180_ERROR_SYSERR_5:
  868. return "System error 5";
  869. case VL6180_ERROR_ECEFAIL:
  870. return "ECE failure";
  871. case VL6180_ERROR_NOCONVERGE:
  872. return "No convergence";
  873. case VL6180_ERROR_RANGEIGNORE:
  874. return "Range ignore";
  875. case VL6180_ERROR_SNR:
  876. return "SNR error";
  877. case VL6180_ERROR_RAWUFLOW:
  878. return "Raw underflow";
  879. case VL6180_ERROR_RAWOFLOW:
  880. return "Raw overflow";
  881. case VL6180_ERROR_RANGEUFLOW:
  882. return "Range underflow";
  883. case VL6180_ERROR_RANGEOFLOW:
  884. return "Range overflow";
  885. default:
  886. return "Unknown error";
  887. }
  888. }
  889. /******************************* Usage Examples ******************************/
  890. /*
  891. // Example 1: Basic VL6180 usage for range measurement
  892. #include "VL6180_ATY.h"
  893. // I2C function implementations (platform specific)
  894. uint8_t i2c_start(void) { // Your I2C start implementation }
  895. uint8_t i2c_stop(void) { // Your I2C stop implementation }
  896. uint8_t i2c_write_byte(uint8_t data) { // Your I2C write implementation }
  897. uint8_t i2c_read_byte(uint8_t ack) { // Your I2C read implementation }
  898. void delay_ms(uint32_t ms) { // Your delay implementation }
  899. void debug_log(const char* format, ...) { // Your log implementation }
  900. int main(void)
  901. {
  902. // Initialize VL6180 device structure
  903. struct VL6180_ATY_Dev vl6180_dev = {
  904. .i2cStart = i2c_start,
  905. .i2cStop = i2c_stop,
  906. .i2cWriteByte = i2c_write_byte,
  907. .i2cReadByte = i2c_read_byte,
  908. .delayMs = delay_ms,
  909. .i2cAddress = VL6180_I2C_ADDR_DEFAULT,
  910. .debugEnable = 1,
  911. .LOG = debug_log,
  912. .initialized = 0 // Auto-initialization will be triggered
  913. };
  914. // VL6180_Init will be called automatically in VL6180_StartRangeMeasurement
  915. while (1) {
  916. // Start single-shot range measurement
  917. if (VL6180_StartRangeMeasurement(&vl6180_dev, VL6180_MODE_RANGE_SINGLE_SHOT) == VL6180_STATUS_OK) {
  918. // Wait for measurement to complete
  919. while (!VL6180_IsRangeReady(&vl6180_dev)) {
  920. delay_ms(1);
  921. }
  922. // Read range result
  923. if (VL6180_ReadRangeResult(&vl6180_dev) == VL6180_STATUS_OK) {
  924. uint8_t range = VL6180_GetRangeValue(&vl6180_dev);
  925. debug_log("Range: %d mm\n", range);
  926. }
  927. // Clear interrupt
  928. VL6180_ClearRangeInterrupt(&vl6180_dev);
  929. }
  930. delay_ms(100);
  931. }
  932. }
  933. // Example 2: VL6180 ALS (Ambient Light Sensor) usage
  934. int als_example(void)
  935. {
  936. struct VL6180_ATY_Dev vl6180_dev = {
  937. .i2cStart = i2c_start,
  938. .i2cStop = i2c_stop,
  939. .i2cWriteByte = i2c_write_byte,
  940. .i2cReadByte = i2c_read_byte,
  941. .delayMs = delay_ms,
  942. .i2cAddress = VL6180_I2C_ADDR_DEFAULT,
  943. .debugEnable = 1,
  944. .LOG = debug_log,
  945. .initialized = 0 // Auto-initialization will be triggered
  946. };
  947. // Configure ALS settings
  948. VL6180_SetALSGain(&vl6180_dev, VL6180_ALS_GAIN_1);
  949. VL6180_SetALSIntegrationPeriod(&vl6180_dev, 100);
  950. while (1) {
  951. // Start single-shot ALS measurement
  952. if (VL6180_StartALSMeasurement(&vl6180_dev, VL6180_MODE_ALS_SINGLE_SHOT) == VL6180_STATUS_OK) {
  953. // Wait for measurement to complete
  954. while (!VL6180_IsALSReady(&vl6180_dev)) {
  955. delay_ms(1);
  956. }
  957. // Read ALS result
  958. if (VL6180_ReadALSResult(&vl6180_dev) == VL6180_STATUS_OK) {
  959. uint16_t als_counts = VL6180_GetALSValue(&vl6180_dev);
  960. float lux = VL6180_ConvertALSToLux(&vl6180_dev, als_counts);
  961. debug_log("ALS: %d counts, %.2f lux\n", als_counts, lux);
  962. }
  963. // Clear interrupt
  964. VL6180_ClearALSInterrupt(&vl6180_dev);
  965. }
  966. delay_ms(500);
  967. }
  968. }
  969. */
  970. /******************************** End Of File *********************************/