STM32L486xx 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)(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>&copy; 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****/