STM32L443xx HAL User Manual
stm32l4xx_hal_opamp_ex.c
Go to the documentation of this file.
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   */