stm32l1xx_hal_opamp_ex.c 36 KB

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