stm32l1xx_hal_opamp_ex.c 30 KB

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