STM32L486xx 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)(OPAMP1, OPAMP2 etc) 00008 * peripheral: 00009 * + Extended Initialization and de-initialization functions 00010 * + Extended Peripheral Control functions 00011 * 00012 @verbatim 00013 ****************************************************************************** 00014 * @attention 00015 * 00016 * <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2> 00017 * 00018 * Redistribution and use in source and binary forms, with or without modification, 00019 * are permitted provided that the following conditions are met: 00020 * 1. Redistributions of source code must retain the above copyright notice, 00021 * this list of conditions and the following disclaimer. 00022 * 2. Redistributions in binary form must reproduce the above copyright notice, 00023 * this list of conditions and the following disclaimer in the documentation 00024 * and/or other materials provided with the distribution. 00025 * 3. Neither the name of STMicroelectronics nor the names of its contributors 00026 * may be used to endorse or promote products derived from this software 00027 * without specific prior written permission. 00028 * 00029 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00030 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00031 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00032 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 00033 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00034 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 00035 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00036 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 00037 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00038 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00039 * 00040 ****************************************************************************** 00041 */ 00042 00043 /* Includes ------------------------------------------------------------------*/ 00044 #include "stm32l4xx_hal.h" 00045 00046 /** @addtogroup STM32L4xx_HAL_Driver 00047 * @{ 00048 */ 00049 00050 /** @defgroup OPAMPEx OPAMPEx 00051 * @brief OPAMP Extended HAL module driver 00052 * @{ 00053 */ 00054 00055 #ifdef HAL_OPAMP_MODULE_ENABLED 00056 00057 /* Private typedef -----------------------------------------------------------*/ 00058 /* Private define ------------------------------------------------------------*/ 00059 /* Private macro -------------------------------------------------------------*/ 00060 /* Private variables ---------------------------------------------------------*/ 00061 /* Private function prototypes -----------------------------------------------*/ 00062 /* Exported functions --------------------------------------------------------*/ 00063 00064 /** @defgroup OPAMP_Exported_Functions OPAMP Exported Functions 00065 * @{ 00066 */ 00067 00068 #if defined (STM32L471xx) || defined (STM32L475xx) || defined (STM32L476xx) || defined (STM32L485xx) || defined (STM32L486xx) || \ 00069 defined (STM32L496xx) || defined (STM32L4A6xx) || \ 00070 defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx) 00071 00072 /** @addtogroup OPAMPEx_Exported_Functions_Group1 00073 * @brief Extended operation functions 00074 * 00075 @verbatim 00076 =============================================================================== 00077 ##### Extended IO operation functions ##### 00078 =============================================================================== 00079 [..] 00080 (+) OPAMP Self calibration. 00081 00082 @endverbatim 00083 * @{ 00084 */ 00085 00086 /* 2 OPAMPS available */ 00087 /* 2 OPAMPS can be calibrated in parallel */ 00088 /* Not available on STM32L43x/STM32L44x where only one OPAMP available */ 00089 00090 /** 00091 * @brief Run the self calibration of the 2 OPAMPs in parallel. 00092 * @note Trimming values (PMOS & NMOS) are updated and user trimming is 00093 * enabled is calibration is successful. 00094 * @note Calibration is performed in the mode specified in OPAMP init 00095 * structure (mode normal or low-power). To perform calibration for 00096 * both modes, repeat this function twice after OPAMP init structure 00097 * accordingly updated. 00098 * @note Calibration runs about 10 ms (5 dichotomy steps, repeated for P 00099 * and N transistors: 10 steps with 1 ms for each step). 00100 * @param hopamp1 handle 00101 * @param hopamp2 handle 00102 * @retval HAL status 00103 */ 00104 00105 HAL_StatusTypeDef HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef *hopamp1, OPAMP_HandleTypeDef *hopamp2) 00106 { 00107 HAL_StatusTypeDef status = HAL_OK; 00108 00109 uint32_t trimmingvaluen1 = 0; 00110 uint32_t trimmingvaluep1 = 0; 00111 uint32_t trimmingvaluen2 = 0; 00112 uint32_t trimmingvaluep2 = 0; 00113 00114 /* Selection of register of trimming depending on power mode: OTR or LPOTR */ 00115 __IO uint32_t* tmp_opamp1_reg_trimming; 00116 __IO uint32_t* tmp_opamp2_reg_trimming; 00117 00118 uint32_t delta; 00119 uint32_t opampmode1; 00120 uint32_t opampmode2; 00121 00122 if((hopamp1 == NULL) || (hopamp1->State == HAL_OPAMP_STATE_BUSYLOCKED) || \ 00123 (hopamp2 == NULL) || (hopamp2->State == HAL_OPAMP_STATE_BUSYLOCKED)) 00124 { 00125 status = HAL_ERROR; 00126 } 00127 else 00128 { 00129 /* Check if OPAMP in calibration mode and calibration not yet enable */ 00130 if((hopamp1->State == HAL_OPAMP_STATE_READY) && (hopamp2->State == HAL_OPAMP_STATE_READY)) 00131 { 00132 /* Check the parameter */ 00133 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp1->Instance)); 00134 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp2->Instance)); 00135 00136 assert_param(IS_OPAMP_POWERMODE(hopamp1->Init.PowerMode)); 00137 assert_param(IS_OPAMP_POWERMODE(hopamp2->Init.PowerMode)); 00138 00139 /* Save OPAMP mode as in */ 00140 /* STM32L471xx STM32L475xx STM32L476xx STM32L485xx STM32L486xx */ 00141 /* the calibration is not working in PGA mode */ 00142 opampmode1 = READ_BIT(hopamp1->Instance->CSR,OPAMP_CSR_OPAMODE); 00143 opampmode2 = READ_BIT(hopamp2->Instance->CSR,OPAMP_CSR_OPAMODE); 00144 00145 /* Use of standalone mode */ 00146 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_OPAMODE, OPAMP_STANDALONE_MODE); 00147 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_OPAMODE, OPAMP_STANDALONE_MODE); 00148 00149 /* user trimming values are used for offset calibration */ 00150 SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_USERTRIM); 00151 SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_USERTRIM); 00152 00153 /* Select trimming settings depending on power mode */ 00154 if (hopamp1->Init.PowerMode == OPAMP_POWERMODE_NORMAL) 00155 { 00156 tmp_opamp1_reg_trimming = &OPAMP1->OTR; 00157 } 00158 else 00159 { 00160 tmp_opamp1_reg_trimming = &OPAMP1->LPOTR; 00161 } 00162 00163 if (hopamp2->Init.PowerMode == OPAMP_POWERMODE_NORMAL) 00164 { 00165 tmp_opamp2_reg_trimming = &OPAMP2->OTR; 00166 } 00167 else 00168 { 00169 tmp_opamp2_reg_trimming = &OPAMP2->LPOTR; 00170 } 00171 00172 /* Enable calibration */ 00173 SET_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALON); 00174 SET_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALON); 00175 00176 /* 1st calibration - N */ 00177 CLEAR_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALSEL); 00178 CLEAR_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALSEL); 00179 00180 /* Enable the selected opamp */ 00181 SET_BIT (hopamp1->Instance->CSR, OPAMP_CSR_OPAMPxEN); 00182 SET_BIT (hopamp2->Instance->CSR, OPAMP_CSR_OPAMPxEN); 00183 00184 /* Init trimming counter */ 00185 /* Medium value */ 00186 trimmingvaluen1 = 16; 00187 trimmingvaluen2 = 16; 00188 delta = 8; 00189 00190 while (delta != 0) 00191 { 00192 /* Set candidate trimming */ 00193 /* OPAMP_POWERMODE_NORMAL */ 00194 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1); 00195 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2); 00196 00197 /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */ 00198 /* Offset trim time: during calibration, minimum time needed between */ 00199 /* two steps to have 1 mV accuracy */ 00200 HAL_Delay(OPAMP_TRIMMING_DELAY); 00201 00202 if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT) != RESET) 00203 { 00204 /* OPAMP_CSR_CALOUT is HIGH try lower trimming */ 00205 trimmingvaluen1 -= delta; 00206 } 00207 else 00208 { 00209 /* OPAMP_CSR_CALOUT is LOW try higher trimming */ 00210 trimmingvaluen1 += delta; 00211 } 00212 00213 if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT) != RESET) 00214 { 00215 /* OPAMP_CSR_CALOUT is HIGH try lower trimming */ 00216 trimmingvaluen2 -= delta; 00217 } 00218 else 00219 { 00220 /* OPAMP_CSR_CALOUT is LOW try higher trimming */ 00221 trimmingvaluen2 += delta; 00222 } 00223 /* Divide range by 2 to continue dichotomy sweep */ 00224 delta >>= 1; 00225 } 00226 00227 /* Still need to check if right calibration is current value or one step below */ 00228 /* Indeed the first value that causes the OUTCAL bit to change from 0 to 1 */ 00229 /* Set candidate trimming */ 00230 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1); 00231 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2); 00232 00233 /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */ 00234 /* Offset trim time: during calibration, minimum time needed between */ 00235 /* two steps to have 1 mV accuracy */ 00236 HAL_Delay(OPAMP_TRIMMING_DELAY); 00237 00238 if ((READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT)) == 0) 00239 { 00240 /* Trimming value is actually one value more */ 00241 trimmingvaluen1++; 00242 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1); 00243 } 00244 00245 if ((READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT)) == 0) 00246 { 00247 /* Trimming value is actually one value more */ 00248 trimmingvaluen2++; 00249 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2); 00250 } 00251 00252 /* 2nd calibration - P */ 00253 SET_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALSEL); 00254 SET_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALSEL); 00255 00256 /* Init trimming counter */ 00257 /* Medium value */ 00258 trimmingvaluep1 = 16; 00259 trimmingvaluep2 = 16; 00260 delta = 8; 00261 00262 while (delta != 0) 00263 { 00264 /* Set candidate trimming */ 00265 /* OPAMP_POWERMODE_NORMAL */ 00266 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING)); 00267 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING)); 00268 00269 /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */ 00270 /* Offset trim time: during calibration, minimum time needed between */ 00271 /* two steps to have 1 mV accuracy */ 00272 HAL_Delay(OPAMP_TRIMMING_DELAY); 00273 00274 if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT) != RESET) 00275 { 00276 /* OPAMP_CSR_CALOUT is HIGH try higher trimming */ 00277 trimmingvaluep1 += delta; 00278 } 00279 else 00280 { 00281 /* OPAMP_CSR_CALOUT is HIGH try lower trimming */ 00282 trimmingvaluep1 -= delta; 00283 } 00284 00285 if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT) != RESET) 00286 { 00287 /* OPAMP_CSR_CALOUT is HIGH try higher trimming */ 00288 trimmingvaluep2 += delta; 00289 } 00290 else 00291 { 00292 /* OPAMP_CSR_CALOUT is LOW try lower trimming */ 00293 trimmingvaluep2 -= delta; 00294 } 00295 /* Divide range by 2 to continue dichotomy sweep */ 00296 delta >>= 1; 00297 } 00298 00299 /* Still need to check if right calibration is current value or one step below */ 00300 /* Indeed the first value that causes the OUTCAL bit to change from 1 to 0 */ 00301 /* Set candidate trimming */ 00302 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING)); 00303 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING)); 00304 00305 /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */ 00306 /* Offset trim time: during calibration, minimum time needed between */ 00307 /* two steps to have 1 mV accuracy */ 00308 HAL_Delay(OPAMP_TRIMMING_DELAY); 00309 00310 if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT) != RESET) 00311 { 00312 /* Trimming value is actually one value more */ 00313 trimmingvaluep1++; 00314 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING)); 00315 } 00316 00317 if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT) != RESET) 00318 { 00319 /* Trimming value is actually one value more */ 00320 trimmingvaluep2++; 00321 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING)); 00322 } 00323 00324 /* Disable the OPAMPs */ 00325 CLEAR_BIT (hopamp1->Instance->CSR, OPAMP_CSR_OPAMPxEN); 00326 CLEAR_BIT (hopamp2->Instance->CSR, OPAMP_CSR_OPAMPxEN); 00327 00328 /* Disable calibration & set normal mode (operating mode) */ 00329 CLEAR_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALON); 00330 CLEAR_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALON); 00331 00332 /* Self calibration is successful */ 00333 /* Store calibration (user trimming) results in init structure. */ 00334 00335 /* Set user trimming mode */ 00336 hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER; 00337 hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER; 00338 00339 /* Affect calibration parameters depending on mode normal/low power */ 00340 if (hopamp1->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER) 00341 { 00342 /* Write calibration result N */ 00343 hopamp1->Init.TrimmingValueN = trimmingvaluen1; 00344 /* Write calibration result P */ 00345 hopamp1->Init.TrimmingValueP = trimmingvaluep1; 00346 } 00347 else 00348 { 00349 /* Write calibration result N */ 00350 hopamp1->Init.TrimmingValueNLowPower = trimmingvaluen1; 00351 /* Write calibration result P */ 00352 hopamp1->Init.TrimmingValuePLowPower = trimmingvaluep1; 00353 } 00354 00355 if (hopamp2->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER) 00356 { 00357 /* Write calibration result N */ 00358 hopamp2->Init.TrimmingValueN = trimmingvaluen2; 00359 /* Write calibration result P */ 00360 hopamp2->Init.TrimmingValueP = trimmingvaluep2; 00361 } 00362 else 00363 { 00364 /* Write calibration result N */ 00365 hopamp2->Init.TrimmingValueNLowPower = trimmingvaluen2; 00366 /* Write calibration result P */ 00367 hopamp2->Init.TrimmingValuePLowPower = trimmingvaluep2; 00368 } 00369 00370 /* Update OPAMP state */ 00371 hopamp1->State = HAL_OPAMP_STATE_READY; 00372 hopamp2->State = HAL_OPAMP_STATE_READY; 00373 00374 /* Restore OPAMP mode after calibration */ 00375 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_OPAMODE, opampmode1); 00376 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_OPAMODE, opampmode2); 00377 } 00378 else 00379 { 00380 /* At least one OPAMP can not be calibrated */ 00381 status = HAL_ERROR; 00382 } 00383 } 00384 return status; 00385 } 00386 00387 /** 00388 * @} 00389 */ 00390 00391 #endif 00392 00393 /** @defgroup OPAMPEx_Exported_Functions_Group2 Peripheral Control functions 00394 * @brief Peripheral Control functions 00395 * 00396 @verbatim 00397 =============================================================================== 00398 ##### Peripheral Control functions ##### 00399 =============================================================================== 00400 [..] 00401 (+) OPAMP unlock. 00402 00403 @endverbatim 00404 * @{ 00405 */ 00406 00407 /** 00408 * @brief Unlock the selected OPAMP configuration. 00409 * @note This function must be called only when OPAMP is in state "locked". 00410 * @param hopamp: OPAMP handle 00411 * @retval HAL status 00412 */ 00413 HAL_StatusTypeDef HAL_OPAMPEx_Unlock(OPAMP_HandleTypeDef* hopamp) 00414 { 00415 HAL_StatusTypeDef status = HAL_OK; 00416 00417 /* Check the OPAMP handle allocation */ 00418 /* Check if OPAMP locked */ 00419 if((hopamp == NULL) || (hopamp->State == HAL_OPAMP_STATE_RESET) 00420 || (hopamp->State == HAL_OPAMP_STATE_READY) 00421 || (hopamp->State == HAL_OPAMP_STATE_CALIBBUSY) 00422 || (hopamp->State == HAL_OPAMP_STATE_BUSY)) 00423 00424 { 00425 status = HAL_ERROR; 00426 } 00427 else 00428 { 00429 /* Check the parameter */ 00430 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance)); 00431 00432 /* OPAMP state changed to locked */ 00433 hopamp->State = HAL_OPAMP_STATE_BUSY; 00434 } 00435 return status; 00436 } 00437 00438 /** 00439 * @} 00440 */ 00441 00442 /** 00443 * @} 00444 */ 00445 00446 #endif /* HAL_OPAMP_MODULE_ENABLED */ 00447 /** 00448 * @} 00449 */ 00450 00451 /** 00452 * @} 00453 */ 00454 00455 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/