You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

stm32l1xx_hal_opamp_ex.c 33KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  1. /**
  2. ******************************************************************************
  3. * @file stm32l1xx_hal_opamp_ex.c
  4. * @author MCD Application Team
  5. * @brief Extended OPAMP HAL module driver.
  6. *
  7. * This file provides firmware functions to manage the following
  8. * functionalities of the operational amplifier(s)(OPAMP1, OPAMP2 etc)
  9. * peripheral:
  10. * + Extended Initialization and de-initialization functions
  11. * + Extended Peripheral Control functions
  12. *
  13. ******************************************************************************
  14. * @attention
  15. *
  16. * <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
  17. * All rights reserved.</center></h2>
  18. *
  19. * This software component is licensed by ST under BSD 3-Clause license,
  20. * the "License"; You may not use this file except in compliance with the
  21. * License. You may obtain a copy of the License at:
  22. * opensource.org/licenses/BSD-3-Clause
  23. *
  24. ******************************************************************************
  25. */
  26. /* Includes ------------------------------------------------------------------*/
  27. #include "stm32l1xx_hal.h"
  28. #ifdef HAL_OPAMP_MODULE_ENABLED
  29. #if defined (STM32L151xCA) || defined (STM32L151xD) || defined (STM32L152xCA) || defined (STM32L152xD) || defined (STM32L162xCA) || defined (STM32L162xD) || defined (STM32L151xE) || defined (STM32L151xDX) || defined (STM32L152xE) || defined (STM32L152xDX) || defined (STM32L162xE) || defined (STM32L162xDX) || defined (STM32L162xC) || defined (STM32L152xC) || defined (STM32L151xC)
  30. /** @addtogroup STM32L1xx_HAL_Driver
  31. * @{
  32. */
  33. /** @defgroup OPAMPEx OPAMPEx
  34. * @brief OPAMP Extended HAL module driver.
  35. * @{
  36. */
  37. /* Private typedef -----------------------------------------------------------*/
  38. /* Private define ------------------------------------------------------------*/
  39. /* Private macro -------------------------------------------------------------*/
  40. /* Private variables ---------------------------------------------------------*/
  41. /* Private function prototypes -----------------------------------------------*/
  42. /* Exported functions --------------------------------------------------------*/
  43. /** @addtogroup OPAMPEx_Exported_Functions OPAMPEx Exported Functions
  44. * @{
  45. */
  46. /** @addtogroup OPAMPEx_Exported_Functions_Group1
  47. * @brief Extended operation functions
  48. *
  49. @verbatim
  50. ===============================================================================
  51. ##### Extended IO operation functions #####
  52. ===============================================================================
  53. [..]
  54. (+) OPAMP Self calibration.
  55. @endverbatim
  56. * @{
  57. */
  58. #if defined (STM32L151xD) || defined (STM32L152xD) || defined (STM32L162xD)
  59. /* 3 OPAMPS available */
  60. /* 3 OPAMPS can be calibrated in parallel */
  61. /**
  62. * @brief Run the self calibration of the 3 OPAMPs in parallel.
  63. * @note Trimming values (PMOS & NMOS) are updated and user trimming is
  64. * enabled is calibration is succesful.
  65. * @note Calibration is performed in the mode specified in OPAMP init
  66. * structure (mode normal or low-power). To perform calibration for
  67. * both modes, repeat this function twice after OPAMP init structure
  68. * accordingly updated.
  69. * @note Calibration runs about 10 ms (5 dichotmy steps, repeated for P
  70. * and N transistors: 10 steps with 1 ms for each step).
  71. * @param hopamp1 handle
  72. * @param hopamp2 handle
  73. * @param hopamp3 handle
  74. * @retval HAL status
  75. */
  76. HAL_StatusTypeDef HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef *hopamp1, OPAMP_HandleTypeDef *hopamp2, OPAMP_HandleTypeDef *hopamp3)
  77. {
  78. HAL_StatusTypeDef status = HAL_OK;
  79. uint32_t* opamp1_trimmingvalue;
  80. uint32_t opamp1_trimmingvaluen = 0;
  81. uint32_t opamp1_trimmingvaluep = 0;
  82. uint32_t* opamp2_trimmingvalue;
  83. uint32_t opamp2_trimmingvaluen = 0;
  84. uint32_t opamp2_trimmingvaluep = 0;
  85. uint32_t* opamp3_trimmingvalue;
  86. uint32_t opamp3_trimmingvaluen = 0;
  87. uint32_t opamp3_trimmingvaluep = 0;
  88. uint32_t trimming_diff_pair; /* Selection of differential transistors pair high or low */
  89. __IO uint32_t* tmp_opamp1_reg_trimming; /* Selection of register of trimming depending on power mode: OTR or LPOTR */
  90. __IO uint32_t* tmp_opamp2_reg_trimming;
  91. __IO uint32_t* tmp_opamp3_reg_trimming;
  92. uint32_t tmp_opamp1_otr_otuser; /* Selection of bit OPAMP_OTR_OT_USER depending on trimming register pointed: OTR or LPOTR */
  93. uint32_t tmp_opamp2_otr_otuser;
  94. uint32_t tmp_opamp3_otr_otuser;
  95. uint32_t tmp_Opa1calout_DefaultSate; /* Bit OPAMP_CSR_OPA1CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
  96. uint32_t tmp_Opa2calout_DefaultSate; /* Bit OPAMP_CSR_OPA2CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
  97. uint32_t tmp_Opa3calout_DefaultSate; /* Bit OPAMP_CSR_OPA3CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
  98. uint32_t tmp_OpaxSwitchesContextBackup = 0x0U;
  99. uint8_t trimming_diff_pair_iteration_count = 0x0U; /* For calibration loop algorithm: to repeat the calibration loop for both differential transistors pair high and low */
  100. uint8_t delta; /* For calibration loop algorithm: Variable for dichotomy steps value */
  101. uint8_t final_step_check = 0x0U; /* For calibration loop algorithm: Flag for additional check of last trimming step */
  102. if((hopamp1 == NULL) || (hopamp2 == NULL) || (hopamp3 == NULL))
  103. {
  104. status = HAL_ERROR;
  105. }
  106. /* Check if OPAMP in calibration mode and calibration not yet enable */
  107. else if(hopamp1->State != HAL_OPAMP_STATE_READY)
  108. {
  109. status = HAL_ERROR;
  110. }
  111. else if(hopamp2->State != HAL_OPAMP_STATE_READY)
  112. {
  113. status = HAL_ERROR;
  114. }
  115. else if(hopamp3->State != HAL_OPAMP_STATE_READY)
  116. {
  117. status = HAL_ERROR;
  118. }
  119. else
  120. {
  121. /* Check the parameter */
  122. assert_param(IS_OPAMP_ALL_INSTANCE(hopamp1->Instance));
  123. assert_param(IS_OPAMP_ALL_INSTANCE(hopamp2->Instance));
  124. assert_param(IS_OPAMP_ALL_INSTANCE(hopamp3->Instance));
  125. assert_param(IS_OPAMP_POWERMODE(hopamp1->Init.PowerMode));
  126. assert_param(IS_OPAMP_POWERMODE(hopamp2->Init.PowerMode));
  127. assert_param(IS_OPAMP_POWERMODE(hopamp3->Init.PowerMode));
  128. /* Update OPAMP state */
  129. hopamp1->State = HAL_OPAMP_STATE_CALIBBUSY;
  130. hopamp2->State = HAL_OPAMP_STATE_CALIBBUSY;
  131. hopamp3->State = HAL_OPAMP_STATE_CALIBBUSY;
  132. /* Backup of switches configuration to restore it at the end of the */
  133. /* calibration. */
  134. tmp_OpaxSwitchesContextBackup = READ_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES_ALL_OPAMPS);
  135. /* Open all switches on non-inverting input, inverting input and output */
  136. /* feedback. */
  137. CLEAR_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES_ALL_OPAMPS);
  138. /* Set calibration mode to user programmed trimming values */
  139. SET_BIT(OPAMP->OTR, OPAMP_OTR_OT_USER);
  140. /* Select trimming settings depending on power mode */
  141. if (hopamp1->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
  142. {
  143. tmp_opamp1_otr_otuser = OPAMP_OTR_OT_USER;
  144. tmp_opamp1_reg_trimming = &OPAMP->OTR;
  145. }
  146. else
  147. {
  148. tmp_opamp1_otr_otuser = 0x00000000;
  149. tmp_opamp1_reg_trimming = &OPAMP->LPOTR;
  150. }
  151. if (hopamp2->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
  152. {
  153. tmp_opamp2_otr_otuser = OPAMP_OTR_OT_USER;
  154. tmp_opamp2_reg_trimming = &OPAMP->OTR;
  155. }
  156. else
  157. {
  158. tmp_opamp2_otr_otuser = 0x00000000;
  159. tmp_opamp2_reg_trimming = &OPAMP->LPOTR;
  160. }
  161. if (hopamp3->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
  162. {
  163. tmp_opamp3_otr_otuser = OPAMP_OTR_OT_USER;
  164. tmp_opamp3_reg_trimming = &OPAMP->OTR;
  165. }
  166. else
  167. {
  168. tmp_opamp3_otr_otuser = 0x00000000;
  169. tmp_opamp3_reg_trimming = &OPAMP->LPOTR;
  170. }
  171. /* Enable the selected opamp */
  172. CLEAR_BIT (OPAMP->CSR, OPAMP_CSR_OPAXPD_ALL);
  173. /* Perform trimming for both differential transistors pair high and low */
  174. for (trimming_diff_pair_iteration_count = 0U; trimming_diff_pair_iteration_count <= 1U; trimming_diff_pair_iteration_count++)
  175. {
  176. if (trimming_diff_pair_iteration_count == 0U)
  177. {
  178. /* Calibration of transistors differential pair high (NMOS) */
  179. trimming_diff_pair = OPAMP_FACTORYTRIMMING_N;
  180. opamp1_trimmingvalue = &opamp1_trimmingvaluen;
  181. opamp2_trimmingvalue = &opamp2_trimmingvaluen;
  182. opamp3_trimmingvalue = &opamp3_trimmingvaluen;
  183. /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value */
  184. /* is 00000b. Used to detect the bit toggling during trimming. */
  185. tmp_Opa1calout_DefaultSate = RESET;
  186. tmp_Opa2calout_DefaultSate = RESET;
  187. tmp_Opa3calout_DefaultSate = RESET;
  188. /* Enable calibration for N differential pair */
  189. MODIFY_REG(OPAMP->CSR, OPAMP_CSR_OPAXCAL_L_ALL,
  190. OPAMP_CSR_OPAXCAL_H_ALL);
  191. }
  192. else /* (trimming_diff_pair_iteration_count == 1) */
  193. {
  194. /* Calibration of transistors differential pair low (PMOS) */
  195. trimming_diff_pair = OPAMP_FACTORYTRIMMING_P;
  196. opamp1_trimmingvalue = &opamp1_trimmingvaluep;
  197. opamp2_trimmingvalue = &opamp2_trimmingvaluep;
  198. opamp3_trimmingvalue = &opamp3_trimmingvaluep;
  199. /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value */
  200. /* is 00000b. Used to detect the bit toggling during trimming. */
  201. tmp_Opa1calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp1);
  202. tmp_Opa2calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp2);
  203. tmp_Opa3calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp3);
  204. /* Enable calibration for P differential pair */
  205. MODIFY_REG(OPAMP->CSR, OPAMP_CSR_OPAXCAL_H_ALL,
  206. OPAMP_CSR_OPAXCAL_L_ALL);
  207. }
  208. /* Perform calibration parameter search by dichotomy sweep */
  209. /* - Delta initial value 16: for 5 dichotomy steps: 16 for the */
  210. /* initial range, then successive delta sweeps (8, 4, 2, 1). */
  211. /* can extend the search range to +/- 15 units. */
  212. /* - Trimming initial value 15: search range will go from 0 to 30 */
  213. /* (Trimming value 31 is forbidden). */
  214. /* Note: After dichotomy sweep, the trimming result is determined. */
  215. /* However, the final trimming step is deduced from previous */
  216. /* trimming steps tested but is not effectively tested. */
  217. /* An additional test step (using variable "final_step_check") */
  218. /* allow to Test the final trimming step. */
  219. *opamp1_trimmingvalue = 15U;
  220. *opamp2_trimmingvalue = 15U;
  221. *opamp3_trimmingvalue = 15U;
  222. delta = 16U;
  223. while ((delta != 0U) || (final_step_check == 1U))
  224. {
  225. /* Set candidate trimming */
  226. MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  227. OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, *opamp1_trimmingvalue) | tmp_opamp1_otr_otuser);
  228. MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  229. OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, *opamp2_trimmingvalue) | tmp_opamp2_otr_otuser);
  230. MODIFY_REG(*tmp_opamp3_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  231. OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, *opamp3_trimmingvalue) | tmp_opamp3_otr_otuser);
  232. /* Offset trimming time: during calibration, minimum time needed */
  233. /* between two steps to have 1 mV accuracy. */
  234. HAL_Delay(OPAMP_TRIMMING_DELAY);
  235. /* Set flag for additional check of last trimming step equal to */
  236. /* dichotomy step before its division by 2 (equivalent to previous */
  237. /* value of dichotomy step). */
  238. final_step_check = delta;
  239. /* Divide range by 2 to continue dichotomy sweep */
  240. delta >>= 1U;
  241. /* Set trimming values for next iteration in function of trimming */
  242. /* result toggle (versus initial state). */
  243. /* Trimming values update with dichotomy delta of previous */
  244. /* iteration. */
  245. /* Note: on the last trimming loop, delta is equal to 0 and */
  246. /* therefore has no effect. */
  247. if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp1)) != tmp_Opa1calout_DefaultSate)
  248. {
  249. /* If calibration output is has toggled, try lower trimming */
  250. *opamp1_trimmingvalue -= delta;
  251. }
  252. else
  253. {
  254. /* If calibration output is has not toggled, try higher trimming */
  255. *opamp1_trimmingvalue += delta;
  256. }
  257. if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp2)) != tmp_Opa2calout_DefaultSate)
  258. {
  259. /* If calibration output is has toggled, try lower trimming */
  260. *opamp2_trimmingvalue -= delta;
  261. }
  262. else
  263. {
  264. /* If calibration output is has not toggled, try higher trimming */
  265. *opamp2_trimmingvalue += delta;
  266. }
  267. if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp3)) != tmp_Opa3calout_DefaultSate)
  268. {
  269. /* If calibration output is has toggled, try lower trimming */
  270. *opamp3_trimmingvalue -= delta;
  271. }
  272. else
  273. {
  274. /* If calibration output is has not toggled, try higher trimming */
  275. *opamp3_trimmingvalue += delta;
  276. }
  277. }
  278. /* Check trimming result of the selected step and perform final fine */
  279. /* trimming. */
  280. /* - If calibration output is has toggled: the current step is */
  281. /* already optimized. */
  282. /* - If calibration output is has not toggled: the current step can */
  283. /* be optimized by incrementing it of one step. */
  284. if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp1)) == tmp_Opa1calout_DefaultSate)
  285. {
  286. *opamp1_trimmingvalue += 1U;
  287. /* Set final fine trimming */
  288. MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  289. OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, *opamp1_trimmingvalue) | tmp_opamp1_otr_otuser);
  290. }
  291. if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp2)) == tmp_Opa2calout_DefaultSate)
  292. {
  293. *opamp2_trimmingvalue += 1U;
  294. /* Set final fine trimming */
  295. MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  296. OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, *opamp2_trimmingvalue) | tmp_opamp2_otr_otuser);
  297. }
  298. if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp3)) == tmp_Opa3calout_DefaultSate)
  299. {
  300. *opamp3_trimmingvalue += 1U;
  301. /* Set final fine trimming */
  302. MODIFY_REG(*tmp_opamp3_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  303. OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, *opamp3_trimmingvalue) | tmp_opamp3_otr_otuser);
  304. }
  305. }
  306. /* Disable calibration for P and N differential pairs */
  307. /* Disable the selected opamp */
  308. CLEAR_BIT (OPAMP->CSR, (OPAMP_CSR_OPAXCAL_H_ALL |
  309. OPAMP_CSR_OPAXCAL_L_ALL |
  310. OPAMP_CSR_OPAXPD_ALL ));
  311. /* Backup of switches configuration to restore it at the end of the */
  312. /* calibration. */
  313. SET_BIT(OPAMP->CSR, tmp_OpaxSwitchesContextBackup);
  314. /* Self calibration is successful */
  315. /* Store calibration (user trimming) results in init structure. */
  316. /* Set user trimming mode */
  317. hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER;
  318. hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER;
  319. hopamp3->Init.UserTrimming = OPAMP_TRIMMING_USER;
  320. /* Affect calibration parameters depending on mode normal/low power */
  321. if (hopamp1->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
  322. {
  323. /* Write calibration result N */
  324. hopamp1->Init.TrimmingValueN = opamp1_trimmingvaluen;
  325. /* Write calibration result P */
  326. hopamp1->Init.TrimmingValueP = opamp1_trimmingvaluep;
  327. }
  328. else
  329. {
  330. /* Write calibration result N */
  331. hopamp1->Init.TrimmingValueNLowPower = opamp1_trimmingvaluen;
  332. /* Write calibration result P */
  333. hopamp1->Init.TrimmingValuePLowPower = opamp1_trimmingvaluep;
  334. }
  335. if (hopamp2->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
  336. {
  337. /* Write calibration result N */
  338. hopamp2->Init.TrimmingValueN = opamp2_trimmingvaluen;
  339. /* Write calibration result P */
  340. hopamp2->Init.TrimmingValueP = opamp2_trimmingvaluep;
  341. }
  342. else
  343. {
  344. /* Write calibration result N */
  345. hopamp2->Init.TrimmingValueNLowPower = opamp2_trimmingvaluen;
  346. /* Write calibration result P */
  347. hopamp2->Init.TrimmingValuePLowPower = opamp2_trimmingvaluep;
  348. }
  349. if (hopamp3->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
  350. {
  351. /* Write calibration result N */
  352. hopamp3->Init.TrimmingValueN = opamp3_trimmingvaluen;
  353. /* Write calibration result P */
  354. hopamp3->Init.TrimmingValueP = opamp3_trimmingvaluep;
  355. }
  356. else
  357. {
  358. /* Write calibration result N */
  359. hopamp3->Init.TrimmingValueNLowPower = opamp3_trimmingvaluen;
  360. /* Write calibration result P */
  361. hopamp3->Init.TrimmingValuePLowPower = opamp3_trimmingvaluep;
  362. }
  363. /* Update OPAMP state */
  364. hopamp1->State = HAL_OPAMP_STATE_READY;
  365. hopamp2->State = HAL_OPAMP_STATE_READY;
  366. hopamp3->State = HAL_OPAMP_STATE_READY;
  367. }
  368. return status;
  369. }
  370. #else
  371. /* 2 OPAMPS available */
  372. /* 2 OPAMPS can be calibrated in parallel */
  373. /**
  374. * @brief Run the self calibration of the 2 OPAMPs in parallel.
  375. * @note Trimming values (PMOS & NMOS) are updated and user trimming is
  376. * enabled is calibration is succesful.
  377. * @note Calibration is performed in the mode specified in OPAMP init
  378. * structure (mode normal or low-power). To perform calibration for
  379. * both modes, repeat this function twice after OPAMP init structure
  380. * accordingly updated.
  381. * @note Calibration runs about 10 ms (5 dichotmy steps, repeated for P
  382. * and N transistors: 10 steps with 1 ms for each step).
  383. * @param hopamp1 handle
  384. * @param hopamp2 handle
  385. * @retval HAL status
  386. */
  387. HAL_StatusTypeDef HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef *hopamp1, OPAMP_HandleTypeDef *hopamp2)
  388. {
  389. HAL_StatusTypeDef status = HAL_OK;
  390. uint32_t* opamp1_trimmingvalue;
  391. uint32_t opamp1_trimmingvaluen = 0;
  392. uint32_t opamp1_trimmingvaluep = 0;
  393. uint32_t* opamp2_trimmingvalue;
  394. uint32_t opamp2_trimmingvaluen = 0;
  395. uint32_t opamp2_trimmingvaluep = 0;
  396. uint32_t trimming_diff_pair; /* Selection of differential transistors pair high or low */
  397. __IO uint32_t* tmp_opamp1_reg_trimming; /* Selection of register of trimming depending on power mode: OTR or LPOTR */
  398. __IO uint32_t* tmp_opamp2_reg_trimming;
  399. uint32_t tmp_opamp1_otr_otuser; /* Selection of bit OPAMP_OTR_OT_USER depending on trimming register pointed: OTR or LPOTR */
  400. uint32_t tmp_opamp2_otr_otuser;
  401. uint32_t tmp_Opa1calout_DefaultSate; /* Bit OPAMP_CSR_OPA1CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
  402. uint32_t tmp_Opa2calout_DefaultSate; /* Bit OPAMP_CSR_OPA2CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
  403. uint32_t tmp_OpaxSwitchesContextBackup;
  404. uint8_t trimming_diff_pair_iteration_count; /* For calibration loop algorithm: to repeat the calibration loop for both differential transistors pair high and low */
  405. uint8_t delta; /* For calibration loop algorithm: Variable for dichotomy steps value */
  406. uint8_t final_step_check = 0x0U; /* For calibration loop algorithm: Flag for additional check of last trimming step */
  407. if((hopamp1 == NULL) || (hopamp2 == NULL))
  408. {
  409. status = HAL_ERROR;
  410. }
  411. /* Check if OPAMP in calibration mode and calibration not yet enable */
  412. else if(hopamp1->State != HAL_OPAMP_STATE_READY)
  413. {
  414. status = HAL_ERROR;
  415. }
  416. else if(hopamp2->State != HAL_OPAMP_STATE_READY)
  417. {
  418. status = HAL_ERROR;
  419. }
  420. else
  421. {
  422. /* Check the parameter */
  423. assert_param(IS_OPAMP_ALL_INSTANCE(hopamp1->Instance));
  424. assert_param(IS_OPAMP_ALL_INSTANCE(hopamp2->Instance));
  425. assert_param(IS_OPAMP_POWERMODE(hopamp1->Init.PowerMode));
  426. assert_param(IS_OPAMP_POWERMODE(hopamp2->Init.PowerMode));
  427. /* Update OPAMP state */
  428. hopamp1->State = HAL_OPAMP_STATE_CALIBBUSY;
  429. hopamp2->State = HAL_OPAMP_STATE_CALIBBUSY;
  430. /* Backup of switches configuration to restore it at the end of the */
  431. /* calibration. */
  432. tmp_OpaxSwitchesContextBackup = READ_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES_ALL_OPAMPS);
  433. /* Open all switches on non-inverting input, inverting input and output */
  434. /* feedback. */
  435. CLEAR_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES_ALL_OPAMPS);
  436. /* Set calibration mode to user programmed trimming values */
  437. SET_BIT(OPAMP->OTR, OPAMP_OTR_OT_USER);
  438. /* Select trimming settings depending on power mode */
  439. if (hopamp1->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
  440. {
  441. tmp_opamp1_otr_otuser = OPAMP_OTR_OT_USER;
  442. tmp_opamp1_reg_trimming = &OPAMP->OTR;
  443. }
  444. else
  445. {
  446. tmp_opamp1_otr_otuser = 0x00000000U;
  447. tmp_opamp1_reg_trimming = &OPAMP->LPOTR;
  448. }
  449. if (hopamp2->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
  450. {
  451. tmp_opamp2_otr_otuser = OPAMP_OTR_OT_USER;
  452. tmp_opamp2_reg_trimming = &OPAMP->OTR;
  453. }
  454. else
  455. {
  456. tmp_opamp2_otr_otuser = 0x00000000U;
  457. tmp_opamp2_reg_trimming = &OPAMP->LPOTR;
  458. }
  459. /* Enable the selected opamp */
  460. CLEAR_BIT (OPAMP->CSR, OPAMP_CSR_OPAXPD_ALL);
  461. /* Perform trimming for both differential transistors pair high and low */
  462. for (trimming_diff_pair_iteration_count = 0U; trimming_diff_pair_iteration_count <= 1U; trimming_diff_pair_iteration_count++)
  463. {
  464. if (trimming_diff_pair_iteration_count == 0U)
  465. {
  466. /* Calibration of transistors differential pair high (NMOS) */
  467. trimming_diff_pair = OPAMP_FACTORYTRIMMING_N;
  468. opamp1_trimmingvalue = &opamp1_trimmingvaluen;
  469. opamp2_trimmingvalue = &opamp2_trimmingvaluen;
  470. /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value */
  471. /* is 00000b. Used to detect the bit toggling during trimming. */
  472. tmp_Opa1calout_DefaultSate = 0U;
  473. tmp_Opa2calout_DefaultSate = 0U;
  474. /* Enable calibration for N differential pair */
  475. MODIFY_REG(OPAMP->CSR, OPAMP_CSR_OPAXCAL_L_ALL,
  476. OPAMP_CSR_OPAXCAL_H_ALL);
  477. }
  478. else /* (trimming_diff_pair_iteration_count == 1) */
  479. {
  480. /* Calibration of transistors differential pair low (PMOS) */
  481. trimming_diff_pair = OPAMP_FACTORYTRIMMING_P;
  482. opamp1_trimmingvalue = &opamp1_trimmingvaluep;
  483. opamp2_trimmingvalue = &opamp2_trimmingvaluep;
  484. /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value */
  485. /* is 00000b. Used to detect the bit toggling during trimming. */
  486. tmp_Opa1calout_DefaultSate = (uint32_t) OPAMP_CSR_OPAXCALOUT(hopamp1);
  487. tmp_Opa2calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp2);
  488. /* Enable calibration for P differential pair */
  489. MODIFY_REG(OPAMP->CSR, OPAMP_CSR_OPAXCAL_H_ALL,
  490. OPAMP_CSR_OPAXCAL_L_ALL);
  491. }
  492. /* Perform calibration parameter search by dichotomy sweep */
  493. /* - Delta initial value 16: for 5 dichotomy steps: 16 for the */
  494. /* initial range, then successive delta sweeps (8, 4, 2, 1). */
  495. /* can extend the search range to +/- 15 units. */
  496. /* - Trimming initial value 15: search range will go from 0 to 30 */
  497. /* (Trimming value 31 is forbidden). */
  498. /* Note: After dichotomy sweep, the trimming result is determined. */
  499. /* However, the final trimming step is deduced from previous */
  500. /* trimming steps tested but is not effectively tested. */
  501. /* An additional test step (using variable "final_step_check") */
  502. /* allow to Test the final trimming step. */
  503. *opamp1_trimmingvalue = 15U;
  504. *opamp2_trimmingvalue = 15U;
  505. delta = 16U;
  506. while ((delta != 0U) || (final_step_check == 1U))
  507. {
  508. /* Set candidate trimming */
  509. MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  510. OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, *opamp1_trimmingvalue) | tmp_opamp1_otr_otuser);
  511. MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  512. OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, *opamp2_trimmingvalue) | tmp_opamp2_otr_otuser);
  513. /* Offset trimming time: during calibration, minimum time needed */
  514. /* between two steps to have 1 mV accuracy. */
  515. HAL_Delay(OPAMP_TRIMMING_DELAY);
  516. /* Set flag for additional check of last trimming step equal to */
  517. /* dichotomy step before its division by 2 (equivalent to previous */
  518. /* value of dichotomy step). */
  519. final_step_check = delta;
  520. /* Divide range by 2 to continue dichotomy sweep */
  521. delta >>= 1U;
  522. /* Set trimming values for next iteration in function of trimming */
  523. /* result toggle (versus initial state). */
  524. /* Trimming values update with dichotomy delta of previous */
  525. /* iteration. */
  526. /* Note: on the last trimming loop, delta is equal to 0 and */
  527. /* therefore has no effect. */
  528. if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp1)) != tmp_Opa1calout_DefaultSate)
  529. {
  530. /* If calibration output is has toggled, try lower trimming */
  531. *opamp1_trimmingvalue -= delta;
  532. }
  533. else
  534. {
  535. /* If calibration output is has not toggled, try higher trimming */
  536. *opamp1_trimmingvalue += delta;
  537. }
  538. if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp2)) != tmp_Opa2calout_DefaultSate)
  539. {
  540. /* If calibration output is has toggled, try lower trimming */
  541. *opamp2_trimmingvalue -= delta;
  542. }
  543. else
  544. {
  545. /* If calibration output is has not toggled, try higher trimming */
  546. *opamp2_trimmingvalue += delta;
  547. }
  548. }
  549. /* Check trimming result of the selected step and perform final fine */
  550. /* trimming. */
  551. /* - If calibration output is has toggled: the current step is */
  552. /* already optimized. */
  553. /* - If calibration output is has not toggled: the current step can */
  554. /* be optimized by incrementing it of one step. */
  555. if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp1)) == tmp_Opa1calout_DefaultSate)
  556. {
  557. *opamp1_trimmingvalue += 1U;
  558. /* Set final fine trimming */
  559. MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  560. OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, *opamp1_trimmingvalue) | tmp_opamp1_otr_otuser);
  561. }
  562. if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp2)) == tmp_Opa2calout_DefaultSate)
  563. {
  564. *opamp2_trimmingvalue += 1U;
  565. /* Set final fine trimming */
  566. MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  567. OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, *opamp2_trimmingvalue) | tmp_opamp2_otr_otuser);
  568. }
  569. }
  570. /* Disable calibration for P and N differential pairs */
  571. /* Disable the selected opamp */
  572. CLEAR_BIT (OPAMP->CSR, (OPAMP_CSR_OPAXCAL_H_ALL |
  573. OPAMP_CSR_OPAXCAL_L_ALL |
  574. OPAMP_CSR_OPAXPD_ALL ));
  575. /* Backup of switches configuration to restore it at the end of the */
  576. /* calibration. */
  577. SET_BIT(OPAMP->CSR, tmp_OpaxSwitchesContextBackup);
  578. /* Self calibration is successful */
  579. /* Store calibration (user trimming) results in init structure. */
  580. /* Set user trimming mode */
  581. hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER;
  582. hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER;
  583. /* Affect calibration parameters depending on mode normal/low power */
  584. if (hopamp1->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
  585. {
  586. /* Write calibration result N */
  587. hopamp1->Init.TrimmingValueN = opamp1_trimmingvaluen;
  588. /* Write calibration result P */
  589. hopamp1->Init.TrimmingValueP = opamp1_trimmingvaluep;
  590. }
  591. else
  592. {
  593. /* Write calibration result N */
  594. hopamp1->Init.TrimmingValueNLowPower = opamp1_trimmingvaluen;
  595. /* Write calibration result P */
  596. hopamp1->Init.TrimmingValuePLowPower = opamp1_trimmingvaluep;
  597. }
  598. if (hopamp2->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
  599. {
  600. /* Write calibration result N */
  601. hopamp2->Init.TrimmingValueN = opamp2_trimmingvaluen;
  602. /* Write calibration result P */
  603. hopamp2->Init.TrimmingValueP = opamp2_trimmingvaluep;
  604. }
  605. else
  606. {
  607. /* Write calibration result N */
  608. hopamp2->Init.TrimmingValueNLowPower = opamp2_trimmingvaluen;
  609. /* Write calibration result P */
  610. hopamp2->Init.TrimmingValuePLowPower = opamp2_trimmingvaluep;
  611. }
  612. /* Update OPAMP state */
  613. hopamp1->State = HAL_OPAMP_STATE_READY;
  614. hopamp2->State = HAL_OPAMP_STATE_READY;
  615. }
  616. return status;
  617. }
  618. #endif /* STM32L151xD || STM32L152xD || STM32L162xD */
  619. /**
  620. * @}
  621. */
  622. /** @defgroup OPAMPEx_Exported_Functions_Group2 Extended Peripheral Control functions
  623. * @brief Extended peripheral control functions
  624. *
  625. @verbatim
  626. ===============================================================================
  627. ##### Peripheral Control functions #####
  628. ===============================================================================
  629. [..]
  630. (+) OPAMP unlock.
  631. @endverbatim
  632. * @{
  633. */
  634. /**
  635. * @brief Unlock the selected OPAMP configuration.
  636. * This function must be called only when OPAMP is in state "locked".
  637. * @param hopamp OPAMP handle
  638. * @retval HAL status
  639. */
  640. HAL_StatusTypeDef HAL_OPAMPEx_Unlock(OPAMP_HandleTypeDef* hopamp)
  641. {
  642. HAL_StatusTypeDef status = HAL_OK;
  643. /* Check the OPAMP handle allocation */
  644. /* Check if OPAMP locked */
  645. if(hopamp == NULL)
  646. {
  647. status = HAL_ERROR;
  648. }
  649. /* Check the OPAMP handle allocation */
  650. /* Check if OPAMP locked */
  651. else if(hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
  652. {
  653. /* Check the parameter */
  654. assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
  655. /* OPAMP state changed to locked */
  656. hopamp->State = HAL_OPAMP_STATE_BUSY;
  657. }
  658. else
  659. {
  660. status = HAL_ERROR;
  661. }
  662. return status;
  663. }
  664. /**
  665. * @}
  666. */
  667. /**
  668. * @}
  669. */
  670. #endif /* STM32L151xCA || STM32L151xD || STM32L152xCA || STM32L152xD || STM32L162xCA || STM32L162xD || STM32L151xE || STM32L151xDX || STM32L152xE || STM32L152xDX || STM32L162xE || STM32L162xDX || STM32L162xC || STM32L152xC || STM32L151xC */
  671. #endif /* HAL_OPAMP_MODULE_ENABLED */
  672. /**
  673. * @}
  674. */
  675. /**
  676. * @}
  677. */
  678. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/