em_adc.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. /***************************************************************************//**
  2. * @file
  3. * @brief Analog to Digital Converter (ADC) Peripheral API
  4. * @author Energy Micro AS
  5. * @version 3.0.0
  6. *******************************************************************************
  7. * @section License
  8. * <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
  9. *******************************************************************************
  10. *
  11. * Permission is granted to anyone to use this software for any purpose,
  12. * including commercial applications, and to alter it and redistribute it
  13. * freely, subject to the following restrictions:
  14. *
  15. * 1. The origin of this software must not be misrepresented; you must not
  16. * claim that you wrote the original software.
  17. * 2. Altered source versions must be plainly marked as such, and must not be
  18. * misrepresented as being the original software.
  19. * 3. This notice may not be removed or altered from any source distribution.
  20. *
  21. * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
  22. * obligation to support this Software. Energy Micro AS is providing the
  23. * Software "AS IS", with no express or implied warranties of any kind,
  24. * including, but not limited to, any implied warranties of merchantability
  25. * or fitness for any particular purpose or warranties against infringement
  26. * of any proprietary rights of a third party.
  27. *
  28. * Energy Micro AS will not be liable for any consequential, incidental, or
  29. * special damages, or any other relief, or for any claim by any third party,
  30. * arising from your use of this Software.
  31. *
  32. ******************************************************************************/
  33. #include "em_adc.h"
  34. #include "em_cmu.h"
  35. #include "em_assert.h"
  36. /***************************************************************************//**
  37. * @addtogroup EM_Library
  38. * @{
  39. ******************************************************************************/
  40. /***************************************************************************//**
  41. * @addtogroup ADC
  42. * @brief Analog to Digital Converter (ADC) Peripheral API
  43. * @{
  44. ******************************************************************************/
  45. /*******************************************************************************
  46. ******************************* DEFINES ***********************************
  47. ******************************************************************************/
  48. /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
  49. /** Validation of ADC register block pointer reference for assert statements. */
  50. #define ADC_REF_VALID(ref) ((ref) == ADC0)
  51. /** Max ADC clock */
  52. #define ADC_MAX_CLOCK 13000000
  53. /** Min ADC clock */
  54. #define ADC_MIN_CLOCK 32000
  55. /** @endcond */
  56. /*******************************************************************************
  57. *************************** LOCAL FUNCTIONS *******************************
  58. ******************************************************************************/
  59. /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
  60. /***************************************************************************//**
  61. * @brief
  62. * Load SCAN calibrate register with predefined values for a certain
  63. * reference.
  64. *
  65. * @details
  66. * During production, calibration values are made and stored in the device
  67. * information page for known references. Notice that for external references,
  68. * calibration values must be determined explicitly, and this function
  69. * will not modify the calibration register.
  70. *
  71. * @param[in] adc
  72. * Pointer to ADC peripheral register block.
  73. *
  74. * @param[in] ref
  75. * Reference to load calibrated values for. No values are loaded for
  76. * external references.
  77. ******************************************************************************/
  78. static void ADC_CalibrateLoadScan(ADC_TypeDef *adc, ADC_Ref_TypeDef ref)
  79. {
  80. uint32_t cal;
  81. /* Load proper calibration data depending on selected reference */
  82. /* NOTE: We use ...SCAN... defines below, they are the same as */
  83. /* similar ...SINGLE... defines. */
  84. switch (ref)
  85. {
  86. case adcRef1V25:
  87. cal = adc->CAL & ~(_ADC_CAL_SCANOFFSET_MASK | _ADC_CAL_SCANGAIN_MASK);
  88. cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_1V25_GAIN_MASK) >>
  89. _DEVINFO_ADC0CAL0_1V25_GAIN_SHIFT) << _ADC_CAL_SCANGAIN_SHIFT;
  90. cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_1V25_OFFSET_MASK) >>
  91. _DEVINFO_ADC0CAL0_1V25_OFFSET_SHIFT) << _ADC_CAL_SCANOFFSET_SHIFT;
  92. adc->CAL = cal;
  93. break;
  94. case adcRef2V5:
  95. cal = adc->CAL & ~(_ADC_CAL_SCANOFFSET_MASK | _ADC_CAL_SCANGAIN_MASK);
  96. cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_2V5_GAIN_MASK) >>
  97. _DEVINFO_ADC0CAL0_2V5_GAIN_SHIFT) << _ADC_CAL_SCANGAIN_SHIFT;
  98. cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_2V5_OFFSET_MASK) >>
  99. _DEVINFO_ADC0CAL0_2V5_OFFSET_SHIFT) << _ADC_CAL_SCANOFFSET_SHIFT;
  100. adc->CAL = cal;
  101. break;
  102. case adcRefVDD:
  103. cal = adc->CAL & ~(_ADC_CAL_SCANOFFSET_MASK | _ADC_CAL_SCANGAIN_MASK);
  104. cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_VDD_GAIN_MASK) >>
  105. _DEVINFO_ADC0CAL1_VDD_GAIN_SHIFT) << _ADC_CAL_SCANGAIN_SHIFT;
  106. cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_VDD_OFFSET_MASK) >>
  107. _DEVINFO_ADC0CAL1_VDD_OFFSET_SHIFT) << _ADC_CAL_SCANOFFSET_SHIFT;
  108. adc->CAL = cal;
  109. break;
  110. case adcRef5VDIFF:
  111. cal = adc->CAL & ~(_ADC_CAL_SCANOFFSET_MASK | _ADC_CAL_SCANGAIN_MASK);
  112. cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_5VDIFF_GAIN_MASK) >>
  113. _DEVINFO_ADC0CAL1_5VDIFF_GAIN_SHIFT) << _ADC_CAL_SCANGAIN_SHIFT;
  114. cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_MASK) >>
  115. _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_SHIFT) << _ADC_CAL_SCANOFFSET_SHIFT;
  116. adc->CAL = cal;
  117. break;
  118. case adcRef2xVDD:
  119. /* Gain value not of relevance for this reference, leave as is */
  120. cal = adc->CAL & ~_ADC_CAL_SCANOFFSET_MASK;
  121. cal |= ((DEVINFO->ADC0CAL2 & _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_MASK) >>
  122. _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_SHIFT) << _ADC_CAL_SCANOFFSET_SHIFT;
  123. adc->CAL = cal;
  124. break;
  125. /* For external references, the calibration must be determined for the */
  126. /* specific application and set explicitly. */
  127. default:
  128. break;
  129. }
  130. }
  131. /***************************************************************************//**
  132. * @brief
  133. * Load SINGLE calibrate register with predefined values for a certain
  134. * reference.
  135. *
  136. * @details
  137. * During production, calibration values are made and stored in the device
  138. * information page for known references. Notice that for external references,
  139. * calibration values must be determined explicitly, and this function
  140. * will not modify the calibration register.
  141. *
  142. * @param[in] adc
  143. * Pointer to ADC peripheral register block.
  144. *
  145. * @param[in] ref
  146. * Reference to load calibrated values for. No values are loaded for
  147. * external references.
  148. ******************************************************************************/
  149. static void ADC_CalibrateLoadSingle(ADC_TypeDef *adc, ADC_Ref_TypeDef ref)
  150. {
  151. uint32_t cal;
  152. /* Load proper calibration data depending on selected reference */
  153. /* NOTE: We use ...SCAN... defines below, they are the same as */
  154. /* similar ...SINGLE... defines. */
  155. switch (ref)
  156. {
  157. case adcRef1V25:
  158. cal = adc->CAL & ~(_ADC_CAL_SINGLEOFFSET_MASK | _ADC_CAL_SINGLEGAIN_MASK);
  159. cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_1V25_GAIN_MASK) >>
  160. _DEVINFO_ADC0CAL0_1V25_GAIN_SHIFT) << _ADC_CAL_SINGLEGAIN_SHIFT;
  161. cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_1V25_OFFSET_MASK) >>
  162. _DEVINFO_ADC0CAL0_1V25_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
  163. adc->CAL = cal;
  164. break;
  165. case adcRef2V5:
  166. cal = adc->CAL & ~(_ADC_CAL_SINGLEOFFSET_MASK | _ADC_CAL_SINGLEGAIN_MASK);
  167. cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_2V5_GAIN_MASK) >>
  168. _DEVINFO_ADC0CAL0_2V5_GAIN_SHIFT) << _ADC_CAL_SINGLEGAIN_SHIFT;
  169. cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_2V5_OFFSET_MASK) >>
  170. _DEVINFO_ADC0CAL0_2V5_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
  171. adc->CAL = cal;
  172. break;
  173. case adcRefVDD:
  174. cal = adc->CAL & ~(_ADC_CAL_SINGLEOFFSET_MASK | _ADC_CAL_SINGLEGAIN_MASK);
  175. cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_VDD_GAIN_MASK) >>
  176. _DEVINFO_ADC0CAL1_VDD_GAIN_SHIFT) << _ADC_CAL_SINGLEGAIN_SHIFT;
  177. cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_VDD_OFFSET_MASK) >>
  178. _DEVINFO_ADC0CAL1_VDD_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
  179. adc->CAL = cal;
  180. break;
  181. case adcRef5VDIFF:
  182. cal = adc->CAL & ~(_ADC_CAL_SINGLEOFFSET_MASK | _ADC_CAL_SINGLEGAIN_MASK);
  183. cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_5VDIFF_GAIN_MASK) >>
  184. _DEVINFO_ADC0CAL1_5VDIFF_GAIN_SHIFT) << _ADC_CAL_SINGLEGAIN_SHIFT;
  185. cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_MASK) >>
  186. _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
  187. adc->CAL = cal;
  188. break;
  189. case adcRef2xVDD:
  190. /* Gain value not of relevance for this reference, leave as is */
  191. cal = adc->CAL & ~_ADC_CAL_SINGLEOFFSET_MASK;
  192. cal |= ((DEVINFO->ADC0CAL2 & _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_MASK) >>
  193. _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
  194. adc->CAL = cal;
  195. break;
  196. /* For external references, the calibration must be determined for the */
  197. /* specific application and set explicitly. */
  198. default:
  199. break;
  200. }
  201. }
  202. /** @endcond */
  203. /*******************************************************************************
  204. ************************** GLOBAL FUNCTIONS *******************************
  205. ******************************************************************************/
  206. /***************************************************************************//**
  207. * @brief
  208. * Initialize ADC.
  209. *
  210. * @details
  211. * Initializes common parts for both single conversion and scan sequence.
  212. * In addition, single and/or scan control configuration must be done, please
  213. * refer to ADC_InitSingle() and ADC_InitScan() respectively.
  214. *
  215. * @note
  216. * This function will stop any ongoing conversion.
  217. *
  218. * @param[in] adc
  219. * Pointer to ADC peripheral register block.
  220. *
  221. * @param[in] init
  222. * Pointer to ADC initialization structure.
  223. ******************************************************************************/
  224. void ADC_Init(ADC_TypeDef *adc, const ADC_Init_TypeDef *init)
  225. {
  226. uint32_t tmp;
  227. EFM_ASSERT(ADC_REF_VALID(adc));
  228. /* Make sure conversion is not in progress */
  229. adc->CMD = ADC_CMD_SINGLESTOP | ADC_CMD_SCANSTOP;
  230. tmp = ((uint32_t)(init->ovsRateSel) << _ADC_CTRL_OVSRSEL_SHIFT) |
  231. (((uint32_t)(init->timebase) << _ADC_CTRL_TIMEBASE_SHIFT) & _ADC_CTRL_TIMEBASE_MASK) |
  232. (((uint32_t)(init->prescale) << _ADC_CTRL_PRESC_SHIFT) & _ADC_CTRL_PRESC_MASK) |
  233. ((uint32_t)(init->lpfMode) << _ADC_CTRL_LPFMODE_SHIFT) |
  234. ((uint32_t)(init->warmUpMode) << _ADC_CTRL_WARMUPMODE_SHIFT);
  235. if (init->tailgate)
  236. {
  237. tmp |= ADC_CTRL_TAILGATE;
  238. }
  239. adc->CTRL = tmp;
  240. }
  241. /***************************************************************************//**
  242. * @brief
  243. * Initialize ADC scan sequence.
  244. *
  245. * @details
  246. * Please refer to ADC_StartScan() for starting scan sequence.
  247. *
  248. * When selecting an external reference, the gain and offset calibration
  249. * must be set explicitly (CAL register). For other references, the
  250. * calibration is updated with values defined during manufacturing.
  251. *
  252. * @note
  253. * This function will stop any ongoing scan sequence.
  254. *
  255. * @param[in] adc
  256. * Pointer to ADC peripheral register block.
  257. *
  258. * @param[in] init
  259. * Pointer to ADC initialization structure.
  260. ******************************************************************************/
  261. void ADC_InitScan(ADC_TypeDef *adc, const ADC_InitScan_TypeDef *init)
  262. {
  263. uint32_t tmp;
  264. EFM_ASSERT(ADC_REF_VALID(adc));
  265. /* Make sure scan sequence is not in progress */
  266. adc->CMD = ADC_CMD_SCANSTOP;
  267. /* Load proper calibration data depending on selected reference */
  268. ADC_CalibrateLoadScan(adc, init->reference);
  269. tmp = ((uint32_t)(init->prsSel) << _ADC_SCANCTRL_PRSSEL_SHIFT) |
  270. ((uint32_t)(init->acqTime) << _ADC_SCANCTRL_AT_SHIFT) |
  271. ((uint32_t)(init->reference) << _ADC_SCANCTRL_REF_SHIFT) |
  272. init->input |
  273. ((uint32_t)(init->resolution) << _ADC_SCANCTRL_RES_SHIFT);
  274. if (init->prsEnable)
  275. {
  276. tmp |= ADC_SCANCTRL_PRSEN;
  277. }
  278. if (init->leftAdjust)
  279. {
  280. tmp |= ADC_SCANCTRL_ADJ_LEFT;
  281. }
  282. if (init->diff)
  283. {
  284. tmp |= ADC_SCANCTRL_DIFF;
  285. }
  286. if (init->rep)
  287. {
  288. tmp |= ADC_SCANCTRL_REP;
  289. }
  290. adc->SCANCTRL = tmp;
  291. }
  292. /***************************************************************************//**
  293. * @brief
  294. * Initialize single ADC sample conversion.
  295. *
  296. * @details
  297. * Please refer to ADC_StartSingle() for starting single conversion.
  298. *
  299. * When selecting an external reference, the gain and offset calibration
  300. * must be set explicitly (CAL register). For other references, the
  301. * calibration is updated with values defined during manufacturing.
  302. *
  303. * @note
  304. * This function will stop any ongoing single conversion.
  305. *
  306. * @param[in] adc
  307. * Pointer to ADC peripheral register block.
  308. *
  309. * @param[in] init
  310. * Pointer to ADC initialization structure.
  311. ******************************************************************************/
  312. void ADC_InitSingle(ADC_TypeDef *adc, const ADC_InitSingle_TypeDef *init)
  313. {
  314. uint32_t tmp;
  315. EFM_ASSERT(ADC_REF_VALID(adc));
  316. /* Make sure single conversion is not in progress */
  317. adc->CMD = ADC_CMD_SINGLESTOP;
  318. /* Load proper calibration data depending on selected reference */
  319. ADC_CalibrateLoadSingle(adc, init->reference);
  320. tmp = ((uint32_t)(init->prsSel) << _ADC_SINGLECTRL_PRSSEL_SHIFT) |
  321. ((uint32_t)(init->acqTime) << _ADC_SINGLECTRL_AT_SHIFT) |
  322. ((uint32_t)(init->reference) << _ADC_SINGLECTRL_REF_SHIFT) |
  323. ((uint32_t)(init->input) << _ADC_SINGLECTRL_INPUTSEL_SHIFT) |
  324. ((uint32_t)(init->resolution) << _ADC_SINGLECTRL_RES_SHIFT);
  325. if (init->prsEnable)
  326. {
  327. tmp |= ADC_SINGLECTRL_PRSEN;
  328. }
  329. if (init->leftAdjust)
  330. {
  331. tmp |= ADC_SINGLECTRL_ADJ_LEFT;
  332. }
  333. if (init->diff)
  334. {
  335. tmp |= ADC_SINGLECTRL_DIFF;
  336. }
  337. if (init->rep)
  338. {
  339. tmp |= ADC_SINGLECTRL_REP;
  340. }
  341. adc->SINGLECTRL = tmp;
  342. }
  343. /***************************************************************************//**
  344. * @brief
  345. * Calculate prescaler value used to determine ADC clock.
  346. *
  347. * @details
  348. * The ADC clock is given by: HFPERCLK / (prescale + 1).
  349. *
  350. * @param[in] adcFreq ADC frequency wanted. The frequency will automatically
  351. * be adjusted to be within valid range according to reference manual.
  352. *
  353. * @param[in] hfperFreq Frequency in Hz of reference HFPER clock. Set to 0 to
  354. * use currently defined HFPER clock setting.
  355. *
  356. * @return
  357. * Prescaler value to use for ADC in order to achieve a clock value
  358. * <= @p adcFreq.
  359. ******************************************************************************/
  360. uint8_t ADC_PrescaleCalc(uint32_t adcFreq, uint32_t hfperFreq)
  361. {
  362. uint32_t ret;
  363. /* Make sure selected ADC clock is within valid range */
  364. if (adcFreq > ADC_MAX_CLOCK)
  365. {
  366. adcFreq = ADC_MAX_CLOCK;
  367. }
  368. else if (adcFreq < ADC_MIN_CLOCK)
  369. {
  370. adcFreq = ADC_MIN_CLOCK;
  371. }
  372. /* Use current HFPER frequency? */
  373. if (!hfperFreq)
  374. {
  375. hfperFreq = CMU_ClockFreqGet(cmuClock_HFPER);
  376. }
  377. ret = (hfperFreq + adcFreq - 1) / adcFreq;
  378. if (ret)
  379. {
  380. ret--;
  381. }
  382. return (uint8_t)ret;
  383. }
  384. /***************************************************************************//**
  385. * @brief
  386. * Reset ADC to same state as after a HW reset.
  387. *
  388. * @note
  389. * The ROUTE register is NOT reset by this function, in order to allow for
  390. * centralized setup of this feature.
  391. *
  392. * @param[in] adc
  393. * Pointer to ADC peripheral register block.
  394. ******************************************************************************/
  395. void ADC_Reset(ADC_TypeDef *adc)
  396. {
  397. uint32_t cal;
  398. /* Stop conversions, before resetting other registers. */
  399. adc->CMD = ADC_CMD_SINGLESTOP | ADC_CMD_SCANSTOP;
  400. adc->SINGLECTRL = _ADC_SINGLECTRL_RESETVALUE;
  401. adc->SCANCTRL = _ADC_SCANCTRL_RESETVALUE;
  402. adc->CTRL = _ADC_CTRL_RESETVALUE;
  403. adc->IEN = _ADC_IEN_RESETVALUE;
  404. adc->IFC = _ADC_IFC_MASK;
  405. adc->BIASPROG = _ADC_BIASPROG_RESETVALUE;
  406. cal = adc->CAL & ~(_ADC_CAL_SINGLEOFFSET_MASK | _ADC_CAL_SINGLEGAIN_MASK);
  407. cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_1V25_GAIN_MASK) >>
  408. _DEVINFO_ADC0CAL0_1V25_GAIN_SHIFT) << _ADC_CAL_SINGLEGAIN_SHIFT;
  409. cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_1V25_OFFSET_MASK) >>
  410. _DEVINFO_ADC0CAL0_1V25_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
  411. adc->CAL = cal;
  412. /* Do not reset route register, setting should be done independently */
  413. }
  414. /***************************************************************************//**
  415. * @brief
  416. * Calculate timebase value in order to get a timebase providing at least 1us.
  417. *
  418. * @param[in] hfperFreq Frequency in Hz of reference HFPER clock. Set to 0 to
  419. * use currently defined HFPER clock setting.
  420. *
  421. * @return
  422. * Timebase value to use for ADC in order to achieve at least 1 us.
  423. ******************************************************************************/
  424. uint8_t ADC_TimebaseCalc(uint32_t hfperFreq)
  425. {
  426. if (!hfperFreq)
  427. {
  428. hfperFreq = CMU_ClockFreqGet(cmuClock_HFPER);
  429. /* Just in case, make sure we get non-zero freq for below calculation */
  430. if (!hfperFreq)
  431. {
  432. hfperFreq = 1;
  433. }
  434. }
  435. #if defined(_EFM32_GIANT_FAMILY)
  436. /* Handle errata on Giant Gecko, max TIMEBASE is 5 bits wide or max 0x1F */
  437. /* cycles. This will give a warmp up time of e.g. 0.645us, not the */
  438. /* required 1us when operating at 48MHz. One must also increase acqTime */
  439. /* to compensate for the missing clock cycles, adding up to 1us in total.*/
  440. /* See reference manual for details. */
  441. if( hfperFreq > 32000000 )
  442. {
  443. hfperFreq = 32000000;
  444. }
  445. #endif
  446. /* Determine number of HFPERCLK cycle >= 1us */
  447. hfperFreq += 999999;
  448. hfperFreq /= 1000000;
  449. /* Return timebase value (N+1 format) */
  450. return (uint8_t)(hfperFreq - 1);
  451. }
  452. /** @} (end addtogroup ADC) */
  453. /** @} (end addtogroup EM_Library) */