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.
 
 
 

451 lines
16 KiB

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