Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:08

0001 /**
0002   ******************************************************************************
0003   * @file    stm32h7xx_hal_opamp_ex.c
0004   * @author  MCD Application Team
0005   * @brief   Extended OPAMP HAL module driver.
0006   *          This file provides firmware functions to manage the following
0007   *          functionalities of the operational amplifier(s) peripheral:
0008   *           + Extended Initialization and de-initialization functions
0009   *           + Extended Peripheral Control functions
0010   *
0011   @verbatim
0012   ******************************************************************************
0013   * @attention
0014   *
0015   * Copyright (c) 2017 STMicroelectronics.
0016   * All rights reserved.
0017   *
0018   * This software is licensed under terms that can be found in the LICENSE file
0019   * in the root directory of this software component.
0020   * If no LICENSE file comes with this software, it is provided AS-IS.
0021   *
0022   ******************************************************************************
0023   */
0024 
0025 /* Includes ------------------------------------------------------------------*/
0026 #include "stm32h7xx_hal.h"
0027 
0028 /** @addtogroup STM32H7xx_HAL_Driver
0029   * @{
0030   */
0031 
0032 /** @defgroup OPAMPEx OPAMPEx
0033   * @ingroup RTEMSBSPsARMSTM32H7
0034   * @brief OPAMP Extended HAL module driver
0035   * @{
0036   */
0037 
0038 #ifdef HAL_OPAMP_MODULE_ENABLED
0039 
0040 /* Private typedef -----------------------------------------------------------*/
0041 /* Private define ------------------------------------------------------------*/
0042 /* Private macro -------------------------------------------------------------*/
0043 /* Private variables ---------------------------------------------------------*/
0044 /* Private function prototypes -----------------------------------------------*/
0045 /* Exported functions --------------------------------------------------------*/
0046 
0047 /** @defgroup OPAMPEx_Exported_Functions OPAMP Extended Exported Functions
0048   * @ingroup RTEMSBSPsARMSTM32H7
0049   * @{
0050   */
0051 
0052 /** @defgroup OPAMPEx_Exported_Functions_Group1 Extended Input and Output operation functions
0053   * @ingroup RTEMSBSPsARMSTM32H7
0054   * @brief    Extended operation functions
0055   *
0056 @verbatim
0057  ===============================================================================
0058               ##### Extended IO operation functions #####
0059  ===============================================================================
0060   [..]
0061       (+) OPAMP Self calibration. 
0062 
0063 @endverbatim
0064   * @{
0065   */
0066 
0067 /**
0068   * @brief  Run the self calibration of 2 OPAMPs in parallel.
0069   * @note   Trimming values (PMOS & NMOS) are updated and user trimming is 
0070   *         enabled is calibration is successful.
0071   * @note   Calibration is performed in the mode specified in OPAMP init
0072   *         structure (mode normal or low power). To perform calibration for
0073   *         both modes, repeat this function twice after OPAMP init structure
0074   *         accordingly updated.
0075   * @param  hopamp1 handle
0076   * @param  hopamp2 handle
0077   * @retval HAL status
0078   */
0079 
0080 HAL_StatusTypeDef HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef *hopamp1, OPAMP_HandleTypeDef *hopamp2)
0081 {
0082   HAL_StatusTypeDef status = HAL_OK;
0083 
0084   uint32_t trimmingvaluen1;
0085   uint32_t trimmingvaluep1;
0086   uint32_t trimmingvaluen2;
0087   uint32_t trimmingvaluep2;
0088 
0089 /* Selection of register of trimming depending on power mode: OTR or HSOTR */
0090   __IO uint32_t* tmp_opamp1_reg_trimming;   
0091   __IO uint32_t* tmp_opamp2_reg_trimming;
0092 
0093   uint32_t delta;
0094   uint32_t opampmode1;
0095   uint32_t opampmode2;
0096   
0097   if((hopamp1 == NULL) || (hopamp2 == NULL)) 
0098   {
0099     status = HAL_ERROR;
0100   }
0101   /* Check if OPAMP in calibration mode and calibration not yet enable */
0102   else if(hopamp1->State !=  HAL_OPAMP_STATE_READY)
0103   {
0104     status = HAL_ERROR;
0105   }
0106   else if(hopamp2->State != HAL_OPAMP_STATE_READY)
0107   {
0108     status = HAL_ERROR;
0109   }
0110   else
0111   {
0112       /* Check the parameter */
0113       assert_param(IS_OPAMP_ALL_INSTANCE(hopamp1->Instance));
0114       assert_param(IS_OPAMP_ALL_INSTANCE(hopamp2->Instance));
0115       
0116       assert_param(IS_OPAMP_POWERMODE(hopamp1->Init.PowerMode));
0117       assert_param(IS_OPAMP_POWERMODE(hopamp2->Init.PowerMode));
0118 
0119       /* Set Calibration mode */
0120       /* Non-inverting input connected to calibration reference voltage. */
0121       SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_FORCEVP);
0122       SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_FORCEVP);
0123 
0124       /* Save OPAMP mode  */
0125       opampmode1 = READ_BIT(hopamp1->Instance->CSR,OPAMP_CSR_VMSEL);
0126       opampmode2 = READ_BIT(hopamp2->Instance->CSR,OPAMP_CSR_VMSEL);
0127 
0128       /* Use of standalone mode */ 
0129       MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_VMSEL, OPAMP_STANDALONE_MODE); 
0130       MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_VMSEL, OPAMP_STANDALONE_MODE); 
0131 
0132       /*  user trimming values are used for offset calibration */
0133       SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_USERTRIM);
0134       SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_USERTRIM);
0135       
0136       /* Select trimming settings depending on power mode */
0137       if (hopamp1->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
0138       {
0139         tmp_opamp1_reg_trimming = &OPAMP1->OTR;
0140       }
0141       else
0142       {
0143         tmp_opamp1_reg_trimming = &OPAMP1->HSOTR;
0144       }
0145       
0146       if (hopamp2->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
0147       {
0148         tmp_opamp2_reg_trimming = &OPAMP2->OTR;
0149       }
0150       else
0151       {
0152         tmp_opamp2_reg_trimming = &OPAMP2->HSOTR;
0153       }
0154       
0155       /* Enable calibration */
0156       SET_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALON);
0157       SET_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALON);
0158   
0159       /* 1st calibration - N */
0160       /* Select 90U% VREF */
0161       MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_90VDDA);
0162       MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_90VDDA);
0163 
0164       /* Enable the selected opamp */
0165       SET_BIT (hopamp1->Instance->CSR, OPAMP_CSR_OPAMPxEN);
0166       SET_BIT (hopamp2->Instance->CSR, OPAMP_CSR_OPAMPxEN);
0167       
0168       /* Init trimming counter */    
0169       /* Medium value */
0170       trimmingvaluen1 = 16U; 
0171       trimmingvaluen2 = 16U; 
0172       delta = 8U; 
0173 
0174       while (delta != 0U)
0175       {
0176         /* Set candidate trimming */
0177         /* OPAMP_POWERMODE_NORMAL */
0178         MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1);
0179         MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2);
0180 
0181         /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */ 
0182         /* Offset trim time: during calibration, minimum time needed between */
0183         /* two steps to have 1 mV accuracy */
0184         HAL_Delay(OPAMP_TRIMMING_DELAY);
0185 
0186         if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U)
0187         { 
0188           /* OPAMP_CSR_CALOUT is Low try higher trimming */
0189           trimmingvaluen1 += delta;
0190         }
0191         else
0192         {
0193           /* OPAMP_CSR_CALOUT is High try lower trimming */
0194           trimmingvaluen1 -= delta;
0195         }
0196 
0197         if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U) 
0198         { 
0199           /* OPAMP_CSR_CALOUT is Low try higher trimming */
0200           trimmingvaluen2 += delta;
0201         }
0202         else
0203         {
0204           /* OPAMP_CSR_CALOUT is High try lower trimming */
0205           trimmingvaluen2 -= delta;
0206         }
0207         /* Divide range by 2 to continue dichotomy sweep */
0208         delta >>= 1U;
0209       }
0210 
0211       /* Still need to check if right calibration is current value or one step below */
0212       /* Indeed the first value that causes the OUTCAL bit to change from 0 to 1  */
0213       /* Set candidate trimming */
0214       MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1);
0215       MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2);
0216       
0217       /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */ 
0218       /* Offset trim time: during calibration, minimum time needed between */
0219       /* two steps to have 1 mV accuracy */
0220       HAL_Delay(OPAMP_TRIMMING_DELAY);
0221       
0222       if ((READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT)) != 0U)
0223       {
0224         /* Trimming value is actually one value more */
0225         trimmingvaluen1++;
0226         MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1);
0227       }
0228        
0229       if ((READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT)) != 0U)
0230       {
0231         /* Trimming value is actually one value more */
0232         trimmingvaluen2++;
0233         MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2);
0234       }
0235       
0236       /* 2nd calibration - P */
0237       /* Select 10U% VREF */
0238       MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_10VDDA);
0239       MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_10VDDA);
0240      
0241       /* Init trimming counter */    
0242       /* Medium value */
0243       trimmingvaluep1 = 16U; 
0244       trimmingvaluep2 = 16U; 
0245       delta = 8U; 
0246       
0247       while (delta != 0U)
0248       {
0249         /* Set candidate trimming */
0250         /* OPAMP_POWERMODE_NORMAL */
0251         MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING));
0252         MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING));
0253 
0254         /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */ 
0255         /* Offset trim time: during calibration, minimum time needed between */
0256         /* two steps to have 1 mV accuracy */
0257         HAL_Delay(OPAMP_TRIMMING_DELAY);
0258 
0259         if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U) 
0260         { 
0261           /* OPAMP_CSR_CALOUT is Low try higher trimming */
0262           trimmingvaluep1 += delta;
0263         }
0264         else
0265         {
0266           /* OPAMP_CSR_CALOUT is HIGH try lower trimming */
0267           trimmingvaluep1 -= delta;
0268         }
0269 
0270         if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U) 
0271         { 
0272           /* OPAMP_CSR_CALOUT is Low try higher trimming */
0273           trimmingvaluep2 += delta;
0274         }
0275         else
0276         {
0277           /* OPAMP_CSR_CALOUT is High try lower trimming */
0278           trimmingvaluep2 -= delta;
0279         }
0280         /* Divide range by 2 to continue dichotomy sweep */
0281         delta >>= 1U;
0282       }
0283       
0284       /* Still need to check if right calibration is current value or one step below */
0285       /* Indeed the first value that causes the OUTCAL bit to change from 1 to 0  */
0286       /* Set candidate trimming */
0287       MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING));
0288       MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING));
0289       
0290       /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */ 
0291       /* Offset trim time: during calibration, minimum time needed between */
0292       /* two steps to have 1 mV accuracy */
0293       HAL_Delay(OPAMP_TRIMMING_DELAY);
0294       
0295       if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U)
0296       {
0297         /* Trimming value is actually one value more */
0298         trimmingvaluep1++;
0299         MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING));
0300       }
0301       
0302       if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT)!= 0U)
0303       {
0304         /* Trimming value is actually one value more */
0305         trimmingvaluep2++;
0306         MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING));
0307       }
0308             
0309       /* Disable calibration & set normal mode (operating mode) */
0310       CLEAR_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALON);
0311       CLEAR_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALON);
0312 
0313      /* Disable the OPAMPs */
0314       CLEAR_BIT (hopamp1->Instance->CSR, OPAMP_CSR_OPAMPxEN);
0315       CLEAR_BIT (hopamp2->Instance->CSR, OPAMP_CSR_OPAMPxEN);
0316 
0317       /* Self calibration is successful */
0318       /* Store calibration (user trimming) results in init structure. */
0319       
0320       /* Set user trimming mode */ 
0321       hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER;
0322       hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER;
0323 
0324       /* Affect calibration parameters depending on mode normal/high speed */
0325       if (hopamp1->Init.PowerMode != OPAMP_POWERMODE_HIGHSPEED)
0326       {
0327         /* Write calibration result N */
0328         hopamp1->Init.TrimmingValueN = trimmingvaluen1;
0329         /* Write calibration result P */
0330         hopamp1->Init.TrimmingValueP = trimmingvaluep1;
0331       }
0332       else
0333       {
0334         /* Write calibration result N */
0335         hopamp1->Init.TrimmingValueNHighSpeed = trimmingvaluen1;
0336         /* Write calibration result P */
0337         hopamp1->Init.TrimmingValuePHighSpeed = trimmingvaluep1;
0338       }
0339       
0340       if (hopamp2->Init.PowerMode != OPAMP_POWERMODE_HIGHSPEED)
0341       {
0342         /* Write calibration result N */
0343         hopamp2->Init.TrimmingValueN = trimmingvaluen2;
0344         /* Write calibration result P */
0345         hopamp2->Init.TrimmingValueP = trimmingvaluep2;
0346       }
0347       else
0348       {
0349         /* Write calibration result N */
0350         hopamp2->Init.TrimmingValueNHighSpeed = trimmingvaluen2;
0351         /* Write calibration result P */
0352         hopamp2->Init.TrimmingValuePHighSpeed = trimmingvaluep2;
0353      
0354        }
0355       /* Update OPAMP state */
0356       hopamp1->State = HAL_OPAMP_STATE_READY;
0357       hopamp2->State = HAL_OPAMP_STATE_READY;
0358 
0359       /* Restore OPAMP mode after calibration */
0360       MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_VMSEL, opampmode1);
0361       MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_VMSEL, opampmode2);
0362   }
0363   
0364   return status;
0365 }
0366 
0367 /**
0368   * @}
0369   */
0370 
0371 /** @defgroup OPAMPEx_Exported_Functions_Group2 Peripheral Control functions 
0372   * @ingroup RTEMSBSPsARMSTM32H7
0373  *  @brief   Peripheral Control functions 
0374  *
0375 @verbatim   
0376  ===============================================================================
0377              ##### Peripheral Control functions #####
0378  ===============================================================================
0379     [..]
0380       (+) OPAMP unlock. 
0381 
0382 @endverbatim
0383   * @{
0384   */
0385 
0386 /**
0387   * @brief  Unlock the selected OPAMP configuration.
0388   * @note   This function must be called only when OPAMP is in state "locked".
0389   * @param  hopamp: OPAMP handle
0390   * @retval HAL status
0391   */
0392 HAL_StatusTypeDef HAL_OPAMPEx_Unlock(OPAMP_HandleTypeDef* hopamp)
0393 {
0394   HAL_StatusTypeDef status = HAL_OK;
0395 
0396   /* Check the OPAMP handle allocation */
0397   /* Check if OPAMP locked */
0398   if(hopamp == NULL)
0399   {
0400     status = HAL_ERROR;
0401   }    
0402   /* Check the OPAMP handle allocation */
0403   /* Check if OPAMP locked */
0404   else if(hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
0405   {
0406     /* Check the parameter */
0407     assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
0408   
0409    /* OPAMP state changed to locked */
0410     hopamp->State = HAL_OPAMP_STATE_BUSY;
0411   }
0412   else
0413   {
0414     status = HAL_ERROR;
0415   }
0416       
0417   return status; 
0418 }
0419 
0420 /**
0421   * @}
0422   */
0423 
0424 /**
0425   * @}
0426   */
0427 
0428 /**
0429   * @}
0430   */
0431 
0432 /**
0433   * @}
0434   */
0435 
0436 #endif /* HAL_OPAMP_MODULE_ENABLED */
0437