am_hal_adc.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. //*****************************************************************************
  2. //
  3. // am_hal_adc.c
  4. //! @file
  5. //!
  6. //! @brief Functions for interfacing with the Analog to Digital Converter.
  7. //!
  8. //! @addtogroup adc2 Analog-to-Digital Converter (ADC)
  9. //! @ingroup apollo2hal
  10. //! @{
  11. //
  12. //*****************************************************************************
  13. //*****************************************************************************
  14. //
  15. // Copyright (c) 2017, Ambiq Micro
  16. // All rights reserved.
  17. //
  18. // Redistribution and use in source and binary forms, with or without
  19. // modification, are permitted provided that the following conditions are met:
  20. //
  21. // 1. Redistributions of source code must retain the above copyright notice,
  22. // this list of conditions and the following disclaimer.
  23. //
  24. // 2. Redistributions in binary form must reproduce the above copyright
  25. // notice, this list of conditions and the following disclaimer in the
  26. // documentation and/or other materials provided with the distribution.
  27. //
  28. // 3. Neither the name of the copyright holder nor the names of its
  29. // contributors may be used to endorse or promote products derived from this
  30. // software without specific prior written permission.
  31. //
  32. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  33. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  34. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  35. // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  36. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  37. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  38. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  39. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  40. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  42. // POSSIBILITY OF SUCH DAMAGE.
  43. //
  44. // This is part of revision 1.2.11 of the AmbiqSuite Development Package.
  45. //
  46. //*****************************************************************************
  47. #include "am_mcu_apollo.h"
  48. //*****************************************************************************
  49. //
  50. //! @brief Private SRAM view of temperature trims.
  51. //!
  52. //! This static SRAM union is private to the ADC HAL functions.
  53. //
  54. //*****************************************************************************
  55. static union
  56. {
  57. //! These trim values are loaded as uint32_t values.
  58. struct
  59. {
  60. //! Temperature of the package test head (in degrees Kelvin)
  61. uint32_t ui32CalibrationTemperature;
  62. //! Voltage corresponding to temperature measured on test head.
  63. uint32_t ui32CalibrationVoltage;
  64. //! ADC offset voltage measured on the package test head.
  65. uint32_t ui32CalibrationOffset;
  66. //! Flag if default (guess) or measured.
  67. bool bMeasured;
  68. } ui32;
  69. //! These trim values are accessed as floats when used in temp calculations.
  70. struct
  71. {
  72. //! Temperature of the package test head in degrees Kelvin
  73. float fCalibrationTemperature;
  74. //! Voltage corresponding to temperature measured on test head.
  75. float fCalibrationVoltage;
  76. //! ADC offset voltage measured on the package test head.
  77. float fCalibrationOffset;
  78. //! Flag if default (guess) or measured.
  79. float fMeasuredFlag;
  80. } flt;
  81. } priv_temp_trims;
  82. //*****************************************************************************
  83. //
  84. //! @brief Configure the ADC.
  85. //!
  86. //! @param psConfig - pointer to the configuration structure for the ADC.
  87. //!
  88. //! This function may be used to perform the initial setup of the ADC based on
  89. //! setting found in a configuration structure.
  90. //!
  91. //! @return None.
  92. //
  93. //*****************************************************************************
  94. void
  95. am_hal_adc_config(am_hal_adc_config_t *psConfig)
  96. {
  97. //
  98. // Set general ADC configuration parameters.
  99. //
  100. AM_REG(ADC, CFG) = (psConfig->ui32Clock |
  101. psConfig->ui32TriggerConfig |
  102. psConfig->ui32Reference |
  103. psConfig->ui32ClockMode |
  104. psConfig->ui32PowerMode |
  105. psConfig->ui32Repeat |
  106. AM_REG_ADC_CFG_ADCEN(1));
  107. //
  108. // Grab the temperature trims.
  109. //
  110. priv_temp_trims.ui32.ui32CalibrationTemperature =
  111. am_hal_flash_load_ui32(AM_HAL_ADC_CALIB_TEMP_ADDR);
  112. priv_temp_trims.ui32.ui32CalibrationVoltage =
  113. am_hal_flash_load_ui32(AM_HAL_ADC_CALIB_AMBIENT_ADDR);
  114. priv_temp_trims.ui32.ui32CalibrationOffset =
  115. am_hal_flash_load_ui32(AM_HAL_ADC_CALIB_ADC_OFFSET_ADDR);
  116. if ( (priv_temp_trims.ui32.ui32CalibrationTemperature == 0xffffffff) ||
  117. (priv_temp_trims.ui32.ui32CalibrationVoltage == 0xffffffff) ||
  118. (priv_temp_trims.ui32.ui32CalibrationOffset == 0xffffffff) )
  119. {
  120. //
  121. // Since the device has not been calibrated on the tester, we'll load
  122. // default calibration values. These default values should result
  123. // in worst-case temperature measurements of +-6 degress C.
  124. //
  125. priv_temp_trims.flt.fCalibrationTemperature = AM_HAL_ADC_CALIB_TEMP_DEFAULT;
  126. priv_temp_trims.flt.fCalibrationVoltage = AM_HAL_ADC_CALIB_AMBIENT_DEFAULT;
  127. priv_temp_trims.flt.fCalibrationOffset = AM_HAL_ADC_CALIB_ADC_OFFSET_DEFAULT;
  128. priv_temp_trims.ui32.bMeasured = false;
  129. }
  130. else
  131. {
  132. priv_temp_trims.ui32.bMeasured = true;
  133. }
  134. }
  135. //*****************************************************************************
  136. //
  137. //! @brief Get the temperature trim parameters after configuring the ADC.
  138. //!
  139. //! @param pfTemp - pointer to a location to store the calibration temperature.
  140. //! @param pfVoltage - pointer to a location to store the calibration voltage.
  141. //! @param pfOffsetV - pointer to a location to store the calibration offset.
  142. //!
  143. //! This function may be used to access the actual temperature sensor trim
  144. //! values from the private structure.
  145. //!
  146. //! WARNING: only call this after the ADC has been configured with
  147. //! am_hal_adc_config.
  148. //!
  149. //! @return None.
  150. //
  151. //*****************************************************************************
  152. void
  153. am_hal_adc_temp_trims_get(float * pfTemp, float * pfVoltage, float * pfOffsetV)
  154. {
  155. //
  156. // Return trim temperature as a float, if you can.
  157. //
  158. if ( pfTemp != NULL )
  159. {
  160. *pfTemp = priv_temp_trims.flt.fCalibrationTemperature;
  161. }
  162. //
  163. // Return trim voltage as a float, if you can.
  164. //
  165. if ( pfVoltage != NULL )
  166. {
  167. *pfVoltage = priv_temp_trims.flt.fCalibrationVoltage;
  168. }
  169. //
  170. // Return trim ADC offset voltage as a float, if you can.
  171. //
  172. if ( pfOffsetV != NULL )
  173. {
  174. *pfOffsetV = priv_temp_trims.flt.fCalibrationOffset;
  175. }
  176. }
  177. //*****************************************************************************
  178. //
  179. //! @brief Set the ADC window parameters.
  180. //!
  181. //! @param ui32Upper - the upper limit for the ADC window.
  182. //! @param ui32Upper - the lower limit for the ADC window.
  183. //!
  184. //! This function may be used to change the ADC window parameters. Please note
  185. //! that the upper and lower limits are only 16-bits wide in the ADC hardware.
  186. //! This function will ignore the upper 16 bits of these arguments.
  187. //!
  188. //! @return None.
  189. //
  190. //*****************************************************************************
  191. void
  192. am_hal_adc_window_set(uint32_t ui32Upper, uint32_t ui32Lower)
  193. {
  194. //
  195. // Set the window limits for the ADC.
  196. //
  197. AM_BFW(ADC, WULIM, ULIM, ui32Upper);
  198. AM_BFW(ADC, WLLIM, LLIM, ui32Lower);
  199. }
  200. //*****************************************************************************
  201. //
  202. //! @brief Configure a single ADC slot.
  203. //!
  204. //! @param ui32SlotNumber - the number of the ADC slot to be configured.
  205. //! @param ui32SlotConfig - contains slot-specific options.
  206. //!
  207. //! This function may be used to configure the settings for an individual ADC
  208. //! slot. The parameter \b ui32SlotConfig should be the logical 'OR' of a slot
  209. //! average macro, a slot hold-time macro, a slot channel macro, and
  210. //! optionally, the slot window enable macro.
  211. //!
  212. //! @return None.
  213. //
  214. //*****************************************************************************
  215. void
  216. am_hal_adc_slot_config(uint32_t ui32SlotNumber, uint32_t ui32SlotConfig)
  217. {
  218. uint32_t ui32RegOffset;
  219. //
  220. // Make sure we're accessing a real slot.
  221. //
  222. am_hal_debug_assert_msg((ui32SlotNumber & 0xFFFFFFFF0) == 0,
  223. "Trying to configure an ADC slot that doesn't exist.");
  224. //
  225. // Locate the correct register for this ADC slot.
  226. //
  227. ui32RegOffset = (AM_REG_ADCn(0) + AM_REG_ADC_SL0CFG_O + (4 * ui32SlotNumber));
  228. //
  229. // Write the register with the caller's configuration value.
  230. //
  231. AM_REGVAL(ui32RegOffset) = ui32SlotConfig;
  232. }
  233. //*****************************************************************************
  234. //
  235. //! @brief Peek at the next fifo entry.
  236. //!
  237. //! This function reads the oldest value in the ADC sample fifo but doesn't
  238. //! actually advance the fifo to the next entry. This function is useful when
  239. //! you need information from the fifo but you don't want to also empty the
  240. //! fifo. This could be helpful if you want to check the FIFO depth without
  241. //! pulling any data out.
  242. //!
  243. //! The value returned by this function is the raw 32-bit value provided by the
  244. //! ADC hardware. In order to interpret this value, you will need to use one of
  245. //! the following macros.
  246. //!
  247. //! @return 32-bit FIFO entry.
  248. //!
  249. //
  250. //*****************************************************************************
  251. uint32_t
  252. am_hal_adc_fifo_peek(void)
  253. {
  254. uint32_t ui32FIFOValue;
  255. //
  256. // Grab a value from the ADC FIFO.
  257. //
  258. ui32FIFOValue = AM_REG(ADC, FIFO);
  259. //
  260. // Return FIFO entry.
  261. //
  262. return ui32FIFOValue;
  263. }
  264. //*****************************************************************************
  265. //
  266. //! @brief
  267. //!
  268. //! This function reads the oldest value in the ADC fifo and then pops the
  269. //! fifo. Use this function when you actually want to pull data out of the
  270. //! fifo.
  271. //!
  272. //! @return 32-bit FIFO entry.
  273. //!
  274. //
  275. //*****************************************************************************
  276. uint32_t
  277. am_hal_adc_fifo_pop(void)
  278. {
  279. uint32_t ui32FIFOValue;
  280. //
  281. // Grab a value from the ADC FIFO.
  282. //
  283. ui32FIFOValue = AM_REG(ADC, FIFO);
  284. //
  285. // Pop the FIFO.
  286. //
  287. AM_REG(ADC, FIFO) = 0;
  288. //
  289. // Return FIFO valid bits.
  290. //
  291. return ui32FIFOValue;
  292. }
  293. //*****************************************************************************
  294. //
  295. //! @brief Issue Software Trigger to the ADC.
  296. //!
  297. //! This function issues the software trigger to the ADC.
  298. //!
  299. //! @return None.
  300. //
  301. //*****************************************************************************
  302. void
  303. am_hal_adc_trigger(void)
  304. {
  305. //
  306. // Write to the Software trigger register in the ADC.
  307. //
  308. AM_REG(ADC, SWT) = 0x37;
  309. }
  310. //*****************************************************************************
  311. //
  312. //! @brief Enable the ADC.
  313. //!
  314. //! Use this function to enable the ADC.
  315. //!
  316. //! @return None.
  317. //
  318. //*****************************************************************************
  319. void
  320. am_hal_adc_enable(void)
  321. {
  322. //
  323. // Enable the ADC.
  324. //
  325. AM_BFW(ADC, CFG, ADCEN, 0x1);
  326. }
  327. //*****************************************************************************
  328. //
  329. //! @brief Disable the ADC.
  330. //!
  331. //! Use this function to disable the ADC.
  332. //!
  333. //! @return None.
  334. //
  335. //*****************************************************************************
  336. void
  337. am_hal_adc_disable(void)
  338. {
  339. //
  340. // Disable the ADC.
  341. //
  342. AM_BFW(ADC, CFG, ADCEN, 0x0);
  343. }
  344. //*****************************************************************************
  345. //
  346. //! @brief Enable selected ADC Interrupts.
  347. //!
  348. //! @param ui32Interrupt - Use the macro bit fields provided in am_hal_adc.h.
  349. //!
  350. //! Use this function to enable the ADC interrupts.
  351. //!
  352. //! @return None.
  353. //
  354. //*****************************************************************************
  355. void
  356. am_hal_adc_int_enable(uint32_t ui32Interrupt)
  357. {
  358. //
  359. // Enable the interrupts.
  360. //
  361. AM_REG(ADC, INTEN) |= ui32Interrupt;
  362. }
  363. //*****************************************************************************
  364. //
  365. //! @brief Return enabled ADC Interrupts.
  366. //!
  367. //! Use this function to get all enabled ADC interrupts.
  368. //!
  369. //! @return enabled ADC Interrupts.
  370. //
  371. //*****************************************************************************
  372. uint32_t
  373. am_hal_adc_int_enable_get(void)
  374. {
  375. //
  376. // Return enabled interrupts.
  377. //
  378. return AM_REG(ADC, INTEN);
  379. }
  380. //*****************************************************************************
  381. //
  382. //! @brief Disable selected ADC Interrupts.
  383. //!
  384. //! @param ui32Interrupt - Use the macro bit fields provided in am_hal_adc.h.
  385. //!
  386. //! Use this function to disable the ADC interrupts.
  387. //!
  388. //! @return None.
  389. //
  390. //*****************************************************************************
  391. void
  392. am_hal_adc_int_disable(uint32_t ui32Interrupt)
  393. {
  394. //
  395. // Disable the interrupts.
  396. //
  397. AM_REG(ADC, INTEN) &= ~ui32Interrupt;
  398. }
  399. //*****************************************************************************
  400. //
  401. //! @brief Clear selected ADC Interrupts.
  402. //!
  403. //! @param ui32Interrupt - Use the macro bit fields provided in am_hal_adc.h.
  404. //!
  405. //! Use this function to clear the ADC interrupts.
  406. //!
  407. //! @return None.
  408. //
  409. //*****************************************************************************
  410. void
  411. am_hal_adc_int_clear(uint32_t ui32Interrupt)
  412. {
  413. //
  414. // Clear the interrupts.
  415. //
  416. AM_REG(ADC, INTCLR) = ui32Interrupt;
  417. }
  418. //*****************************************************************************
  419. //
  420. //! @brief Set selected ADC Interrupts.
  421. //!
  422. //! @param ui32Interrupt - Use the macro bit fields provided in am_hal_adc.h.
  423. //!
  424. //! Use this function to set the ADC interrupts.
  425. //!
  426. //! @return None.
  427. //
  428. //*****************************************************************************
  429. void
  430. am_hal_adc_int_set(uint32_t ui32Interrupt)
  431. {
  432. //
  433. // Set the interrupts.
  434. //
  435. AM_REG(ADC, INTSET) = ui32Interrupt;
  436. }
  437. //*****************************************************************************
  438. //
  439. //! @brief Return either enabled or raw selected ADC interrupt status.
  440. //!
  441. //! @param bEnabledOnly - return the status of only the enabled interrupts.
  442. //!
  443. //! Use this function to get the ADC interrupt status.
  444. //!
  445. //! @return enabled or raw ADC interrupt status.
  446. //
  447. //*****************************************************************************
  448. uint32_t
  449. am_hal_adc_int_status_get(bool bEnabledOnly)
  450. {
  451. //
  452. // Return the status.
  453. //
  454. if (bEnabledOnly)
  455. {
  456. uint32_t u32RetVal = AM_REG(ADC, INTEN);
  457. u32RetVal &= AM_REG(ADC, INTSTAT);
  458. return u32RetVal;
  459. }
  460. else
  461. {
  462. return AM_REG(ADC, INTSTAT);
  463. }
  464. }
  465. //*****************************************************************************
  466. //
  467. //! @brief Return temperature in degrees C of supplied voltage.
  468. //!
  469. //! @param fVoltage - return the temperature corresponding to this voltage.
  470. //!
  471. //! Use this function to convert volts from the temperature sensor into degrees
  472. //! C. Caller converts ADC binary code to volts based on reference used.
  473. //! This routine looks up the trim parameters and returns corrected temperature.
  474. //!
  475. //! The computation is based on a line running through 0 degrees K.
  476. //! We find the slope from the trimmed temperature calibration point.
  477. //!
  478. //!
  479. //! @return the temperature in degrees C.
  480. //
  481. //*****************************************************************************
  482. float
  483. am_hal_adc_volts_to_celsius(float fVoltage)
  484. {
  485. float fTemp;
  486. //
  487. // Get calibration temperature from trimmed values & convert to degrees K.
  488. //
  489. float fCalibration_temp = priv_temp_trims.flt.fCalibrationTemperature;
  490. //
  491. // Get remaining trimmed values.
  492. //
  493. float fCalibration_voltage = priv_temp_trims.flt.fCalibrationVoltage;
  494. float fCalibration_offset = priv_temp_trims.flt.fCalibrationOffset;
  495. //
  496. // Compute the temperature.
  497. //
  498. fTemp = fCalibration_temp;
  499. fTemp /= (fCalibration_voltage - fCalibration_offset);
  500. fTemp *= (fVoltage - fCalibration_offset);
  501. //
  502. // Give it back to the caller in Celsius.
  503. //
  504. return fTemp - 273.15f;
  505. }
  506. //*****************************************************************************
  507. //
  508. // End Doxygen group.
  509. //! @}
  510. //
  511. //*****************************************************************************