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.
 
 
 

436 lines
14 KiB

  1. /**
  2. ******************************************************************************
  3. * @file stm32h7xx_hal_opamp_ex.c
  4. * @author MCD Application Team
  5. * @brief Extended OPAMP HAL module driver.
  6. * This file provides firmware functions to manage the following
  7. * functionalities of the operational amplifier(s)(OPAMP1, OPAMP2 etc)
  8. * peripheral:
  9. * + Extended Initialization and de-initialization functions
  10. * + Extended Peripheral Control functions
  11. *
  12. @verbatim
  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 "stm32h7xx_hal.h"
  28. /** @addtogroup STM32H7xx_HAL_Driver
  29. * @{
  30. */
  31. /** @defgroup OPAMPEx OPAMPEx
  32. * @brief OPAMP Extended HAL module driver
  33. * @{
  34. */
  35. #ifdef HAL_OPAMP_MODULE_ENABLED
  36. /* Private typedef -----------------------------------------------------------*/
  37. /* Private define ------------------------------------------------------------*/
  38. /* Private macro -------------------------------------------------------------*/
  39. /* Private variables ---------------------------------------------------------*/
  40. /* Private function prototypes -----------------------------------------------*/
  41. /* Exported functions --------------------------------------------------------*/
  42. /** @defgroup OPAMPEx_Exported_Functions OPAMP Extended Exported Functions
  43. * @{
  44. */
  45. /** @defgroup OPAMPEx_Exported_Functions_Group1 Extended Input and Output operation functions
  46. * @brief Extended operation functions
  47. *
  48. @verbatim
  49. ===============================================================================
  50. ##### Extended IO operation functions #####
  51. ===============================================================================
  52. [..]
  53. (+) OPAMP Self calibration.
  54. @endverbatim
  55. * @{
  56. */
  57. /**
  58. * @brief Run the self calibration of 2 OPAMPs in parallel.
  59. * @note Trimming values (PMOS & NMOS) are updated and user trimming is
  60. * enabled is calibration is successful.
  61. * @note Calibration is performed in the mode specified in OPAMP init
  62. * structure (mode normal or low power). To perform calibration for
  63. * both modes, repeat this function twice after OPAMP init structure
  64. * accordingly updated.
  65. * @param hopamp1 handle
  66. * @param hopamp2 handle
  67. * @retval HAL status
  68. */
  69. HAL_StatusTypeDef HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef *hopamp1, OPAMP_HandleTypeDef *hopamp2)
  70. {
  71. HAL_StatusTypeDef status = HAL_OK;
  72. uint32_t trimmingvaluen1;
  73. uint32_t trimmingvaluep1;
  74. uint32_t trimmingvaluen2;
  75. uint32_t trimmingvaluep2;
  76. /* Selection of register of trimming depending on power mode: OTR or HSOTR */
  77. __IO uint32_t* tmp_opamp1_reg_trimming;
  78. __IO uint32_t* tmp_opamp2_reg_trimming;
  79. uint32_t delta;
  80. uint32_t opampmode1;
  81. uint32_t opampmode2;
  82. if((hopamp1 == NULL) || (hopamp2 == NULL))
  83. {
  84. status = HAL_ERROR;
  85. }
  86. /* Check if OPAMP in calibration mode and calibration not yet enable */
  87. else if(hopamp1->State != HAL_OPAMP_STATE_READY)
  88. {
  89. status = HAL_ERROR;
  90. }
  91. else if(hopamp2->State != HAL_OPAMP_STATE_READY)
  92. {
  93. status = HAL_ERROR;
  94. }
  95. else
  96. {
  97. /* Check the parameter */
  98. assert_param(IS_OPAMP_ALL_INSTANCE(hopamp1->Instance));
  99. assert_param(IS_OPAMP_ALL_INSTANCE(hopamp2->Instance));
  100. assert_param(IS_OPAMP_POWERMODE(hopamp1->Init.PowerMode));
  101. assert_param(IS_OPAMP_POWERMODE(hopamp2->Init.PowerMode));
  102. /* Set Calibration mode */
  103. /* Non-inverting input connected to calibration reference voltage. */
  104. SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_FORCEVP);
  105. SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_FORCEVP);
  106. /* Save OPAMP mode */
  107. opampmode1 = READ_BIT(hopamp1->Instance->CSR,OPAMP_CSR_VMSEL);
  108. opampmode2 = READ_BIT(hopamp2->Instance->CSR,OPAMP_CSR_VMSEL);
  109. /* Use of standalone mode */
  110. MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_VMSEL, OPAMP_STANDALONE_MODE);
  111. MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_VMSEL, OPAMP_STANDALONE_MODE);
  112. /* user trimming values are used for offset calibration */
  113. SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_USERTRIM);
  114. SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_USERTRIM);
  115. /* Select trimming settings depending on power mode */
  116. if (hopamp1->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
  117. {
  118. tmp_opamp1_reg_trimming = &OPAMP1->OTR;
  119. }
  120. else
  121. {
  122. tmp_opamp1_reg_trimming = &OPAMP1->HSOTR;
  123. }
  124. if (hopamp2->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
  125. {
  126. tmp_opamp2_reg_trimming = &OPAMP2->OTR;
  127. }
  128. else
  129. {
  130. tmp_opamp2_reg_trimming = &OPAMP2->HSOTR;
  131. }
  132. /* Enable calibration */
  133. SET_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALON);
  134. SET_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALON);
  135. /* 1st calibration - N */
  136. /* Select 90U% VREF */
  137. MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_90VDDA);
  138. MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_90VDDA);
  139. /* Enable the selected opamp */
  140. SET_BIT (hopamp1->Instance->CSR, OPAMP_CSR_OPAMPxEN);
  141. SET_BIT (hopamp2->Instance->CSR, OPAMP_CSR_OPAMPxEN);
  142. /* Init trimming counter */
  143. /* Medium value */
  144. trimmingvaluen1 = 16U;
  145. trimmingvaluen2 = 16U;
  146. delta = 8U;
  147. while (delta != 0U)
  148. {
  149. /* Set candidate trimming */
  150. /* OPAMP_POWERMODE_NORMAL */
  151. MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1);
  152. MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2);
  153. /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
  154. /* Offset trim time: during calibration, minimum time needed between */
  155. /* two steps to have 1 mV accuracy */
  156. HAL_Delay(OPAMP_TRIMMING_DELAY);
  157. if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U)
  158. {
  159. /* OPAMP_CSR_CALOUT is Low try higher trimming */
  160. trimmingvaluen1 += delta;
  161. }
  162. else
  163. {
  164. /* OPAMP_CSR_CALOUT is High try lower trimming */
  165. trimmingvaluen1 -= delta;
  166. }
  167. if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U)
  168. {
  169. /* OPAMP_CSR_CALOUT is Low try higher trimming */
  170. trimmingvaluen2 += delta;
  171. }
  172. else
  173. {
  174. /* OPAMP_CSR_CALOUT is High try lower trimming */
  175. trimmingvaluen2 -= delta;
  176. }
  177. /* Divide range by 2 to continue dichotomy sweep */
  178. delta >>= 1U;
  179. }
  180. /* Still need to check if right calibration is current value or one step below */
  181. /* Indeed the first value that causes the OUTCAL bit to change from 0 to 1 */
  182. /* Set candidate trimming */
  183. MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1);
  184. MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2);
  185. /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
  186. /* Offset trim time: during calibration, minimum time needed between */
  187. /* two steps to have 1 mV accuracy */
  188. HAL_Delay(OPAMP_TRIMMING_DELAY);
  189. if ((READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT)) != 0U)
  190. {
  191. /* Trimming value is actually one value more */
  192. trimmingvaluen1++;
  193. MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1);
  194. }
  195. if ((READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT)) != 0U)
  196. {
  197. /* Trimming value is actually one value more */
  198. trimmingvaluen2++;
  199. MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2);
  200. }
  201. /* 2nd calibration - P */
  202. /* Select 10U% VREF */
  203. MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_10VDDA);
  204. MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_10VDDA);
  205. /* Init trimming counter */
  206. /* Medium value */
  207. trimmingvaluep1 = 16U;
  208. trimmingvaluep2 = 16U;
  209. delta = 8U;
  210. while (delta != 0U)
  211. {
  212. /* Set candidate trimming */
  213. /* OPAMP_POWERMODE_NORMAL */
  214. MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING));
  215. MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING));
  216. /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
  217. /* Offset trim time: during calibration, minimum time needed between */
  218. /* two steps to have 1 mV accuracy */
  219. HAL_Delay(OPAMP_TRIMMING_DELAY);
  220. if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U)
  221. {
  222. /* OPAMP_CSR_CALOUT is Low try higher trimming */
  223. trimmingvaluep1 += delta;
  224. }
  225. else
  226. {
  227. /* OPAMP_CSR_CALOUT is HIGH try lower trimming */
  228. trimmingvaluep1 -= delta;
  229. }
  230. if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U)
  231. {
  232. /* OPAMP_CSR_CALOUT is Low try higher trimming */
  233. trimmingvaluep2 += delta;
  234. }
  235. else
  236. {
  237. /* OPAMP_CSR_CALOUT is High try lower trimming */
  238. trimmingvaluep2 -= delta;
  239. }
  240. /* Divide range by 2 to continue dichotomy sweep */
  241. delta >>= 1U;
  242. }
  243. /* Still need to check if right calibration is current value or one step below */
  244. /* Indeed the first value that causes the OUTCAL bit to change from 1 to 0 */
  245. /* Set candidate trimming */
  246. MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING));
  247. MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING));
  248. /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
  249. /* Offset trim time: during calibration, minimum time needed between */
  250. /* two steps to have 1 mV accuracy */
  251. HAL_Delay(OPAMP_TRIMMING_DELAY);
  252. if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U)
  253. {
  254. /* Trimming value is actually one value more */
  255. trimmingvaluep1++;
  256. MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING));
  257. }
  258. if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U)
  259. {
  260. /* Trimming value is actually one value more */
  261. trimmingvaluep2++;
  262. MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING));
  263. }
  264. /* Disable calibration & set normal mode (operating mode) */
  265. CLEAR_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALON);
  266. CLEAR_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALON);
  267. /* Disable the OPAMPs */
  268. CLEAR_BIT (hopamp1->Instance->CSR, OPAMP_CSR_OPAMPxEN);
  269. CLEAR_BIT (hopamp2->Instance->CSR, OPAMP_CSR_OPAMPxEN);
  270. /* Self calibration is successful */
  271. /* Store calibration (user trimming) results in init structure. */
  272. /* Set user trimming mode */
  273. hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER;
  274. hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER;
  275. /* Affect calibration parameters depending on mode normal/high speed */
  276. if (hopamp1->Init.PowerMode != OPAMP_POWERMODE_HIGHSPEED)
  277. {
  278. /* Write calibration result N */
  279. hopamp1->Init.TrimmingValueN = trimmingvaluen1;
  280. /* Write calibration result P */
  281. hopamp1->Init.TrimmingValueP = trimmingvaluep1;
  282. }
  283. else
  284. {
  285. /* Write calibration result N */
  286. hopamp1->Init.TrimmingValueNHighSpeed = trimmingvaluen1;
  287. /* Write calibration result P */
  288. hopamp1->Init.TrimmingValuePHighSpeed = trimmingvaluep1;
  289. }
  290. if (hopamp2->Init.PowerMode != OPAMP_POWERMODE_HIGHSPEED)
  291. {
  292. /* Write calibration result N */
  293. hopamp2->Init.TrimmingValueN = trimmingvaluen2;
  294. /* Write calibration result P */
  295. hopamp2->Init.TrimmingValueP = trimmingvaluep2;
  296. }
  297. else
  298. {
  299. /* Write calibration result N */
  300. hopamp2->Init.TrimmingValueNHighSpeed = trimmingvaluen2;
  301. /* Write calibration result P */
  302. hopamp2->Init.TrimmingValuePHighSpeed = trimmingvaluep2;
  303. }
  304. /* Update OPAMP state */
  305. hopamp1->State = HAL_OPAMP_STATE_READY;
  306. hopamp2->State = HAL_OPAMP_STATE_READY;
  307. /* Restore OPAMP mode after calibration */
  308. MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_VMSEL, opampmode1);
  309. MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_VMSEL, opampmode2);
  310. }
  311. return status;
  312. }
  313. /**
  314. * @}
  315. */
  316. /** @defgroup OPAMPEx_Exported_Functions_Group2 Peripheral Control functions
  317. * @brief Peripheral Control functions
  318. *
  319. @verbatim
  320. ===============================================================================
  321. ##### Peripheral Control functions #####
  322. ===============================================================================
  323. [..]
  324. (+) OPAMP unlock.
  325. @endverbatim
  326. * @{
  327. */
  328. /**
  329. * @brief Unlock the selected OPAMP configuration.
  330. * @note This function must be called only when OPAMP is in state "locked".
  331. * @param hopamp: OPAMP handle
  332. * @retval HAL status
  333. */
  334. HAL_StatusTypeDef HAL_OPAMPEx_Unlock(OPAMP_HandleTypeDef* hopamp)
  335. {
  336. HAL_StatusTypeDef status = HAL_OK;
  337. /* Check the OPAMP handle allocation */
  338. /* Check if OPAMP locked */
  339. if(hopamp == NULL)
  340. {
  341. status = HAL_ERROR;
  342. }
  343. /* Check the OPAMP handle allocation */
  344. /* Check if OPAMP locked */
  345. else if(hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
  346. {
  347. /* Check the parameter */
  348. assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
  349. /* OPAMP state changed to locked */
  350. hopamp->State = HAL_OPAMP_STATE_BUSY;
  351. }
  352. else
  353. {
  354. status = HAL_ERROR;
  355. }
  356. return status;
  357. }
  358. /**
  359. * @}
  360. */
  361. /**
  362. * @}
  363. */
  364. /**
  365. * @}
  366. */
  367. /**
  368. * @}
  369. */
  370. #endif /* HAL_OPAMP_MODULE_ENABLED */
  371. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/