STM32H735xx HAL User Manual
|
00001 /** 00002 ****************************************************************************** 00003 * @file stm32h7xx_hal_opamp_ex.c 00004 * @author MCD Application Team 00005 * @brief Extended OPAMP HAL module driver. 00006 * This file provides firmware functions to manage the following 00007 * functionalities of the operational amplifier(s) peripheral: 00008 * + Extended Initialization and de-initialization functions 00009 * + Extended Peripheral Control functions 00010 * 00011 @verbatim 00012 ****************************************************************************** 00013 * @attention 00014 * 00015 * Copyright (c) 2017 STMicroelectronics. 00016 * All rights reserved. 00017 * 00018 * This software is licensed under terms that can be found in the LICENSE file 00019 * in the root directory of this software component. 00020 * If no LICENSE file comes with this software, it is provided AS-IS. 00021 * 00022 ****************************************************************************** 00023 */ 00024 00025 /* Includes ------------------------------------------------------------------*/ 00026 #include "stm32h7xx_hal.h" 00027 00028 /** @addtogroup STM32H7xx_HAL_Driver 00029 * @{ 00030 */ 00031 00032 /** @defgroup OPAMPEx OPAMPEx 00033 * @brief OPAMP Extended HAL module driver 00034 * @{ 00035 */ 00036 00037 #ifdef HAL_OPAMP_MODULE_ENABLED 00038 00039 /* Private typedef -----------------------------------------------------------*/ 00040 /* Private define ------------------------------------------------------------*/ 00041 /* Private macro -------------------------------------------------------------*/ 00042 /* Private variables ---------------------------------------------------------*/ 00043 /* Private function prototypes -----------------------------------------------*/ 00044 /* Exported functions --------------------------------------------------------*/ 00045 00046 /** @defgroup OPAMPEx_Exported_Functions OPAMP Extended Exported Functions 00047 * @{ 00048 */ 00049 00050 /** @defgroup OPAMPEx_Exported_Functions_Group1 Extended Input and Output operation functions 00051 * @brief Extended operation functions 00052 * 00053 @verbatim 00054 =============================================================================== 00055 ##### Extended IO operation functions ##### 00056 =============================================================================== 00057 [..] 00058 (+) OPAMP Self calibration. 00059 00060 @endverbatim 00061 * @{ 00062 */ 00063 00064 /** 00065 * @brief Run the self calibration of 2 OPAMPs in parallel. 00066 * @note Trimming values (PMOS & NMOS) are updated and user trimming is 00067 * enabled is calibration is successful. 00068 * @note Calibration is performed in the mode specified in OPAMP init 00069 * structure (mode normal or low power). To perform calibration for 00070 * both modes, repeat this function twice after OPAMP init structure 00071 * accordingly updated. 00072 * @param hopamp1 handle 00073 * @param hopamp2 handle 00074 * @retval HAL status 00075 */ 00076 00077 HAL_StatusTypeDef HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef *hopamp1, OPAMP_HandleTypeDef *hopamp2) 00078 { 00079 HAL_StatusTypeDef status = HAL_OK; 00080 00081 uint32_t trimmingvaluen1; 00082 uint32_t trimmingvaluep1; 00083 uint32_t trimmingvaluen2; 00084 uint32_t trimmingvaluep2; 00085 00086 /* Selection of register of trimming depending on power mode: OTR or HSOTR */ 00087 __IO uint32_t* tmp_opamp1_reg_trimming; 00088 __IO uint32_t* tmp_opamp2_reg_trimming; 00089 00090 uint32_t delta; 00091 uint32_t opampmode1; 00092 uint32_t opampmode2; 00093 00094 if((hopamp1 == NULL) || (hopamp2 == NULL)) 00095 { 00096 status = HAL_ERROR; 00097 } 00098 /* Check if OPAMP in calibration mode and calibration not yet enable */ 00099 else if(hopamp1->State != HAL_OPAMP_STATE_READY) 00100 { 00101 status = HAL_ERROR; 00102 } 00103 else if(hopamp2->State != HAL_OPAMP_STATE_READY) 00104 { 00105 status = HAL_ERROR; 00106 } 00107 else 00108 { 00109 /* Check the parameter */ 00110 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp1->Instance)); 00111 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp2->Instance)); 00112 00113 assert_param(IS_OPAMP_POWERMODE(hopamp1->Init.PowerMode)); 00114 assert_param(IS_OPAMP_POWERMODE(hopamp2->Init.PowerMode)); 00115 00116 /* Set Calibration mode */ 00117 /* Non-inverting input connected to calibration reference voltage. */ 00118 SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_FORCEVP); 00119 SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_FORCEVP); 00120 00121 /* Save OPAMP mode */ 00122 opampmode1 = READ_BIT(hopamp1->Instance->CSR,OPAMP_CSR_VMSEL); 00123 opampmode2 = READ_BIT(hopamp2->Instance->CSR,OPAMP_CSR_VMSEL); 00124 00125 /* Use of standalone mode */ 00126 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_VMSEL, OPAMP_STANDALONE_MODE); 00127 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_VMSEL, OPAMP_STANDALONE_MODE); 00128 00129 /* user trimming values are used for offset calibration */ 00130 SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_USERTRIM); 00131 SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_USERTRIM); 00132 00133 /* Select trimming settings depending on power mode */ 00134 if (hopamp1->Init.PowerMode == OPAMP_POWERMODE_NORMAL) 00135 { 00136 tmp_opamp1_reg_trimming = &OPAMP1->OTR; 00137 } 00138 else 00139 { 00140 tmp_opamp1_reg_trimming = &OPAMP1->HSOTR; 00141 } 00142 00143 if (hopamp2->Init.PowerMode == OPAMP_POWERMODE_NORMAL) 00144 { 00145 tmp_opamp2_reg_trimming = &OPAMP2->OTR; 00146 } 00147 else 00148 { 00149 tmp_opamp2_reg_trimming = &OPAMP2->HSOTR; 00150 } 00151 00152 /* Enable calibration */ 00153 SET_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALON); 00154 SET_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALON); 00155 00156 /* 1st calibration - N */ 00157 /* Select 90U% VREF */ 00158 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_90VDDA); 00159 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_90VDDA); 00160 00161 /* Enable the selected opamp */ 00162 SET_BIT (hopamp1->Instance->CSR, OPAMP_CSR_OPAMPxEN); 00163 SET_BIT (hopamp2->Instance->CSR, OPAMP_CSR_OPAMPxEN); 00164 00165 /* Init trimming counter */ 00166 /* Medium value */ 00167 trimmingvaluen1 = 16U; 00168 trimmingvaluen2 = 16U; 00169 delta = 8U; 00170 00171 while (delta != 0U) 00172 { 00173 /* Set candidate trimming */ 00174 /* OPAMP_POWERMODE_NORMAL */ 00175 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1); 00176 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2); 00177 00178 /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */ 00179 /* Offset trim time: during calibration, minimum time needed between */ 00180 /* two steps to have 1 mV accuracy */ 00181 HAL_Delay(OPAMP_TRIMMING_DELAY); 00182 00183 if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U) 00184 { 00185 /* OPAMP_CSR_CALOUT is Low try higher trimming */ 00186 trimmingvaluen1 += delta; 00187 } 00188 else 00189 { 00190 /* OPAMP_CSR_CALOUT is High try lower trimming */ 00191 trimmingvaluen1 -= delta; 00192 } 00193 00194 if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U) 00195 { 00196 /* OPAMP_CSR_CALOUT is Low try higher trimming */ 00197 trimmingvaluen2 += delta; 00198 } 00199 else 00200 { 00201 /* OPAMP_CSR_CALOUT is High try lower trimming */ 00202 trimmingvaluen2 -= delta; 00203 } 00204 /* Divide range by 2 to continue dichotomy sweep */ 00205 delta >>= 1U; 00206 } 00207 00208 /* Still need to check if right calibration is current value or one step below */ 00209 /* Indeed the first value that causes the OUTCAL bit to change from 0 to 1 */ 00210 /* Set candidate trimming */ 00211 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1); 00212 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2); 00213 00214 /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */ 00215 /* Offset trim time: during calibration, minimum time needed between */ 00216 /* two steps to have 1 mV accuracy */ 00217 HAL_Delay(OPAMP_TRIMMING_DELAY); 00218 00219 if ((READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT)) != 0U) 00220 { 00221 /* Trimming value is actually one value more */ 00222 trimmingvaluen1++; 00223 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1); 00224 } 00225 00226 if ((READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT)) != 0U) 00227 { 00228 /* Trimming value is actually one value more */ 00229 trimmingvaluen2++; 00230 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2); 00231 } 00232 00233 /* 2nd calibration - P */ 00234 /* Select 10U% VREF */ 00235 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_10VDDA); 00236 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_10VDDA); 00237 00238 /* Init trimming counter */ 00239 /* Medium value */ 00240 trimmingvaluep1 = 16U; 00241 trimmingvaluep2 = 16U; 00242 delta = 8U; 00243 00244 while (delta != 0U) 00245 { 00246 /* Set candidate trimming */ 00247 /* OPAMP_POWERMODE_NORMAL */ 00248 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING)); 00249 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING)); 00250 00251 /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */ 00252 /* Offset trim time: during calibration, minimum time needed between */ 00253 /* two steps to have 1 mV accuracy */ 00254 HAL_Delay(OPAMP_TRIMMING_DELAY); 00255 00256 if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U) 00257 { 00258 /* OPAMP_CSR_CALOUT is Low try higher trimming */ 00259 trimmingvaluep1 += delta; 00260 } 00261 else 00262 { 00263 /* OPAMP_CSR_CALOUT is HIGH try lower trimming */ 00264 trimmingvaluep1 -= delta; 00265 } 00266 00267 if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U) 00268 { 00269 /* OPAMP_CSR_CALOUT is Low try higher trimming */ 00270 trimmingvaluep2 += delta; 00271 } 00272 else 00273 { 00274 /* OPAMP_CSR_CALOUT is High try lower trimming */ 00275 trimmingvaluep2 -= delta; 00276 } 00277 /* Divide range by 2 to continue dichotomy sweep */ 00278 delta >>= 1U; 00279 } 00280 00281 /* Still need to check if right calibration is current value or one step below */ 00282 /* Indeed the first value that causes the OUTCAL bit to change from 1 to 0 */ 00283 /* Set candidate trimming */ 00284 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING)); 00285 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING)); 00286 00287 /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */ 00288 /* Offset trim time: during calibration, minimum time needed between */ 00289 /* two steps to have 1 mV accuracy */ 00290 HAL_Delay(OPAMP_TRIMMING_DELAY); 00291 00292 if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U) 00293 { 00294 /* Trimming value is actually one value more */ 00295 trimmingvaluep1++; 00296 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING)); 00297 } 00298 00299 if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U) 00300 { 00301 /* Trimming value is actually one value more */ 00302 trimmingvaluep2++; 00303 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING)); 00304 } 00305 00306 /* Disable calibration & set normal mode (operating mode) */ 00307 CLEAR_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALON); 00308 CLEAR_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALON); 00309 00310 /* Disable the OPAMPs */ 00311 CLEAR_BIT (hopamp1->Instance->CSR, OPAMP_CSR_OPAMPxEN); 00312 CLEAR_BIT (hopamp2->Instance->CSR, OPAMP_CSR_OPAMPxEN); 00313 00314 /* Self calibration is successful */ 00315 /* Store calibration (user trimming) results in init structure. */ 00316 00317 /* Set user trimming mode */ 00318 hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER; 00319 hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER; 00320 00321 /* Affect calibration parameters depending on mode normal/high speed */ 00322 if (hopamp1->Init.PowerMode != OPAMP_POWERMODE_HIGHSPEED) 00323 { 00324 /* Write calibration result N */ 00325 hopamp1->Init.TrimmingValueN = trimmingvaluen1; 00326 /* Write calibration result P */ 00327 hopamp1->Init.TrimmingValueP = trimmingvaluep1; 00328 } 00329 else 00330 { 00331 /* Write calibration result N */ 00332 hopamp1->Init.TrimmingValueNHighSpeed = trimmingvaluen1; 00333 /* Write calibration result P */ 00334 hopamp1->Init.TrimmingValuePHighSpeed = trimmingvaluep1; 00335 } 00336 00337 if (hopamp2->Init.PowerMode != OPAMP_POWERMODE_HIGHSPEED) 00338 { 00339 /* Write calibration result N */ 00340 hopamp2->Init.TrimmingValueN = trimmingvaluen2; 00341 /* Write calibration result P */ 00342 hopamp2->Init.TrimmingValueP = trimmingvaluep2; 00343 } 00344 else 00345 { 00346 /* Write calibration result N */ 00347 hopamp2->Init.TrimmingValueNHighSpeed = trimmingvaluen2; 00348 /* Write calibration result P */ 00349 hopamp2->Init.TrimmingValuePHighSpeed = trimmingvaluep2; 00350 00351 } 00352 /* Update OPAMP state */ 00353 hopamp1->State = HAL_OPAMP_STATE_READY; 00354 hopamp2->State = HAL_OPAMP_STATE_READY; 00355 00356 /* Restore OPAMP mode after calibration */ 00357 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_VMSEL, opampmode1); 00358 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_VMSEL, opampmode2); 00359 } 00360 00361 return status; 00362 } 00363 00364 /** 00365 * @} 00366 */ 00367 00368 /** @defgroup OPAMPEx_Exported_Functions_Group2 Peripheral Control functions 00369 * @brief Peripheral Control functions 00370 * 00371 @verbatim 00372 =============================================================================== 00373 ##### Peripheral Control functions ##### 00374 =============================================================================== 00375 [..] 00376 (+) OPAMP unlock. 00377 00378 @endverbatim 00379 * @{ 00380 */ 00381 00382 /** 00383 * @brief Unlock the selected OPAMP configuration. 00384 * @note This function must be called only when OPAMP is in state "locked". 00385 * @param hopamp: OPAMP handle 00386 * @retval HAL status 00387 */ 00388 HAL_StatusTypeDef HAL_OPAMPEx_Unlock(OPAMP_HandleTypeDef* hopamp) 00389 { 00390 HAL_StatusTypeDef status = HAL_OK; 00391 00392 /* Check the OPAMP handle allocation */ 00393 /* Check if OPAMP locked */ 00394 if(hopamp == NULL) 00395 { 00396 status = HAL_ERROR; 00397 } 00398 /* Check the OPAMP handle allocation */ 00399 /* Check if OPAMP locked */ 00400 else if(hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED) 00401 { 00402 /* Check the parameter */ 00403 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance)); 00404 00405 /* OPAMP state changed to locked */ 00406 hopamp->State = HAL_OPAMP_STATE_BUSY; 00407 } 00408 else 00409 { 00410 status = HAL_ERROR; 00411 } 00412 00413 return status; 00414 } 00415 00416 /** 00417 * @} 00418 */ 00419 00420 /** 00421 * @} 00422 */ 00423 00424 /** 00425 * @} 00426 */ 00427 00428 /** 00429 * @} 00430 */ 00431 00432 #endif /* HAL_OPAMP_MODULE_ENABLED */ 00433