STM32L443xx HAL User Manual
|
00001 /** 00002 ****************************************************************************** 00003 * @file stm32l4xx_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 "stm32l4xx_hal.h" 00027 00028 /** @addtogroup STM32L4xx_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 OPAMP_Exported_Functions OPAMP Exported Functions 00047 * @{ 00048 */ 00049 00050 #if defined (STM32L471xx) || defined (STM32L475xx) || defined (STM32L476xx) || defined (STM32L485xx) || defined (STM32L486xx) || \ 00051 defined (STM32L496xx) || defined (STM32L4A6xx) || \ 00052 defined (STM32L4P5xx) || defined (STM32L4Q5xx) || \ 00053 defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx) 00054 00055 /** @addtogroup OPAMPEx_Exported_Functions_Group1 00056 * @brief Extended operation functions 00057 * 00058 @verbatim 00059 =============================================================================== 00060 ##### Extended IO operation functions ##### 00061 =============================================================================== 00062 [..] 00063 (+) OPAMP Self calibration. 00064 00065 @endverbatim 00066 * @{ 00067 */ 00068 00069 /* 2 OPAMPS available */ 00070 /* 2 OPAMPS can be calibrated in parallel */ 00071 /* Not available on STM32L41x/STM32L42x/STM32L43x/STM32L44x where only one OPAMP available */ 00072 00073 /** 00074 * @brief Run the self calibration of the 2 OPAMPs in parallel. 00075 * @note Trimming values (PMOS & NMOS) are updated and user trimming is 00076 * enabled is calibration is successful. 00077 * @note Calibration is performed in the mode specified in OPAMP init 00078 * structure (mode normal or low-power). To perform calibration for 00079 * both modes, repeat this function twice after OPAMP init structure 00080 * accordingly updated. 00081 * @note Calibration runs about 10 ms (5 dichotomy steps, repeated for P 00082 * and N transistors: 10 steps with 1 ms for each step). 00083 * @param hopamp1 handle 00084 * @param hopamp2 handle 00085 * @retval HAL status 00086 */ 00087 00088 HAL_StatusTypeDef HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef *hopamp1, OPAMP_HandleTypeDef *hopamp2) 00089 { 00090 HAL_StatusTypeDef status = HAL_OK; 00091 00092 uint32_t trimmingvaluen1; 00093 uint32_t trimmingvaluep1; 00094 uint32_t trimmingvaluen2; 00095 uint32_t trimmingvaluep2; 00096 00097 /* Selection of register of trimming depending on power mode: OTR or LPOTR */ 00098 __IO uint32_t* tmp_opamp1_reg_trimming; 00099 __IO uint32_t* tmp_opamp2_reg_trimming; 00100 00101 uint32_t delta; 00102 uint32_t opampmode1; 00103 uint32_t opampmode2; 00104 00105 if((hopamp1 == NULL) || (hopamp2 == NULL)) 00106 { 00107 status = HAL_ERROR; 00108 } 00109 /* Check if OPAMP in calibration mode and calibration not yet enable */ 00110 else if(hopamp1->State != HAL_OPAMP_STATE_READY) 00111 { 00112 status = HAL_ERROR; 00113 } 00114 else if(hopamp2->State != HAL_OPAMP_STATE_READY) 00115 { 00116 status = HAL_ERROR; 00117 } 00118 else 00119 { 00120 /* Check the parameter */ 00121 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp1->Instance)); 00122 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp2->Instance)); 00123 00124 assert_param(IS_OPAMP_POWERMODE(hopamp1->Init.PowerMode)); 00125 assert_param(IS_OPAMP_POWERMODE(hopamp2->Init.PowerMode)); 00126 00127 /* Save OPAMP mode as in */ 00128 /* STM32L471xx STM32L475xx STM32L476xx STM32L485xx STM32L486xx */ 00129 /* the calibration is not working in PGA mode */ 00130 opampmode1 = READ_BIT(hopamp1->Instance->CSR,OPAMP_CSR_OPAMODE); 00131 opampmode2 = READ_BIT(hopamp2->Instance->CSR,OPAMP_CSR_OPAMODE); 00132 00133 /* Use of standalone mode */ 00134 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_OPAMODE, OPAMP_STANDALONE_MODE); 00135 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_OPAMODE, OPAMP_STANDALONE_MODE); 00136 00137 /* user trimming values are used for offset calibration */ 00138 SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_USERTRIM); 00139 SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_USERTRIM); 00140 00141 /* Select trimming settings depending on power mode */ 00142 if (hopamp1->Init.PowerMode == OPAMP_POWERMODE_NORMALPOWER) 00143 { 00144 tmp_opamp1_reg_trimming = &OPAMP1->OTR; 00145 } 00146 else 00147 { 00148 tmp_opamp1_reg_trimming = &OPAMP1->LPOTR; 00149 } 00150 00151 if (hopamp2->Init.PowerMode == OPAMP_POWERMODE_NORMALPOWER) 00152 { 00153 tmp_opamp2_reg_trimming = &OPAMP2->OTR; 00154 } 00155 else 00156 { 00157 tmp_opamp2_reg_trimming = &OPAMP2->LPOTR; 00158 } 00159 00160 /* Enable calibration */ 00161 SET_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALON); 00162 SET_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALON); 00163 00164 /* 1st calibration - N */ 00165 CLEAR_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALSEL); 00166 CLEAR_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALSEL); 00167 00168 /* Enable the selected opamp */ 00169 SET_BIT (hopamp1->Instance->CSR, OPAMP_CSR_OPAMPxEN); 00170 SET_BIT (hopamp2->Instance->CSR, OPAMP_CSR_OPAMPxEN); 00171 00172 /* Init trimming counter */ 00173 /* Medium value */ 00174 trimmingvaluen1 = 16U; 00175 trimmingvaluen2 = 16U; 00176 delta = 8U; 00177 00178 while (delta != 0U) 00179 { 00180 /* Set candidate trimming */ 00181 /* OPAMP_POWERMODE_NORMALPOWER */ 00182 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1); 00183 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2); 00184 00185 /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */ 00186 /* Offset trim time: during calibration, minimum time needed between */ 00187 /* two steps to have 1 mV accuracy */ 00188 HAL_Delay(OPAMP_TRIMMING_DELAY); 00189 00190 if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT) != 0U) 00191 { 00192 /* OPAMP_CSR_CALOUT is HIGH try lower trimming */ 00193 trimmingvaluen1 -= delta; 00194 } 00195 else 00196 { 00197 /* OPAMP_CSR_CALOUT is LOW try higher trimming */ 00198 trimmingvaluen1 += delta; 00199 } 00200 00201 if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT) != 0U) 00202 { 00203 /* OPAMP_CSR_CALOUT is HIGH try lower trimming */ 00204 trimmingvaluen2 -= delta; 00205 } 00206 else 00207 { 00208 /* OPAMP_CSR_CALOUT is LOW try higher trimming */ 00209 trimmingvaluen2 += delta; 00210 } 00211 /* Divide range by 2 to continue dichotomy sweep */ 00212 delta >>= 1U; 00213 } 00214 00215 /* Still need to check if right calibration is current value or one step below */ 00216 /* Indeed the first value that causes the OUTCAL bit to change from 0 to 1 */ 00217 /* Set candidate trimming */ 00218 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1); 00219 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2); 00220 00221 /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */ 00222 /* Offset trim time: during calibration, minimum time needed between */ 00223 /* two steps to have 1 mV accuracy */ 00224 HAL_Delay(OPAMP_TRIMMING_DELAY); 00225 00226 if ((READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT)) == 0U) 00227 { 00228 /* Trimming value is actually one value more */ 00229 trimmingvaluen1++; 00230 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1); 00231 } 00232 00233 if ((READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT)) == 0U) 00234 { 00235 /* Trimming value is actually one value more */ 00236 trimmingvaluen2++; 00237 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2); 00238 } 00239 00240 /* 2nd calibration - P */ 00241 SET_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALSEL); 00242 SET_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALSEL); 00243 00244 /* Init trimming counter */ 00245 /* Medium value */ 00246 trimmingvaluep1 = 16U; 00247 trimmingvaluep2 = 16U; 00248 delta = 8U; 00249 00250 while (delta != 0U) 00251 { 00252 /* Set candidate trimming */ 00253 /* OPAMP_POWERMODE_NORMALPOWER */ 00254 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING)); 00255 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING)); 00256 00257 /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */ 00258 /* Offset trim time: during calibration, minimum time needed between */ 00259 /* two steps to have 1 mV accuracy */ 00260 HAL_Delay(OPAMP_TRIMMING_DELAY); 00261 00262 if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT) != 0U) 00263 { 00264 /* OPAMP_CSR_CALOUT is HIGH try higher trimming */ 00265 trimmingvaluep1 += delta; 00266 } 00267 else 00268 { 00269 /* OPAMP_CSR_CALOUT is HIGH try lower trimming */ 00270 trimmingvaluep1 -= delta; 00271 } 00272 00273 if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT) != 0U) 00274 { 00275 /* OPAMP_CSR_CALOUT is HIGH try higher trimming */ 00276 trimmingvaluep2 += delta; 00277 } 00278 else 00279 { 00280 /* OPAMP_CSR_CALOUT is LOW try lower trimming */ 00281 trimmingvaluep2 -= delta; 00282 } 00283 /* Divide range by 2 to continue dichotomy sweep */ 00284 delta >>= 1U; 00285 } 00286 00287 /* Still need to check if right calibration is current value or one step below */ 00288 /* Indeed the first value that causes the OUTCAL bit to change from 1 to 0 */ 00289 /* Set candidate trimming */ 00290 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING)); 00291 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING)); 00292 00293 /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */ 00294 /* Offset trim time: during calibration, minimum time needed between */ 00295 /* two steps to have 1 mV accuracy */ 00296 HAL_Delay(OPAMP_TRIMMING_DELAY); 00297 00298 if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT) != 0U) 00299 { 00300 /* Trimming value is actually one value more */ 00301 trimmingvaluep1++; 00302 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING)); 00303 } 00304 00305 if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT) != 0U) 00306 { 00307 /* Trimming value is actually one value more */ 00308 trimmingvaluep2++; 00309 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING)); 00310 } 00311 00312 /* Disable the OPAMPs */ 00313 CLEAR_BIT (hopamp1->Instance->CSR, OPAMP_CSR_OPAMPxEN); 00314 CLEAR_BIT (hopamp2->Instance->CSR, OPAMP_CSR_OPAMPxEN); 00315 00316 /* Disable calibration & set normal mode (operating mode) */ 00317 CLEAR_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALON); 00318 CLEAR_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALON); 00319 00320 /* Self calibration is successful */ 00321 /* Store calibration (user trimming) results in init structure. */ 00322 00323 /* Set user trimming mode */ 00324 hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER; 00325 hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER; 00326 00327 /* Affect calibration parameters depending on mode normal/low power */ 00328 if (hopamp1->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER) 00329 { 00330 /* Write calibration result N */ 00331 hopamp1->Init.TrimmingValueN = trimmingvaluen1; 00332 /* Write calibration result P */ 00333 hopamp1->Init.TrimmingValueP = trimmingvaluep1; 00334 } 00335 else 00336 { 00337 /* Write calibration result N */ 00338 hopamp1->Init.TrimmingValueNLowPower = trimmingvaluen1; 00339 /* Write calibration result P */ 00340 hopamp1->Init.TrimmingValuePLowPower = trimmingvaluep1; 00341 } 00342 00343 if (hopamp2->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER) 00344 { 00345 /* Write calibration result N */ 00346 hopamp2->Init.TrimmingValueN = trimmingvaluen2; 00347 /* Write calibration result P */ 00348 hopamp2->Init.TrimmingValueP = trimmingvaluep2; 00349 } 00350 else 00351 { 00352 /* Write calibration result N */ 00353 hopamp2->Init.TrimmingValueNLowPower = trimmingvaluen2; 00354 /* Write calibration result P */ 00355 hopamp2->Init.TrimmingValuePLowPower = trimmingvaluep2; 00356 } 00357 00358 /* Update OPAMP state */ 00359 hopamp1->State = HAL_OPAMP_STATE_READY; 00360 hopamp2->State = HAL_OPAMP_STATE_READY; 00361 00362 /* Restore OPAMP mode after calibration */ 00363 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_OPAMODE, opampmode1); 00364 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_OPAMODE, opampmode2); 00365 } 00366 return status; 00367 } 00368 00369 /** 00370 * @} 00371 */ 00372 00373 #endif 00374 00375 /** @defgroup OPAMPEx_Exported_Functions_Group2 Peripheral Control functions 00376 * @brief Peripheral Control functions 00377 * 00378 @verbatim 00379 =============================================================================== 00380 ##### Peripheral Control functions ##### 00381 =============================================================================== 00382 [..] 00383 (+) OPAMP unlock. 00384 00385 @endverbatim 00386 * @{ 00387 */ 00388 00389 /** 00390 * @brief Unlock the selected OPAMP configuration. 00391 * @note This function must be called only when OPAMP is in state "locked". 00392 * @param hopamp OPAMP handle 00393 * @retval HAL status 00394 */ 00395 HAL_StatusTypeDef HAL_OPAMPEx_Unlock(OPAMP_HandleTypeDef* hopamp) 00396 { 00397 HAL_StatusTypeDef status = HAL_OK; 00398 00399 /* Check the OPAMP handle allocation */ 00400 /* Check if OPAMP locked */ 00401 if(hopamp == NULL) 00402 { 00403 status = HAL_ERROR; 00404 } 00405 /* Check the OPAMP handle allocation */ 00406 /* Check if OPAMP locked */ 00407 else if(hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED) 00408 { 00409 /* Check the parameter */ 00410 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance)); 00411 00412 /* OPAMP state changed to locked */ 00413 hopamp->State = HAL_OPAMP_STATE_BUSY; 00414 } 00415 else 00416 { 00417 status = HAL_ERROR; 00418 } 00419 00420 return status; 00421 } 00422 00423 /** 00424 * @} 00425 */ 00426 00427 /** 00428 * @} 00429 */ 00430 00431 #endif /* HAL_OPAMP_MODULE_ENABLED */ 00432 /** 00433 * @} 00434 */ 00435 00436 /** 00437 * @} 00438 */