STM32H735xx HAL User Manual
stm32h7xx_hal_opamp_ex.c
Go to the documentation of this file.
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