AS7331.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. /**
  2. * @file AS7331.hpp
  3. * @brief UV Spectral Sensor - AS7331 Driver
  4. *
  5. * This driver provides a communication interface for the AS7331 UV spectral sensor.
  6. * It includes configurations for I2C addressing, device modes, gain, clock frequency,
  7. * and measurement settings.
  8. *
  9. * Inspired by: https://github.com/sparkfun/SparkFun_AS7331_Arduino_Library/blob/main/src/sfeAS7331.h
  10. * Datasheet: https://look.ams-osram.com/m/1856fd2c69c35605/original/AS7331-Spectral-UVA-B-C-Sensor.pdf
  11. */
  12. #pragma once
  13. #include <stddef.h>
  14. #include <stdint.h>
  15. #include <furi_hal_i2c_types.h>
  16. /**
  17. * @defgroup AS7331_I2C_Addressing I2C Addressing
  18. * @brief I2C address definitions for AS7331
  19. *
  20. * The 7-bit I2C address is defined as [1, 1, 1, 0, 1, A1, A0], where A1 and A0 are configurable address pins.
  21. * @{
  22. */
  23. /** Default I2C address when A1 = 0, A0 = 0 */
  24. const uint8_t DefaultI2CAddr = 0x74;
  25. /** Secondary I2C address when A1 = 0, A0 = 1 */
  26. const uint8_t SecondaryI2CAddr = 0x75;
  27. /** Tertiary I2C address when A1 = 1, A0 = 0 */
  28. const uint8_t TertiaryI2CAddr = 0x76;
  29. /** Quaternary I2C address when A1 = 1, A0 = 1 */
  30. const uint8_t QuaternaryI2CAddr = 0x77;
  31. /** Expected API Generation Register content (Device ID + Mutation number) */
  32. const uint8_t ExpectedAGENContent = 0x21;
  33. /** @} */ // End of AS7331_I2C_Addressing group
  34. /**
  35. * @defgroup AS7331_Enums Enumerations
  36. * @brief Enumerations for AS7331 settings
  37. * @{
  38. */
  39. /**
  40. * @brief Device Operating Modes
  41. */
  42. enum as7331_device_mode_t : uint8_t {
  43. DEVICE_MODE_CONFIG = 0x2, /**< Configuration mode */
  44. DEVICE_MODE_MEASURE = 0x3 /**< Measurement mode */
  45. };
  46. /**
  47. * @brief Sensor Gain Settings (CREG1:GAIN)
  48. *
  49. * Default: GAIN_2 (1010)
  50. *
  51. * Gain value is calculated as:
  52. * **gain = 2<sup>(11 - gain_code)</sup>**
  53. */
  54. enum as7331_gain_t : uint8_t {
  55. GAIN_2048 = 0x0000,
  56. GAIN_1024,
  57. GAIN_512,
  58. GAIN_256,
  59. GAIN_128,
  60. GAIN_64,
  61. GAIN_32,
  62. GAIN_16,
  63. GAIN_8,
  64. GAIN_4,
  65. GAIN_2,
  66. GAIN_1
  67. };
  68. /**
  69. * @brief Integration Time Settings (CREG1:TIME)
  70. *
  71. * Default: TIME_64MS (0110)
  72. *
  73. * The conversion time in the enumerators (in milliseconds) is valid for a clock frequency of 1.024 MHz.
  74. * For higher clock frequencies, the conversion time is divided by 2 each time the clock frequency is doubled.
  75. *
  76. * **Conversion Time [ms] = 2<sup>integration_time_code</sup>**
  77. */
  78. enum as7331_integration_time_t : uint8_t {
  79. TIME_1MS = 0x0,
  80. TIME_2MS,
  81. TIME_4MS,
  82. TIME_8MS,
  83. TIME_16MS,
  84. TIME_32MS,
  85. TIME_64MS,
  86. TIME_128MS,
  87. TIME_256MS,
  88. TIME_512MS,
  89. TIME_1024MS,
  90. TIME_2048MS,
  91. TIME_4096MS,
  92. TIME_8192MS,
  93. TIME_16384MS
  94. };
  95. /**
  96. * @brief Divider Settings (CREG2:DIV)
  97. *
  98. * Default: DIV_2 (000)
  99. *
  100. * Divider value is calculated as:
  101. * **divider = 2<sup>(1 + divider_code)</sup>**
  102. */
  103. enum as7331_divider_t : uint8_t {
  104. DIV_2 = 0x0,
  105. DIV_4,
  106. DIV_8,
  107. DIV_16,
  108. DIV_32,
  109. DIV_64,
  110. DIV_128,
  111. DIV_256
  112. };
  113. /**
  114. * @brief Internal Clock Frequency Settings fCLK (CREG3:CCLK)
  115. *
  116. * Default: CCLK_1_024_MHZ
  117. *
  118. * Clock frequency is calculated as:
  119. * **clock_frequency = 1.024 × 2<sup>clock_frequency_code</sup>** (in MHz)
  120. */
  121. enum as7331_clock_frequency_t : uint8_t {
  122. CCLK_1_024_MHZ = 0x00, /**< 1.024 MHz: 1 - 16384 ms (Conversion Time) */
  123. CCLK_2_048_MHZ,
  124. CCLK_4_096_MHZ,
  125. CCLK_8_192_MHZ /**< 8.192 MHz: 0.125 - 2048 ms (Conversion Time) */
  126. };
  127. /**
  128. * @brief Measurement Modes (CREG3:MMODE)
  129. *
  130. * Default: MEASUREMENT_MODE_COMMAND (01)
  131. */
  132. enum as7331_measurement_mode_t : uint8_t {
  133. MEASUREMENT_MODE_CONTINUOUS = 0x0, /**< Continuous Measurement Mode (CONT) */
  134. MEASUREMENT_MODE_COMMAND, /**< Command Measurement Mode (CMD) */
  135. MEASUREMENT_MODE_SYNC_START, /**< Synchronous Measurement Mode (SYNS) - externally synchronized start of measurement */
  136. MEASUREMENT_MODE_SYNC_START_END /**< Synchronous Measurement Start and End Mode (SYND) - start and end of measurement are externally synchronized */
  137. };
  138. /** @brief UV Type Selection */
  139. enum as7331_uv_type_t : uint8_t { UV_A, UV_B, UV_C };
  140. /** @} */ // End of AS7331_Enums group
  141. /**
  142. * @defgroup AS7331_Config_Registers Configuration Register Definitions
  143. * @brief Definitions for configuration registers
  144. *
  145. * Registers are 8 bits long and can only be accessed in the configuration mode.
  146. * @{
  147. */
  148. /** @brief OSR configuration register address */
  149. const uint8_t RegCfgOsr = 0x00;
  150. /**
  151. * @brief Operational State Register (OSR) Register Layout
  152. */
  153. typedef union {
  154. struct {
  155. as7331_device_mode_t
  156. operating_state : 3; /**< DOS (010) - Device Operating State (OSR[2:0]) */
  157. uint8_t software_reset : 1; /**< SW_RES (0) - Software Reset (OSR[3]) */
  158. uint8_t reserved : 2; /**< Reserved, do not write (OSR[5:4]) */
  159. uint8_t power_down : 1; /**< PD (1) - Power Down (OSR[6]) */
  160. uint8_t start_state : 1; /**< SS (0) - Start State (OSR[7]) */
  161. };
  162. uint8_t byte;
  163. } as7331_osr_reg_t;
  164. /** @brief AGEN register address */
  165. const uint8_t RegCfgAgen = 0x02;
  166. /**
  167. * @brief AGEN Register Layout
  168. */
  169. typedef union {
  170. struct {
  171. uint8_t
  172. mutation : 4; /**< MUT (0001) - Mutation number of control register bank. Incremented when control registers change (AGEN[3:0]) */
  173. uint8_t device_id : 4; /**< DEVID (0010) - Device ID number (AGEN[7:4]) */
  174. };
  175. uint8_t byte;
  176. } as7331_agen_reg_t;
  177. /** @brief CREG1 -- Configuration Register 1 address */
  178. const uint8_t RegCfgCreg1 = 0x06;
  179. /**
  180. * @brief CREG1 Register Layout
  181. */
  182. typedef union {
  183. struct {
  184. as7331_integration_time_t
  185. integration_time : 4; /**< TIME (0110) - Integration time (CREG1[3:0]) */
  186. as7331_gain_t gain : 4; /**< GAIN (1010) - Sensor gain (CREG1[7:4]) */
  187. };
  188. uint8_t byte;
  189. } as7331_creg1_reg_t;
  190. /** @brief CREG2 -- Configuration Register 2 address */
  191. const uint8_t RegCfgCreg2 = 0x07;
  192. /**
  193. * @brief CREG2 Register Layout
  194. */
  195. typedef union {
  196. struct {
  197. as7331_divider_t divider : 3; /**< DIV (000) - Divider value (CREG2[2:0]) */
  198. uint8_t enable_divider : 1; /**< EN_DIV (0) - Divider enable (CREG2[3]) */
  199. uint8_t reserved : 2; /**< Reserved, do not write (CREG2[5:4]) */
  200. uint8_t
  201. enable_temp : 1; /**< EN_TM (1) - Temperature measurement enable in SYND mode (CREG2[6]) */
  202. uint8_t reserved1 : 1; /**< Reserved, do not write (CREG2[7]) */
  203. };
  204. uint8_t byte;
  205. } as7331_creg2_reg_t;
  206. /** @brief CREG3 -- Configuration Register 3 address */
  207. const uint8_t RegCfgCreg3 = 0x08;
  208. /**
  209. * @brief CREG3 Register Layout
  210. */
  211. typedef union {
  212. struct {
  213. as7331_clock_frequency_t
  214. clock_frequency : 2; /**< CCLK (00) - Internal clock frequency (CREG3[1:0]) */
  215. uint8_t reserved : 1; /**< Reserved, do not write (CREG3[2]) */
  216. uint8_t ready_mode : 1; /**< RDYOD (0) - Ready pin mode (CREG3[3]) */
  217. uint8_t standby : 1; /**< SB (0) - Standby mode (CREG3[4]) */
  218. uint8_t reserved1 : 1; /**< Reserved, do not write (CREG3[5]) */
  219. as7331_measurement_mode_t
  220. measurement_mode : 2; /**< MMODE (01) - Measurement mode selection (CREG3[7:6]) */
  221. };
  222. uint8_t byte;
  223. } as7331_creg3_reg_t;
  224. /** @brief BREAK register address */
  225. const uint8_t RegCfgBreak =
  226. 0x09; /**< BREAK (0x19) - Break time TBREAK between two measurements (except CMD mode) */
  227. /** @brief EDGES register address */
  228. const uint8_t RegCfgEdges = 0x0A; /**< EDGES (0x1) - Number of SYN falling edges */
  229. /** @brief OPTREG - Option Register address */
  230. const uint8_t RegCfgOptReg = 0x0B;
  231. /**
  232. * @brief OPTREG Register Layout
  233. */
  234. typedef union {
  235. struct {
  236. uint8_t init_idx : 1; /**< INIT_IDX (1) - I2C repeat start mode flag (OPTREG[0]) */
  237. uint8_t reserved : 7; /**< Reserved, do not write (OPTREG[7:1]) */
  238. };
  239. uint8_t byte;
  240. } as7331_optreg_reg_t;
  241. /** @} */ // End of AS7331_Config_Registers group
  242. /**
  243. * @defgroup AS7331_Measurement_Registers Measurement Register Definitions
  244. * @brief Definitions for measurement registers
  245. *
  246. * Registers are 16 bits long and read-only, except for the lower byte of the OSR/STATUS register.
  247. * @{
  248. */
  249. /** @brief OSR/Status register address */
  250. const uint8_t RegMeasOsrStatus = 0x00;
  251. /**
  252. * @brief OSR/STATUS Register Layout
  253. */
  254. typedef union {
  255. struct {
  256. as7331_osr_reg_t osr; /**< OSR settings (lower byte) (OSRSTAT[7:0]) */
  257. uint8_t power_state : 1; /**< POWERSTATE - Power Down state (OSRSTAT[8]) */
  258. uint8_t standby_state : 1; /**< STANDBYSTATE - Standby mode state (OSRSTAT[9]) */
  259. uint8_t not_ready : 1; /**< NOTREADY - Inverted ready pin state (OSRSTAT[10]) */
  260. uint8_t new_data : 1; /**< NDATA - New data available (OSRSTAT[11]) */
  261. uint8_t lost_data : 1; /**< LDATA - Data overwritten before retrieval (OSRSTAT[12]) */
  262. uint8_t adc_overflow : 1; /**< ADCOF - Overflow of ADC channel (OSRSTAT[13]) */
  263. uint8_t result_overflow : 1; /**< MRESOF - Overflow of MRES1...MRES3 (OSRSTAT[14]) */
  264. uint8_t
  265. out_conv_overflow : 1; /**< OUTCONVOF - Overflow of internal 24-bit OUTCONV (OSRSTAT[15]) */
  266. };
  267. uint16_t word;
  268. } as7331_osr_status_reg_t;
  269. /** @brief TEMP register address (12-bit temperature, MS 4 bits are 0) */
  270. const uint8_t RegMeasTemp = 0x01;
  271. /** @brief MRES1 register address - Measurement Result A */
  272. const uint8_t RegMeasResultA = 0x02;
  273. /** @brief MRES2 register address - Measurement Result B */
  274. const uint8_t RegMeasResultB = 0x03;
  275. /** @brief MRES3 register address - Measurement Result C */
  276. const uint8_t RegMeasResultC = 0x04;
  277. /** @brief OUTCONVL register address - First 16 bits of 24-bit OUTCONV */
  278. const uint8_t RegMeasOutConvL = 0x05;
  279. /** @brief OUTCONVH register address - Upper 8 bits of OUTCONV, MSB is 0 */
  280. const uint8_t RegMeasOutConvH = 0x06;
  281. /** @} */ // End of AS7331_Measurement_Registers group
  282. /**
  283. * @brief AS7331 UV Spectral Sensor Driver
  284. *
  285. * This class provides an interface for the AS7331 UV spectral sensor,
  286. * allowing configuration and measurement.
  287. */
  288. class AS7331 {
  289. public:
  290. /** @brief Struct to hold raw measurement results */
  291. struct RawResults {
  292. uint16_t uv_a; /**< Raw measurement for UV-A channel */
  293. uint16_t uv_b; /**< Raw measurement for UV-B channel */
  294. uint16_t uv_c; /**< Raw measurement for UV-C channel */
  295. };
  296. /** @brief Struct to hold processed measurement results */
  297. struct Results {
  298. double uv_a; /**< Irradiance for UV-A in µW/cm² */
  299. double uv_b; /**< Irradiance for UV-B in µW/cm² */
  300. double uv_c; /**< Irradiance for UV-C in µW/cm² */
  301. };
  302. /**
  303. * @brief Constructs an AS7331 sensor object
  304. *
  305. * @param address I2C address of the sensor (default is DefaultI2CAddr)
  306. */
  307. AS7331(uint8_t address = DefaultI2CAddr);
  308. /**
  309. * @brief Initialize the sensor
  310. *
  311. * @param address I2C address in 7-bit format. If 0x0, scan the I2C bus to find the device.
  312. * @return true if initialization is successful, false otherwise
  313. */
  314. bool init(const uint8_t& address = 0);
  315. // Configuration methods
  316. /**
  317. * @brief Set sensor gain (CREG1:GAIN)
  318. *
  319. * @param gain Gain setting from as7331_gain_t
  320. * @return true if successful, false otherwise
  321. */
  322. bool setGain(const as7331_gain_t& gain);
  323. /**
  324. * @brief Set integration time (CREG1:TIME)
  325. *
  326. * @param time Integration time setting from as7331_integration_time_t
  327. * @return true if successful, false otherwise
  328. */
  329. bool setIntegrationTime(const as7331_integration_time_t& time);
  330. /**
  331. * @brief Set output divider (CREG2:DIV)
  332. *
  333. * @param divider Divider setting from as7331_divider_t
  334. * @param enable Enable or disable the divider
  335. * @return true if successful, false otherwise
  336. */
  337. bool setDivider(const as7331_divider_t& divider, const bool enable = true);
  338. /**
  339. * @brief Set clock frequency (CREG3:CCLK)
  340. *
  341. * @param freq Clock frequency setting from as7331_clock_frequency_t
  342. * @return true if successful, false otherwise
  343. */
  344. bool setClockFrequency(const as7331_clock_frequency_t& freq);
  345. /**
  346. * @brief Set measurement mode (CREG3:MMODE)
  347. *
  348. * @param mode Measurement mode setting from as7331_measurement_mode_t
  349. * @return true if successful, false otherwise
  350. */
  351. bool setMeasurementMode(const as7331_measurement_mode_t& mode);
  352. // Power management
  353. /**
  354. * @brief Enable or disable power-down state (OSR:PD)
  355. *
  356. * @param power_down true to enable power-down, false to disable
  357. * @return true if successful, false otherwise
  358. */
  359. bool setPowerDown(const bool& power_down);
  360. /**
  361. * @brief Enable or disable standby mode (CREG3:SB)
  362. *
  363. * @param standby true to enable standby, false to disable
  364. * @return true if successful, false otherwise
  365. */
  366. bool setStandby(const bool& standby);
  367. // Measurement methods
  368. /**
  369. * @brief Start the measurement (OSR:SS = 1)
  370. *
  371. * @return true if successful, false otherwise
  372. */
  373. bool startMeasurement();
  374. /**
  375. * @brief Stop the measurement (OSR:SS = 0)
  376. *
  377. * @return true if successful, false otherwise
  378. */
  379. bool stopMeasurement();
  380. /**
  381. * @brief Wait for the measurement to complete based on conversion time
  382. */
  383. void waitForMeasurement();
  384. /**
  385. * @brief Get raw measurement results
  386. *
  387. * Before reading results, wait an appropriate amount of time for the measurement to complete (TCONV).
  388. *
  389. * @param rawResults Struct to hold raw measurement results
  390. * @return true if successful, false otherwise
  391. */
  392. bool getRawResults(RawResults& rawResults);
  393. /**
  394. * @brief Get processed measurement results
  395. *
  396. * Before reading results, wait an appropriate amount of time for the measurement to complete (TCONV).
  397. *
  398. * @param results Struct to hold processed measurement results
  399. * @param rawResults Struct to hold raw measurement results
  400. * @return true if successful, false otherwise
  401. */
  402. bool getResults(Results& results, RawResults& rawResults);
  403. /**
  404. * @brief Get processed measurement results
  405. *
  406. * Before reading results, wait an appropriate amount of time for the measurement to complete (TCONV).
  407. *
  408. * @param results Struct to hold processed measurement results
  409. * @return true if successful, false otherwise
  410. */
  411. bool getResults(Results& results);
  412. /**
  413. * @brief Get temperature measurement
  414. *
  415. * Before reading results, wait an appropriate amount of time for the measurement to complete (TCONV).
  416. *
  417. * @param temperature Temperature in degrees Celsius
  418. * @return true if successful, false otherwise
  419. */
  420. bool getTemperature(double& temperature);
  421. // Utility methods
  422. /**
  423. * @brief Check if the device is ready
  424. *
  425. * @param i2c_address_7bit I2C address in 7-bit format (default uses internal address)
  426. * @return true if device is ready, false otherwise
  427. */
  428. bool deviceReady(const uint8_t& i2c_address_7bit = 0);
  429. /**
  430. * @brief Perform a software reset
  431. *
  432. * This immediately stops any running measurements and resets the device to its configuration state,
  433. * with all registers reverting to their initial values.
  434. *
  435. * @return true if the reset was successful, false otherwise
  436. */
  437. bool reset();
  438. // Getter methods
  439. /**
  440. * @brief Get device ID (including mutation number)
  441. *
  442. * @param deviceID Struct to hold device ID
  443. * @return true if successful, false otherwise
  444. */
  445. bool getDeviceID(as7331_agen_reg_t& deviceID);
  446. /**
  447. * @brief Get status register in measurement mode
  448. *
  449. * @param status Struct to hold status register data
  450. * @return true if successful, false otherwise
  451. */
  452. bool getStatus(as7331_osr_status_reg_t& status);
  453. // Local config getter methods
  454. /**
  455. * @brief Get current gain setting
  456. *
  457. * @return Current gain setting as as7331_gain_t
  458. */
  459. as7331_gain_t getGain() const;
  460. /**
  461. * @brief Get actual gain value
  462. *
  463. * @return Gain value as integer
  464. */
  465. int16_t getGainValue() const;
  466. /**
  467. * @brief Get current integration time setting
  468. *
  469. * @return Current integration time as as7331_integration_time_t
  470. */
  471. as7331_integration_time_t getIntegrationTime() const;
  472. /**
  473. * @brief Get current conversion time in seconds
  474. *
  475. * @return Conversion time in seconds
  476. */
  477. double getConversionTime() const;
  478. /**
  479. * @brief Get current divider setting
  480. *
  481. * @return Current divider setting as as7331_divider_t
  482. */
  483. as7331_divider_t getDivider() const;
  484. /**
  485. * @brief Check if divider is enabled
  486. *
  487. * @return true if divider is enabled, false otherwise
  488. */
  489. bool isDividerEnabled() const;
  490. /**
  491. * @brief Get actual divider value
  492. *
  493. * @return Divider value as integer
  494. */
  495. uint8_t getDividerValue() const;
  496. /**
  497. * @brief Get current clock frequency setting
  498. *
  499. * @return Current clock frequency as as7331_clock_frequency_t
  500. */
  501. as7331_clock_frequency_t getClockFrequency() const;
  502. /**
  503. * @brief Get actual clock frequency value
  504. *
  505. * @return Clock frequency in MHz
  506. */
  507. double getClockFrequencyValue() const;
  508. /**
  509. * @brief Get current measurement mode
  510. *
  511. * @return Current measurement mode as as7331_measurement_mode_t
  512. */
  513. as7331_measurement_mode_t getMeasurementMode() const;
  514. /**
  515. * @brief Check if power-down is enabled
  516. *
  517. * @return true if power-down is enabled, false otherwise
  518. */
  519. bool isPowerDown() const;
  520. /**
  521. * @brief Check if standby mode is enabled
  522. *
  523. * @return true if standby is enabled, false otherwise
  524. */
  525. bool isStandby() const;
  526. private:
  527. // Internal helper methods
  528. /**
  529. * @brief Set the device mode
  530. *
  531. * @param mode Device mode to set
  532. * @return true if successful, false otherwise
  533. */
  534. bool setDeviceMode(const as7331_device_mode_t& mode);
  535. /**
  536. * @brief Read OSR register and update local config
  537. *
  538. * @param osr Struct to hold OSR register data
  539. * @return true if successful, false otherwise
  540. */
  541. bool readOSRRegister(as7331_osr_reg_t& osr);
  542. /**
  543. * @brief Write OSR register and update local config
  544. *
  545. * @param osr OSR register data to write
  546. * @return true if successful, false otherwise
  547. */
  548. bool writeOSRRegister(const as7331_osr_reg_t& osr);
  549. /**
  550. * @defgroup AS7331_I2C_Methods AS7331 Custom I2C Methods
  551. * @brief Custom I2C read and write functions for the AS7331 sensor.
  552. *
  553. * These functions utilize a "repeated start" condition instead of terminating each transaction with a STOP condition, as required by the AS7331.
  554. * This is achieved using `FuriHalI2cEndAwaitRestart` and `FuriHalI2cBeginRestart`, despite their documentation referring to "Clock Stretching," which the AS7331 does not support.
  555. *
  556. * @note The caller is responsible for calling `furi_hal_i2c_acquire` and `furi_hal_i2c_release`.
  557. * @{
  558. */
  559. /**
  560. * @brief Read multiple bytes from consecutive registers
  561. *
  562. * @param handle I2C bus handle
  563. * @param start_register_addr Starting register address
  564. * @param buffer Buffer to store read data
  565. * @param length Number of bytes to read
  566. * @return true if successful, false otherwise
  567. * @ingroup AS7331_I2C_Methods
  568. */
  569. bool readRegisters(
  570. FuriHalI2cBusHandle& handle,
  571. uint8_t start_register_addr,
  572. uint8_t* buffer,
  573. size_t length);
  574. /**
  575. * @brief Read an 8-bit register
  576. *
  577. * @param handle I2C bus handle
  578. * @param register_addr Register address to read
  579. * @param data Variable to store read data
  580. * @return true if successful, false otherwise
  581. * @ingroup AS7331_I2C_Methods
  582. */
  583. bool readRegister(FuriHalI2cBusHandle& handle, uint8_t register_addr, uint8_t& data);
  584. /**
  585. * @brief Read a 16-bit register
  586. *
  587. * @param handle I2C bus handle
  588. * @param register_addr Register address to read
  589. * @param data Variable to store read data
  590. * @return true if successful, false otherwise
  591. * @ingroup AS7331_I2C_Methods
  592. */
  593. bool readRegister16(FuriHalI2cBusHandle& handle, uint8_t register_addr, uint16_t& data);
  594. /**
  595. * @brief Write an 8-bit register
  596. *
  597. * @param handle I2C bus handle
  598. * @param register_addr Register address to write
  599. * @param data Data to write
  600. * @return true if successful, false otherwise
  601. * @ingroup AS7331_I2C_Methods
  602. */
  603. bool writeRegister(FuriHalI2cBusHandle& handle, uint8_t register_addr, const uint8_t& data);
  604. /** @} */ // End of AS7331_I2C_Methods group
  605. /**
  606. * @brief Scan I2C bus for AS7331 device
  607. *
  608. * @return Found I2C address in 7-bit format, 0 if not found
  609. */
  610. uint8_t scan_i2c_bus();
  611. /**
  612. * @brief Update local configuration variables from device registers
  613. *
  614. * @return true if successful, false otherwise
  615. */
  616. bool updateLocalConfig();
  617. /**
  618. * @brief Calculate Full-Scale Range (FSREe) for a given UV type
  619. *
  620. * @param uvType UV type (UV_A, UV_B, UV_C)
  621. * @param adjustForIntegrationTime Optional. A boolean flag indicating whether to adjust FSREe for the integration TIME setting. Default is `true`.
  622. * @return FSREe value in µW/cm², `-1.0` if an error occurs
  623. */
  624. double calculateFSREe(as7331_uv_type_t uvType, bool adjustForIntegrationTime = true);
  625. // Private member variables
  626. uint8_t _i2c_addr_8bit;
  627. as7331_device_mode_t _deviceMode;
  628. bool _power_down;
  629. as7331_gain_t _gain; /**< Gain code (0 to 11) */
  630. as7331_integration_time_t _integration_time; /**< Integration time code (0 to 15) */
  631. bool _enable_divider; /**< Divider enabled (CREG2:EN_DIV) */
  632. as7331_divider_t _divider; /**< Divider value (CREG2:DIV) */
  633. as7331_clock_frequency_t _clock_frequency; /**< Clock frequency code (0 to 3) */
  634. bool _standby;
  635. as7331_measurement_mode_t _measurement_mode;
  636. };