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.
 
 
 

457 lines
16 KiB

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