Beispiel #1
0
HAL_StatusTypeDef HAL_OPAMP_Start(OPAMP_HandleTypeDef* hopamp)
{ 
  HAL_StatusTypeDef status = HAL_OK;
  
  /* Check the OPAMP handle allocation */
  /* Check if OPAMP locked */
  if((hopamp == NULL) || (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED))
  {
    status = HAL_ERROR;
  }
  else
  {
    /* Check the parameter */
    assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
    
    if(hopamp->State == HAL_OPAMP_STATE_READY)
    {
      /* Enable the selected opamp */
      CLEAR_BIT (OPAMP->CSR, OPAMP_CSR_OPAXPD(hopamp));
      
      /* Update the OPAMP state */
      /* From HAL_OPAMP_STATE_READY to HAL_OPAMP_STATE_BUSY */
      hopamp->State = HAL_OPAMP_STATE_BUSY;   
    }
    else
    {
      status = HAL_ERROR;
    }
    
   }
  return status;
}
/**
  * @brief  DeInitialize the OPAMP peripheral.
  * @note   Deinitialization can be performed if the OPAMP configuration is locked.
  *         (the lock is SW in L4)
  * @param  hopamp: OPAMP handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_OPAMP_DeInit(OPAMP_HandleTypeDef *hopamp)
{
  HAL_StatusTypeDef status = HAL_OK;
  
  /* Check the OPAMP handle allocation */
  /* DeInit not allowed if calibration is ongoing */
  if((hopamp == NULL) || (hopamp->State == HAL_OPAMP_STATE_CALIBBUSY))
  {
    status = HAL_ERROR;
  }
  else
  {
    /* Check the parameter */
    assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));

    /* Set OPAMP_CSR register to reset value */
    /* Mind that OPAMP1_CSR_OPARANGE of CSR of OPAMP1 remains unchanged (applies to both OPAMPs) */ 
    /* OPAMP shall be disabled first separately */     
    CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
    MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_RESET_BITS, OPAMP_CSR_RESET_VALUE);
    
    /* DeInit the low level hardware: GPIO, CLOCK and NVIC */
    HAL_OPAMP_MspDeInit(hopamp);

    /* Update the OPAMP state*/
    hopamp->State = HAL_OPAMP_STATE_RESET;   
    
    /* Process unlocked */
    __HAL_UNLOCK(hopamp);
  }
  
  return status;
}
/**
  * @brief  Stop the opamp 
  * @param  hopamp: OPAMP handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_OPAMP_Stop(OPAMP_HandleTypeDef *hopamp)
{ 
  HAL_StatusTypeDef status = HAL_OK;
    
  /* Check the OPAMP handle allocation */
  /* Check if OPAMP locked */
  /* Check if OPAMP calibration ongoing */
  if((hopamp == NULL) || (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED) \
                      || (hopamp->State == HAL_OPAMP_STATE_CALIBBUSY))  
  {
    status = HAL_ERROR;
  }
  else
  {
    /* Check the parameter */
    assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));

    if(hopamp->State == HAL_OPAMP_STATE_BUSY)
    {
      /* Disable the selected opamp */
      CLEAR_BIT (hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN); 
    
      /* Update the OPAMP state*/     
      /* From  HAL_OPAMP_STATE_BUSY to HAL_OPAMP_STATE_READY*/
      hopamp->State = HAL_OPAMP_STATE_READY;
    }
    else
    {
      status = HAL_ERROR;
    }
  }
  return status;
}
Beispiel #4
0
/**
  * @brief  DeInitializes the OPAMP peripheral 
  * @note   Deinitialization can't be performed if the OPAMP configuration is locked.
  *         To unlock the configuration, perform a system reset.
  * @param  hopamp: OPAMP handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_OPAMP_DeInit(OPAMP_HandleTypeDef *hopamp)
{
  HAL_StatusTypeDef status = HAL_OK;

  /* Check the OPAMP handle allocation */
  /* Check if OPAMP locked */
  /* DeInit not allowed if calibration is ongoing */
  if((hopamp == NULL) || (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED) \
                      || (hopamp->State == HAL_OPAMP_STATE_CALIBBUSY))
  {
    status = HAL_ERROR;
  }
  else
  {
    /* Check the parameter */
    assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));

    /* Set OPAMP_CSR register to reset value */
    WRITE_REG(hopamp->Instance->CSR, OPAMP_CSR_RESET_VALUE);

    /* DeInit the low level hardware: GPIO, CLOCK and NVIC */
    HAL_OPAMP_MspDeInit(hopamp);

    /* Update the OPAMP state*/
    hopamp->State = HAL_OPAMP_STATE_RESET;
  }
  return status;
}
/**
  * @brief  DeInitializes the OPAMP peripheral 
  * @note   Deinitialization can't be performed if the OPAMP configuration is locked.
  *         To unlock the configuration, perform a system reset.
  * @param  hopamp: OPAMP handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_OPAMP_DeInit(OPAMP_HandleTypeDef* hopamp)
{
  HAL_StatusTypeDef status = HAL_OK;
  
  /* Check the OPAMP handle allocation */
  /* Check if OPAMP locked */
  /* DeInit not allowed if calibration is ongoing */
  if((hopamp == NULL) || (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED) \
                      || (hopamp->State == HAL_OPAMP_STATE_CALIBBUSY))
  {
    status = HAL_ERROR;
  }
  else
  {

    /* Check the parameter */
    assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
    
    /* Open all switches on non-inverting input, inverting input and output   */
    /* feedback.                                                              */
    CLEAR_BIT(OPAMP->CSR, __OPAMP_CSR_ALL_SWITCHES(hopamp));

    /* DeInit the low level hardware */
    HAL_OPAMP_MspDeInit(hopamp);

  /* Update the OPAMP state*/
    hopamp->State = HAL_OPAMP_STATE_RESET;
  }
  
  /* Process unlocked */
  __HAL_UNLOCK(hopamp);
  
  return status;
}
Beispiel #6
0
/**
  * @brief  Initialize some features of OPAMP instance.
  * @note   This function reset bit of calibration mode to ensure
  *         to be in functional mode, in order to have OPAMP parameters
  *         (inputs selection, ...) set with the corresponding OPAMP mode
  *         to be effective.
  * @param  OPAMPx OPAMP instance
  * @param  OPAMP_InitStruct Pointer to a @ref LL_OPAMP_InitTypeDef structure
  * @retval An ErrorStatus enumeration value:
  *          - SUCCESS: OPAMP registers are initialized
  *          - ERROR: OPAMP registers are not initialized
  */
ErrorStatus LL_OPAMP_Init(OPAMP_TypeDef *OPAMPx, LL_OPAMP_InitTypeDef *OPAMP_InitStruct)
{
  ErrorStatus status = SUCCESS;
  
  /* Check the parameters */
  assert_param(IS_OPAMP_ALL_INSTANCE(OPAMPx));
  assert_param(IS_LL_OPAMP_FUNCTIONAL_MODE(OPAMP_InitStruct->FunctionalMode));
  assert_param(IS_LL_OPAMP_INPUT_NONINVERTING(OPAMPx, OPAMP_InitStruct->InputNonInverting));
  
  /* Note: OPAMP inverting input can be used with OPAMP in mode standalone    */
  /*       or PGA with external capacitors for filtering circuit.             */
  /*       Otherwise (OPAMP in mode follower), OPAMP inverting input is       */
  /*       not used (not connected to GPIO pin).                              */
  if(OPAMP_InitStruct->FunctionalMode != LL_OPAMP_MODE_FOLLOWER)
  {
    assert_param(IS_LL_OPAMP_INPUT_INVERTING(OPAMPx, OPAMP_InitStruct->InputInverting));
  }
  
  /* Note: Hardware constraint (refer to description of this function):       */
  /*       OPAMP instance must not be locked.                                 */
  if(LL_OPAMP_IsLocked(OPAMPx) == 0U)
  {
    /* Configuration of OPAMP instance :                                      */
    /*  - Functional mode                                                     */
    /*  - Input non-inverting                                                 */
    /*  - Input inverting                                                     */
    /* Note: Bit OPAMP_CSR_CALON reset to ensure to be in functional mode.    */
    if(OPAMP_InitStruct->FunctionalMode != LL_OPAMP_MODE_FOLLOWER)
    {
      MODIFY_REG(OPAMPx->CSR,
                   OPAMP_CSR_CALON
                 | OPAMP_CSR_VMSEL
                 | OPAMP_CSR_VPSEL
                ,
                   OPAMP_InitStruct->FunctionalMode
                 | OPAMP_InitStruct->InputNonInverting
                 | OPAMP_InitStruct->InputInverting
                );
    }
    else
    {
      MODIFY_REG(OPAMPx->CSR,
                   OPAMP_CSR_CALON
                 | OPAMP_CSR_VMSEL
                 | OPAMP_CSR_VPSEL
                ,
                   LL_OPAMP_MODE_FOLLOWER
                 | OPAMP_InitStruct->InputNonInverting
                );
    }
  }
  else
  {
    /* Initialization error: OPAMP instance is locked.                        */
    status = ERROR;
  }

  return status;
}
/**
  * @brief  Initialize some features of OPAMP instance.
  * @note   This function reset bit of calibration mode to ensure
  *         to be in functional mode, in order to have OPAMP parameters
  *         (inputs selection, ...) set with the corresponding OPAMP mode
  *         to be effective.
  * @note   This function configures features of the selected OPAMP instance.
  *         Some features are also available at scope OPAMP common instance
  *         (common to several OPAMP instances).
  *         Refer to functions having argument "OPAMPxy_COMMON" as parameter.
  * @param  OPAMPx OPAMP instance
  * @param  OPAMP_InitStruct Pointer to a @ref LL_OPAMP_InitTypeDef structure
  * @retval An ErrorStatus enumeration value:
  *          - SUCCESS: OPAMP registers are initialized
  *          - ERROR: OPAMP registers are not initialized
  */
ErrorStatus LL_OPAMP_Init(OPAMP_TypeDef *OPAMPx, LL_OPAMP_InitTypeDef *OPAMP_InitStruct)
{
  /* Check the parameters */
  assert_param(IS_OPAMP_ALL_INSTANCE(OPAMPx));
  assert_param(IS_LL_OPAMP_POWER_MODE(OPAMP_InitStruct->PowerMode));
  assert_param(IS_LL_OPAMP_FUNCTIONAL_MODE(OPAMP_InitStruct->FunctionalMode));
  assert_param(IS_LL_OPAMP_INPUT_NONINVERTING(OPAMPx, OPAMP_InitStruct->InputNonInverting));

  /* Note: OPAMP inverting input can be used with OPAMP in mode standalone    */
  /*       or PGA with external capacitors for filtering circuit.             */
  /*       Otherwise (OPAMP in mode follower), OPAMP inverting input is       */
  /*       not used (not connected to GPIO pin).                              */
  if(OPAMP_InitStruct->FunctionalMode != LL_OPAMP_MODE_FOLLOWER)
  {
    assert_param(IS_LL_OPAMP_INPUT_INVERTING(OPAMPx, OPAMP_InitStruct->InputInverting));
  }

  /* Configuration of OPAMP instance :                                        */
  /*  - PowerMode                                                             */
  /*  - Functional mode                                                       */
  /*  - Input non-inverting                                                   */
  /*  - Input inverting                                                       */
  /* Note: Bit OPAMP_CSR_CALON reset to ensure to be in functional mode.      */
  if(OPAMP_InitStruct->FunctionalMode != LL_OPAMP_MODE_FOLLOWER)
  {
    MODIFY_REG(OPAMPx->CSR,
                 OPAMP_CSR_OPALPM
               | OPAMP_CSR_OPAMODE
               | OPAMP_CSR_CALON
               | OPAMP_CSR_VMSEL
               | OPAMP_CSR_VPSEL
              ,
                 (OPAMP_InitStruct->PowerMode & OPAMP_POWERMODE_CSR_BIT_MASK)
               | OPAMP_InitStruct->FunctionalMode
               | OPAMP_InitStruct->InputNonInverting
               | OPAMP_InitStruct->InputInverting
              );
  }
  else
  {
    MODIFY_REG(OPAMPx->CSR,
                 OPAMP_CSR_OPALPM
               | OPAMP_CSR_OPAMODE
               | OPAMP_CSR_CALON
               | OPAMP_CSR_VMSEL
               | OPAMP_CSR_VPSEL
              ,
                 (OPAMP_InitStruct->PowerMode & OPAMP_POWERMODE_CSR_BIT_MASK)
               | LL_OPAMP_MODE_FOLLOWER
               | OPAMP_InitStruct->InputNonInverting
               | LL_OPAMP_INPUT_INVERT_CONNECT_NO
              );
  }

  return SUCCESS;
}
/**
  * @brief  De-initialize registers of the selected OPAMP instance
  *         to their default reset values.
  * @param  OPAMPx OPAMP instance
  * @retval An ErrorStatus enumeration value:
  *          - SUCCESS: OPAMP registers are de-initialized
  *          - ERROR: OPAMP registers are not de-initialized
  */
ErrorStatus LL_OPAMP_DeInit(OPAMP_TypeDef* OPAMPx)
{
  ErrorStatus status = SUCCESS;

  /* Check the parameters */
  assert_param(IS_OPAMP_ALL_INSTANCE(OPAMPx));

  LL_OPAMP_WriteReg(OPAMPx, CSR, 0x00000000U);

  return status;
}
Beispiel #9
0
/**
  * @brief  DeInitializes the OPAMP peripheral 
  * @note   Deinitialization can be performed if the OPAMP configuration is locked.
  *         (the OPAMP lock is SW in STM32L1)
  * @param  hopamp: OPAMP handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_OPAMP_DeInit(OPAMP_HandleTypeDef* hopamp)
{
  HAL_StatusTypeDef status = HAL_OK;
  
  /* Check the OPAMP handle allocation */
  /* DeInit not allowed if calibration is ongoing */
  if((hopamp == NULL) || (hopamp->State == HAL_OPAMP_STATE_CALIBBUSY))
  {
    status = HAL_ERROR;
  }
  else
  {
    /* Check the parameter */
    assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
    
    /* Disable the selected opamp */
    SET_BIT (OPAMP->CSR, OPAMP_CSR_OPAXPD(hopamp));
    
    /* Open all switches on non-inverting input, inverting input and output   */
    /* feedback.                                                              */
    /* Note: OPAMP register CSR is written directly, independently of OPAMP   */
    /*       instance, because all OPAMP settings are dispatched in the same  */
    /*       register.                                                        */
    /*       Settings of bits for each OPAMP instances are managed case by    */
    /*       case using macro (OPAMP_CSR_S3SELX(), OPAMP_CSR_ANAWSELX(), ...) */
    CLEAR_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES(hopamp));

    /* Note: Registers and bits shared with other OPAMP instances are kept    */
    /*       unchanged, to not impact other OPAMP while operating on the      */
    /*       selected OPAMP.                                                  */
    /*       Unchanged: bit OPAMP_OTR_OT_USER (parameter "UserTrimming")      */
    /*                  bit OPAMP_CSR_AOP_RANGE (parameter "PowerSupplyRange")*/

    /* DeInit the low level hardware: GPIO, CLOCK and NVIC */
    HAL_OPAMP_MspDeInit(hopamp);

    /* Update the OPAMP state*/
    hopamp->State = HAL_OPAMP_STATE_RESET;
  }
  
  /* Process unlocked */
  __HAL_UNLOCK(hopamp);
  
  return status;
}
/**
  * @brief  DeInitializes the OPAMP peripheral 
  * @note   Deinitialization can't be performed if the OPAMP configuration is locked.
  *         To unlock the configuration, perform a system reset.
  * @param  hopamp: OPAMP handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_OPAMP_DeInit(OPAMP_HandleTypeDef *hopamp)
{
  HAL_StatusTypeDef status = HAL_OK;

  /* Check the OPAMP handle allocation */
  /* DeInit not allowed if calibration is ongoing */
  if((hopamp == NULL) || (hopamp->State == HAL_OPAMP_STATE_CALIBBUSY))
  {
    status = HAL_ERROR;
  }
  else
  {
    /* Check the parameter */
    assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));

    /* Set OPAMP_CSR register to reset value */
    WRITE_REG(hopamp->Instance->CSR, OPAMP_CSR_RESET_VALUE);

    /* DeInit the low level hardware: GPIO, CLOCK and NVIC */
    /* When OPAMP is locked, unlocking can be achieved thanks to */ 
    /* __HAL_RCC_SYSCFG_CLK_DISABLE() call within HAL_OPAMP_MspDeInit */
    /* Note that __HAL_RCC_SYSCFG_CLK_DISABLE() also disables comparator */
    HAL_OPAMP_MspDeInit(hopamp);

    if (OPAMP_CSR_RESET_VALUE == hopamp->Instance->CSR)
    {
      /* Update the OPAMP state */
      hopamp->State = HAL_OPAMP_STATE_RESET;
    }
    else /* RESET STATE */ 
    {
      /* DeInit not complete */ 
      /* It can be the case if OPAMP was formerly locked */ 
      status = HAL_ERROR;

      /* The OPAMP state is NOT updated */      
    }
  }
  
  /* Process unlocked */
  __HAL_UNLOCK(hopamp);
  
  return status;
}
Beispiel #11
0
/**
  * @brief  De-initialize registers of the selected OPAMP instance
  *         to their default reset values.
  * @note   If comparator is locked, de-initialization by software is
  *         not possible.
  *         The only way to unlock the comparator is a device hardware reset.
  * @param  OPAMPx OPAMP instance
  * @retval An ErrorStatus enumeration value:
  *          - SUCCESS: OPAMP registers are de-initialized
  *          - ERROR: OPAMP registers are not de-initialized
  */
ErrorStatus LL_OPAMP_DeInit(OPAMP_TypeDef* OPAMPx)
{
  ErrorStatus status = SUCCESS;
  
  /* Check the parameters */
  assert_param(IS_OPAMP_ALL_INSTANCE(OPAMPx));
  
  /* Note: Hardware constraint (refer to description of this function):       */
  /*       OPAMP instance must not be locked.                                 */
  if(LL_OPAMP_IsLocked(OPAMPx) == 0U)
  {
  LL_OPAMP_WriteReg(OPAMPx, CSR, 0x00000000U);
  }
  else
  {
    /* OPAMP instance is locked: de-initialization by software is              */
    /* not possible.                                                           */
    /* The only way to unlock the OPAMP is a device hardware reset.            */
    status = ERROR;
  }
  
  return status;
}
HAL_StatusTypeDef HAL_OPAMP_SelfCalibrate(OPAMP_HandleTypeDef *hopamp)
{ 

  HAL_StatusTypeDef status = HAL_OK;
  
  uint32_t trimmingvaluen = 0;
  uint32_t trimmingvaluep = 0;
  uint32_t delta;
  
  /* Check the OPAMP handle allocation */
  /* Check if OPAMP locked */
  if((hopamp == NULL) || (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED))
  {
    status = HAL_ERROR;
  }
  else
  {
  
    /* Check if OPAMP in calibration mode and calibration not yet enable */
    if(hopamp->State ==  HAL_OPAMP_STATE_READY)
    {
      /* Check the parameter */
      assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));

      /* Set Calibration mode */
      /* Non-inverting input connected to calibration reference voltage. */
      SET_BIT(hopamp->Instance->CSR, OPAMP_CSR_FORCEVP);

      /*  user trimming values are used for offset calibration */
      SET_BIT(hopamp->Instance->CSR, OPAMP_CSR_USERTRIM);
      
      /* Enable calibration */
      SET_BIT (hopamp->Instance->CSR, OPAMP_CSR_CALON);
  
      /* 1st calibration - N */
      /* Select 90% VREF */
      MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_90VDDA);
      
      /* Enable the selected opamp */
      SET_BIT (hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
      
      /* Init trimming counter */    
      /* Medium value */
      trimmingvaluen = 16; 
      delta = 8;
      
      while (delta != 0)
      {
        /* Set candidate trimming */
        MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen<<OPAMP_INPUT_INVERTING);
              
        /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */ 
        /* Offset trim time: during calibration, minimum time needed between */
        /* two steps to have 1 mV accuracy */
        HAL_Delay(2);

        if ((hopamp->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
        { 
          /* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
          trimmingvaluen += delta;
        }
        else
        {
          /* OPAMP_CSR_OUTCAL is LOW try lower trimming */
          trimmingvaluen -= delta;
        }
                      
        delta >>= 1;
      }

      /* Still need to check if righ calibration is current value or un step below */
      /* Indeed the first value that causes the OUTCAL bit to change from 1 to 0  */
      MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen<<OPAMP_INPUT_INVERTING);
      
       /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */ 
       /* Offset trim time: during calibration, minimum time needed between */
       /* two steps to have 1 mV accuracy */
       HAL_Delay(2);
      
      if ((hopamp->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET) 
      { 
        /* OPAMP_CSR_OUTCAL is actually one value more */
        trimmingvaluen++;
        /* Set right trimming */
        MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen<<OPAMP_INPUT_INVERTING);
      }
       
      /* 2nd calibration - P */
      /* Select 10% VREF */
      MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_10VDDA);
      
      /* Init trimming counter */    
      /* Medium value */
      trimmingvaluep = 16; 
      delta = 8;
      
      while (delta != 0)
      {
        /* Set candidate trimming */
        MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep<<OPAMP_INPUT_NONINVERTING);
               
        /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */ 
        /* Offset trim time: during calibration, minimum time needed between */
        /* two steps to have 1 mV accuracy */
        HAL_Delay(2);

        if ((hopamp->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET) 
        { 
          /* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
          trimmingvaluep += delta;
        }
        else
        {
          trimmingvaluep -= delta;
        }
                      
        delta >>= 1;
      }
      
      /* Still need to check if righ calibration is current value or un step below */
      /* Indeed the first value that causes the OUTCAL bit to change from 1 to 0 */
      /* Set candidate trimming */
      MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep<<OPAMP_INPUT_NONINVERTING);

       /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */ 
       /* Offset trim time: during calibration, minimum time needed between */
       /* two steps to have 1 mV accuracy */
       HAL_Delay(2);
      
      if ((hopamp->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
      { 
        /* OPAMP_CSR_OUTCAL is actually one value more */
        trimmingvaluep++;
        /* Set right trimming */
        MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep<<OPAMP_INPUT_NONINVERTING);
      }
           
      /* Disable calibration */
      CLEAR_BIT (hopamp->Instance->CSR, OPAMP_CSR_CALON);

      /* Disable the OPAMP */
      CLEAR_BIT (hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
      
      /* Set operating mode  */
      /* Non-inverting input connected to calibration reference voltage. */
      CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_FORCEVP);
            
      /* Self calibration is successful  */
      /* Store calibration(user timming) results in init structure. */

      /* Write calibration result N */
      hopamp->Init.TrimmingValueN = trimmingvaluen;
     
      /* Write calibration result P */
      hopamp->Init.TrimmingValueP = trimmingvaluep;

      /* Select user timming mode */      
      /* And updated with calibrated settings */
      hopamp->Init.UserTrimming = OPAMP_TRIMMING_USER;
      MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep<<OPAMP_INPUT_NONINVERTING);
      MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen<<OPAMP_INPUT_INVERTING);
    }

    else
    {
Beispiel #13
0
/**
  * @brief  Initializes the OPAMP according to the specified
  *         parameters in the OPAMP_InitTypeDef and create the associated handle.
  * @note   If the selected opamp is locked, initialization can't be performed.
  *         To unlock the configuration, perform a system reset.
  * @param  hopamp: OPAMP handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_OPAMP_Init(OPAMP_HandleTypeDef* hopamp)
{ 
  HAL_StatusTypeDef status = HAL_OK;
  uint32_t tmp_csr = 0;       /* Temporary variable to update register CSR, except bits ANAWSSELx, S7SEL2, OPA_RANGE, OPAxCALOUT */
  
  /* Check the OPAMP handle allocation and lock status */
  /* Init not allowed if calibration is ongoing */
  if((hopamp == NULL) || (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
                      || (hopamp->State == HAL_OPAMP_STATE_CALIBBUSY) )
  {
    status = HAL_ERROR;
  }
  else
  {
    /* Check the parameter */
    assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
       
    /* Set OPAMP parameters */
    assert_param(IS_OPAMP_POWER_SUPPLY_RANGE(hopamp->Init.PowerSupplyRange));
    assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode));
    assert_param(IS_OPAMP_FUNCTIONAL_NORMALMODE(hopamp->Init.Mode));
    assert_param(IS_OPAMP_NONINVERTING_INPUT_CHECK_INSTANCE(hopamp, hopamp->Init.NonInvertingInput));
    assert_param(IS_OPAMP_TRIMMING(hopamp->Init.UserTrimming));
    
    if (hopamp->Init.Mode != OPAMP_FOLLOWER_MODE)
    {
      assert_param(IS_OPAMP_INVERTING_INPUT(hopamp->Init.InvertingInput));
    }
    
    if (hopamp->Init.UserTrimming == OPAMP_TRIMMING_USER)
    {
      if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
      {
        assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueP));
        assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueN));
      }
      else
      {
        assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValuePLowPower));
        assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueNLowPower));
      }
    }
    
    if(hopamp->State == HAL_OPAMP_STATE_RESET)
    {
      /* Allocate lock resource and initialize it */
      hopamp->Lock = HAL_UNLOCKED;
    }

    /* Call MSP init function */
    HAL_OPAMP_MspInit(hopamp);
    
    /* Set OPAMP parameters                                                   */
    /* - Set internal switches in function of:                                */
    /*   - OPAMP selected mode: standalone or follower.                       */
    /*   - Non-inverting input connection                                     */
    /*   - Inverting input connection                                         */
    /* - Set power supply range                                               */
    /* - Set power mode and associated calibration parameters                 */
    
    /* Get OPAMP CSR register into temporary variable */
    /* Note: OPAMP register CSR is written directly, independently of OPAMP   */
    /*       instance, because all OPAMP settings are dispatched in the same  */
    /*       register.                                                        */
    /*       Settings of bits for each OPAMP instances are managed case by    */
    /*       case using macro (OPAMP_CSR_S3SELX(), OPAMP_CSR_ANAWSELX(), ...) */
    tmp_csr = OPAMP->CSR;
    
    /* Open all switches on non-inverting input, inverting input and output   */
    /* feedback.                                                              */
    CLEAR_BIT(tmp_csr, OPAMP_CSR_ALL_SWITCHES(hopamp));
    
    /* Set internal switches in function of OPAMP mode selected: standalone   */
    /* or follower.                                                           */
    /* If follower mode is selected, feedback switch S3 is closed and         */
    /* inverting inputs switches are let opened.                              */
    /* If standalone mode is selected, feedback switch S3 is let opened and   */
    /* the selected inverting inputs switch is closed.                        */
    if (hopamp->Init.Mode == OPAMP_FOLLOWER_MODE)
    {
      /* Follower mode: Close switches S3 and SanB */
      SET_BIT(tmp_csr, OPAMP_CSR_S3SELX(hopamp));
    }
    else
    {
      /* Set internal switches in function of inverting input selected:       */
      /* Close switch to connect OPAMP inverting input to the selected        */
      /* input: dedicated IO pin or alternative IO pin available on some      */
      /* device packages.                                                     */
      if (hopamp->Init.InvertingInput == OPAMP_INVERTINGINPUT_IO0)
      {
        /* Close switch to connect OPAMP non-inverting input to               */
        /* dedicated IO pin low-leakage.                                      */
        SET_BIT(tmp_csr, OPAMP_CSR_S4SELX(hopamp));
      }
      else
      {
        /* Close switch to connect OPAMP inverting input to alternative       */
        /* IO pin available on some device packages.                          */
        SET_BIT(tmp_csr, OPAMP_CSR_ANAWSELX(hopamp));
      }
    }
    
    /* Set internal switches in function of non-inverting input selected:     */
    /* Close switch to connect OPAMP non-inverting input to the selected      */
    /* input: dedicated IO pin or DAC channel.                                */
    if (hopamp->Init.NonInvertingInput == OPAMP_NONINVERTINGINPUT_IO0)
    {
      /* Close switch to connect OPAMP non-inverting input to                 */
      /* dedicated IO pin low-leakage.                                        */
      SET_BIT(tmp_csr, OPAMP_CSR_S5SELX(hopamp));
    }
    else if (hopamp->Init.NonInvertingInput == OPAMP_NONINVERTINGINPUT_DAC_CH1)
    {
      
      /* Particular case for connection to DAC channel 1:                     */
      /* OPAMP_NONINVERTINGINPUT_DAC_CH1 available on OPAMP1 and OPAMP2 only  */
      /* (OPAMP3 availability depends on device category).                    */
      if ((hopamp->Instance == OPAMP1) || (hopamp->Instance == OPAMP2))
      {
        /* Close switch to connect OPAMP non-inverting input to               */
        /* DAC channel 1.                                                     */
        SET_BIT(tmp_csr, OPAMP_CSR_S6SELX(hopamp));
      }
      else
      {
        /* Set HAL status to error if another OPAMP instance as OPAMP1 or     */
        /* OPAMP2 is intended to be connected to DAC channel 2.               */
        status = HAL_ERROR;
      }
    }
    else /* if (hopamp->Init.NonInvertingInput ==                             */
         /*     OPAMP_NONINVERTINGINPUT_DAC_CH2  )                            */
    {
      /* Particular case for connection to DAC channel 2:                     */
      /* OPAMP_NONINVERTINGINPUT_DAC_CH2 available on OPAMP2 and OPAMP3 only  */
      /* (OPAMP3 availability depends on device category).                    */
      if (hopamp->Instance == OPAMP2)
      {
        /* Close switch to connect OPAMP non-inverting input to               */
        /* DAC channel 2.                                                     */
        SET_BIT(tmp_csr, OPAMP_CSR_S7SEL2);
      }
      /* If OPAMP3 is selected (if available) */
      else if (hopamp->Instance != OPAMP1)
      {
        /* Close switch to connect OPAMP non-inverting input to               */
        /* DAC channel 2.                                                     */
        SET_BIT(tmp_csr, OPAMP_CSR_S6SELX(hopamp));
      }
      else
      {
        /* Set HAL status to error if another OPAMP instance as OPAMP2 or     */
        /* OPAMP3 (if available) is intended to be connected to DAC channel 2.*/
        status = HAL_ERROR;
      }
    }
    
    /* Continue OPAMP configuration if settings of switches are correct */
    if (status != HAL_ERROR)
    {
      /* Set power mode and associated calibration parameters */
      if (hopamp->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
      {
        /* Set normal mode */
        CLEAR_BIT(tmp_csr, OPAMP_CSR_OPAXLPM(hopamp));
        
        if (hopamp->Init.UserTrimming == OPAMP_TRIMMING_USER)
        {
          /* Set calibration mode (factory or user) and values for            */
          /* transistors differential pair high (PMOS) and low (NMOS) for     */
          /* normal mode.                                                     */
          MODIFY_REG(OPAMP->OTR, OPAMP_OTR_OT_USER                                                                     |
                                 OPAMP_OFFSET_TRIM_SET(hopamp, OPAMP_FACTORYTRIMMING_N, OPAMP_TRIM_VALUE_MASK)       |
                                 OPAMP_OFFSET_TRIM_SET(hopamp, OPAMP_FACTORYTRIMMING_P, OPAMP_TRIM_VALUE_MASK)        ,
                                 hopamp->Init.UserTrimming                                                             |
                                 OPAMP_OFFSET_TRIM_SET(hopamp, OPAMP_FACTORYTRIMMING_N, hopamp->Init.TrimmingValueN) |
                                 OPAMP_OFFSET_TRIM_SET(hopamp, OPAMP_FACTORYTRIMMING_P, hopamp->Init.TrimmingValueP)  );
        }
        else
        {
          /* Set calibration mode to factory */
          CLEAR_BIT(OPAMP->OTR, OPAMP_OTR_OT_USER);
        }
        
      }
      else
      {
        /* Set low power mode */
        SET_BIT(tmp_csr, OPAMP_CSR_OPAXLPM(hopamp));
        
        if (hopamp->Init.UserTrimming == OPAMP_TRIMMING_USER)
        {
          /* Set calibration mode to user trimming */
          SET_BIT(OPAMP->OTR, OPAMP_OTR_OT_USER);
          
          /* Set values for transistors differential pair high (PMOS) and low */
          /* (NMOS) for low power mode.                                       */
          MODIFY_REG(OPAMP->LPOTR, OPAMP_OFFSET_TRIM_SET(hopamp, OPAMP_FACTORYTRIMMING_N, OPAMP_TRIM_VALUE_MASK)               |
                                   OPAMP_OFFSET_TRIM_SET(hopamp, OPAMP_FACTORYTRIMMING_P, OPAMP_TRIM_VALUE_MASK)                ,
                                   OPAMP_OFFSET_TRIM_SET(hopamp, OPAMP_FACTORYTRIMMING_N, hopamp->Init.TrimmingValueNLowPower) |
                                   OPAMP_OFFSET_TRIM_SET(hopamp, OPAMP_FACTORYTRIMMING_P, hopamp->Init.TrimmingValuePLowPower)  );
        }
        else
        {
          /* Set calibration mode to factory trimming */
          CLEAR_BIT(OPAMP->OTR, OPAMP_OTR_OT_USER);
        }
        
      }
      
      
      /* Configure the power supply range */
      MODIFY_REG(tmp_csr, OPAMP_CSR_AOP_RANGE,
                          hopamp->Init.PowerSupplyRange);
      
      /* Set OPAMP CSR register from temporary variable */
      /* This allows to apply all changes on one time, in case of update on   */
      /* the fly with OPAMP previously set and running:                       */
      /*  - to avoid hazardous transient switches settings (risk of short     */
      /*    circuit)                                                          */
      /*  - to avoid interruption of input signal                             */
      OPAMP->CSR = tmp_csr;

                
      /* Update the OPAMP state */
      /* If coming from state reset: Update from state RESET to state READY */
      if (hopamp->State == HAL_OPAMP_STATE_RESET)
      {
        hopamp->State = HAL_OPAMP_STATE_READY;
      }
      /* else: OPAMP state remains READY or BUSY state (no update) */
    }
  }
  
  return status;
}
/**
  * @brief  Initializes the OPAMP according to the specified
  *         parameters in the OPAMP_InitTypeDef and create the associated handle.
  * @note   If the selected opamp is locked, initialization can't be performed.
  *         To unlock the configuration, perform a system reset.
  * @param  hopamp: OPAMP handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_OPAMP_Init(OPAMP_HandleTypeDef *hopamp)

{ 
  HAL_StatusTypeDef status = HAL_OK;

  /* Check the OPAMP handle allocation and lock status */
  /* Init not allowed if calibration is ongoing */
  if((hopamp == NULL) || (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED) \
                      || (hopamp->State == HAL_OPAMP_STATE_CALIBBUSY))
  {
    return HAL_ERROR;
  }
  else
  {
      
    /* Check the parameter */
    assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
       
    /* Set OPAMP parameters */
    assert_param(IS_OPAMP_FUNCTIONAL_NORMALMODE(hopamp->Init.Mode));
    assert_param(IS_OPAMP_NONINVERTING_INPUT(hopamp->Init.NonInvertingInput));
    if ((hopamp->Init.Mode) == OPAMP_STANDALONE_MODE)
    {
      assert_param(IS_OPAMP_INVERTING_INPUT(hopamp->Init.InvertingInput));
    }
  
    assert_param(IS_OPAMP_TIMERCONTROLLED_MUXMODE(hopamp->Init.TimerControlledMuxmode));

    if ((hopamp->Init.TimerControlledMuxmode) == OPAMP_TIMERCONTROLLEDMUXMODE_ENABLE)
    {
      assert_param(IS_OPAMP_SEC_NONINVERTINGINPUT(hopamp->Init.NonInvertingInputSecondary));
      if ((hopamp->Init.Mode) == OPAMP_STANDALONE_MODE)
      {
        assert_param(IS_OPAMP_SEC_INVERTINGINPUT(hopamp->Init.InvertingInputSecondary));
      }
    }
    
    if ((hopamp->Init.Mode) == OPAMP_PGA_MODE)
    {
      assert_param(IS_OPAMP_PGACONNECT(hopamp->Init.PgaConnect));
      assert_param(IS_OPAMP_PGA_GAIN(hopamp->Init.PgaGain));
    }
    
    assert_param(IS_OPAMP_TRIMMING(hopamp->Init.UserTrimming)); 
    if ((hopamp->Init.UserTrimming) == OPAMP_TRIMMING_USER)
    {
      assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueP));
      assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueN));
    }
 
    /* Init SYSCFG and the low level hardware to access opamp */
    __HAL_RCC_SYSCFG_CLK_ENABLE();
    
    if(hopamp->State == HAL_OPAMP_STATE_RESET)
    {
      /* Allocate lock resource and initialize it */
      hopamp->Lock = HAL_UNLOCKED;
    }

    /* Call MSP init function */
    HAL_OPAMP_MspInit(hopamp);
                                          
    /* Set OPAMP parameters */
    /*     Set  bits according to hopamp->hopamp->Init.Mode value                                 */
    /*     Set  bits according to hopamp->hopamp->Init.InvertingInput value                       */
    /*     Set  bits according to hopamp->hopamp->Init.NonInvertingInput value                    */
    /*     Set  bits according to hopamp->hopamp->Init.TimerControlledMuxmode value               */
    /*     Set  bits according to hopamp->hopamp->Init.InvertingInputSecondary  value             */
    /*     Set  bits according to hopamp->hopamp->Init.NonInvertingInputSecondary value           */
    /*     Set  bits according to hopamp->hopamp->Init.PgaConnect value                           */
    /*     Set  bits according to hopamp->hopamp->Init.PgaGain value                              */
    /*     Set  bits according to hopamp->hopamp->Init.UserTrimming value                         */
    /*     Set  bits according to hopamp->hopamp->Init.TrimmingValueP value                       */
    /*     Set  bits according to hopamp->hopamp->Init.TrimmingValueN value                       */
    
    
    /* check if OPAMP_PGA_MODE & in Follower mode */
    /*   - InvertingInput                         */
    /*   - InvertingInputSecondary                */
    /* are Not Applicable                         */
    
    if ((hopamp->Init.Mode == OPAMP_PGA_MODE) || (hopamp->Init.Mode == OPAMP_FOLLOWER_MODE))
    {
      MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_UPDATE_PARAMETERS_INIT_MASK, \
                                        hopamp->Init.Mode | \
                                        hopamp->Init.NonInvertingInput | \
                                        hopamp->Init.TimerControlledMuxmode | \
                                        hopamp->Init.NonInvertingInputSecondary  | \
                                        hopamp->Init.PgaConnect | \
                                        hopamp->Init.PgaGain | \
                                        hopamp->Init.UserTrimming | \
                                        (hopamp->Init.TrimmingValueP << OPAMP_INPUT_NONINVERTING) | \
                                        (hopamp->Init.TrimmingValueN << OPAMP_INPUT_INVERTING));  

    }    
    else /* OPAMP_STANDALONE_MODE */
    {
      MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_UPDATE_PARAMETERS_INIT_MASK, \
                                        hopamp->Init.Mode | \
                                        hopamp->Init.InvertingInput    | \
                                        hopamp->Init.NonInvertingInput | \
                                        hopamp->Init.TimerControlledMuxmode | \
                                        hopamp->Init.InvertingInputSecondary  | \
                                        hopamp->Init.NonInvertingInputSecondary  | \
                                        hopamp->Init.PgaConnect | \
                                        hopamp->Init.PgaGain | \
                                        hopamp->Init.UserTrimming | \
                                        (hopamp->Init.TrimmingValueP << OPAMP_INPUT_NONINVERTING) | \
                                        (hopamp->Init.TrimmingValueN << OPAMP_INPUT_INVERTING));     
    } 
    
    /* Update the OPAMP state*/
    if (hopamp->State == HAL_OPAMP_STATE_RESET)
    {
      /* From RESET state to READY State */
    hopamp->State = HAL_OPAMP_STATE_READY;
    }
    /* else: remain in READY or BUSY state (no update) */
  
    return status;
    }
}
/**
  * @brief  Run the self calibration of the 3 OPAMPs in parallel.
  * @note   Trimming values (PMOS & NMOS) are updated and user trimming is 
  *         enabled is calibration is succesful.
  * @note   Calibration is performed in the mode specified in OPAMP init
  *         structure (mode normal or low-power). To perform calibration for
  *         both modes, repeat this function twice after OPAMP init structure
  *         accordingly updated.
  * @note   Calibration runs about 10 ms (5 dichotmy steps, repeated for P  
  *         and N transistors: 10 steps with 1 ms for each step).
  * @param  hopamp1 handle
  * @param  hopamp2 handle
  * @param  hopamp3 handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef *hopamp1, OPAMP_HandleTypeDef *hopamp2, OPAMP_HandleTypeDef *hopamp3)
{
  HAL_StatusTypeDef status = HAL_OK;
  
  uint32_t* opamp1_trimmingvalue = 0;
  uint32_t opamp1_trimmingvaluen = 0;
  uint32_t opamp1_trimmingvaluep = 0;
  
  uint32_t* opamp2_trimmingvalue = 0;
  uint32_t opamp2_trimmingvaluen = 0;
  uint32_t opamp2_trimmingvaluep = 0;
  
  uint32_t* opamp3_trimmingvalue = 0;
  uint32_t opamp3_trimmingvaluen = 0;
  uint32_t opamp3_trimmingvaluep = 0;
  
  uint32_t trimming_diff_pair = 0;          /* Selection of differential transistors pair high or low */

  __IO uint32_t* tmp_opamp1_reg_trimming;   /* Selection of register of trimming depending on power mode: OTR or LPOTR */
  __IO uint32_t* tmp_opamp2_reg_trimming;
  __IO uint32_t* tmp_opamp3_reg_trimming;
  uint32_t tmp_opamp1_otr_otuser = 0;       /* Selection of bit OPAMP_OTR_OT_USER depending on trimming register pointed: OTR or LPOTR */
  uint32_t tmp_opamp2_otr_otuser = 0;
  uint32_t tmp_opamp3_otr_otuser = 0;
  
  uint32_t tmp_Opa1calout_DefaultSate = 0;  /* Bit OPAMP_CSR_OPA1CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
  uint32_t tmp_Opa2calout_DefaultSate = 0;  /* Bit OPAMP_CSR_OPA2CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
  uint32_t tmp_Opa3calout_DefaultSate = 0;  /* Bit OPAMP_CSR_OPA3CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */

  uint32_t tmp_OpaxSwitchesContextBackup = 0;
  
  uint8_t trimming_diff_pair_iteration_count = 0;       /* For calibration loop algorithm: to repeat the calibration loop for both differential transistors pair high and low */
  uint8_t delta = 0;                                    /* For calibration loop algorithm: Variable for dichotomy steps value */
  uint8_t final_step_check = 0;                         /* For calibration loop algorithm: Flag for additional check of last trimming step */
  
  /* Check the OPAMP handle allocation */
  /* Check if OPAMP locked */
  if((hopamp1 == NULL) || (hopamp1->State == HAL_OPAMP_STATE_BUSYLOCKED) ||
     (hopamp2 == NULL) || (hopamp2->State == HAL_OPAMP_STATE_BUSYLOCKED) ||
     (hopamp3 == NULL) || (hopamp3->State == HAL_OPAMP_STATE_BUSYLOCKED)   ) 
  {
    status = HAL_ERROR;
  }
  else
  {
  
    /* Check if OPAMP in calibration mode and calibration not yet enable */
    if((hopamp1->State == HAL_OPAMP_STATE_READY) &&
       (hopamp2->State == HAL_OPAMP_STATE_READY) &&
       (hopamp3->State == HAL_OPAMP_STATE_READY)   )
    {
      /* Check the parameter */
      assert_param(IS_OPAMP_ALL_INSTANCE(hopamp1->Instance));
      assert_param(IS_OPAMP_ALL_INSTANCE(hopamp2->Instance));
      assert_param(IS_OPAMP_ALL_INSTANCE(hopamp3->Instance));
      assert_param(IS_OPAMP_POWERMODE(hopamp1->Init.PowerMode));
      assert_param(IS_OPAMP_POWERMODE(hopamp2->Init.PowerMode));
      assert_param(IS_OPAMP_POWERMODE(hopamp3->Init.PowerMode));
      
      /* Update OPAMP state */
      hopamp1->State = HAL_OPAMP_STATE_CALIBBUSY;
      hopamp2->State = HAL_OPAMP_STATE_CALIBBUSY;
      hopamp3->State = HAL_OPAMP_STATE_CALIBBUSY;
      
      /* Backup of switches configuration to restore it at the end of the     */
      /* calibration.                                                         */
      tmp_OpaxSwitchesContextBackup = READ_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES_ALL_OPAMPS);
      
      /* Open all switches on non-inverting input, inverting input and output */
      /* feedback.                                                            */
      CLEAR_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES_ALL_OPAMPS);
      
      /* Set calibration mode to user programmed trimming values */
      SET_BIT(OPAMP->OTR, OPAMP_OTR_OT_USER);
      
      /* Select trimming settings depending on power mode */
      if (hopamp1->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
      {
        tmp_opamp1_otr_otuser = OPAMP_OTR_OT_USER;
        tmp_opamp1_reg_trimming = &OPAMP->OTR;
      }
      else
      {
        tmp_opamp1_otr_otuser = 0x00000000;
        tmp_opamp1_reg_trimming = &OPAMP->LPOTR;
      }
      
      if (hopamp2->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
      {
        tmp_opamp2_otr_otuser = OPAMP_OTR_OT_USER;
        tmp_opamp2_reg_trimming = &OPAMP->OTR;
      }
      else
      {
        tmp_opamp2_otr_otuser = 0x00000000;
        tmp_opamp2_reg_trimming = &OPAMP->LPOTR;
      }
      
      if (hopamp3->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
      {
        tmp_opamp3_otr_otuser = OPAMP_OTR_OT_USER;
        tmp_opamp3_reg_trimming = &OPAMP->OTR;
      }
      else
      {
        tmp_opamp3_otr_otuser = 0x00000000;
        tmp_opamp3_reg_trimming = &OPAMP->LPOTR;
      }
      
      /* Enable the selected opamp */
      CLEAR_BIT (OPAMP->CSR, OPAMP_CSR_OPAXPD_ALL);
      
      /* Perform trimming for both differential transistors pair high and low */
      for (trimming_diff_pair_iteration_count = 0; trimming_diff_pair_iteration_count <=1; trimming_diff_pair_iteration_count++)
      {
        if (trimming_diff_pair_iteration_count == 0)
        {
          /* Calibration of transistors differential pair high (NMOS) */
          trimming_diff_pair = OPAMP_FACTORYTRIMMING_N;
          opamp1_trimmingvalue = &opamp1_trimmingvaluen;
          opamp2_trimmingvalue = &opamp2_trimmingvaluen;
          opamp3_trimmingvalue = &opamp3_trimmingvaluen;
          
          /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value   */
          /* is 00000b. Used to detect the bit toggling during trimming.      */
          tmp_Opa1calout_DefaultSate = RESET;
          tmp_Opa2calout_DefaultSate = RESET;
          tmp_Opa3calout_DefaultSate = RESET;
          
          /* Enable calibration for N differential pair */
          MODIFY_REG(OPAMP->CSR, OPAMP_CSR_OPAXCAL_L_ALL,
                                 OPAMP_CSR_OPAXCAL_H_ALL);
        }
        else /* (trimming_diff_pair_iteration_count == 1) */
        {
          /* Calibration of transistors differential pair low (PMOS) */
          trimming_diff_pair = OPAMP_FACTORYTRIMMING_P;
          opamp1_trimmingvalue = &opamp1_trimmingvaluep;
          opamp2_trimmingvalue = &opamp2_trimmingvaluep;
          opamp3_trimmingvalue = &opamp3_trimmingvaluep;
          
          /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value   */
          /* is 00000b. Used to detect the bit toggling during trimming.      */
          tmp_Opa1calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp1);
          tmp_Opa2calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp2);
          tmp_Opa3calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp3);
          
          /* Enable calibration for P differential pair */
          MODIFY_REG(OPAMP->CSR, OPAMP_CSR_OPAXCAL_H_ALL,
                                 OPAMP_CSR_OPAXCAL_L_ALL);
        }
        
      
        /* Perform calibration parameter search by dichotomy sweep */
        /*  - Delta initial value 16: for 5 dichotomy steps: 16 for the       */
        /*    initial range, then successive delta sweeps (8, 4, 2, 1).       */
        /*    can extend the search range to +/- 15 units.                    */
        /*  - Trimming initial value 15: search range will go from 0 to 30    */
        /*    (Trimming value 31 is forbidden).                               */
        /* Note: After dichotomy sweep, the trimming result is determined.    */
        /*       However, the final trimming step is deduced from previous    */
        /*       trimming steps tested but is not effectively tested.         */
        /*       An additional test step (using variable "final_step_check")  */
        /*       allow to Test the final trimming step.                       */
        *opamp1_trimmingvalue = 15;
        *opamp2_trimmingvalue = 15;
        *opamp3_trimmingvalue = 15;
        delta = 16;
        
        while ((delta != 0) || (final_step_check == 1))
        {
          /* Set candidate trimming */
          MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
                                               OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, *opamp1_trimmingvalue) | tmp_opamp1_otr_otuser);

          MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
                                               OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, *opamp2_trimmingvalue) | tmp_opamp2_otr_otuser);

          MODIFY_REG(*tmp_opamp3_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
                                               OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, *opamp3_trimmingvalue) | tmp_opamp3_otr_otuser);
          
          /* Offset trimming time: during calibration, minimum time needed    */
          /* between two steps to have 1 mV accuracy.                         */
          HAL_Delay(OPAMP_TRIMMING_DELAY);
          
          /* Set flag for additional check of last trimming step equal to     */
          /* dichotomy step before its division by 2 (equivalent to previous  */
          /* value of dichotomy step).                                        */
          final_step_check = delta;
          
          /* Divide range by 2 to continue dichotomy sweep */
          delta >>= 1;
          
          /* Set trimming values for next iteration in function of trimming   */
          /* result toggle (versus initial state).                            */
          /* Trimming values update with dichotomy delta of previous          */
          /* iteration.                                                       */
          /* Note: on the last trimming loop, delta is equal to 0 and         */
          /*       therefore has no effect.                                   */
          if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp1)) != tmp_Opa1calout_DefaultSate)
          {
            /* If calibration output is has toggled, try lower trimming */
            *opamp1_trimmingvalue -= delta;
          }
          else
          {
            /* If calibration output is has not toggled, try higher trimming */
            *opamp1_trimmingvalue += delta;
          }
          
          if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp2)) != tmp_Opa2calout_DefaultSate)
          {
            /* If calibration output is has toggled, try lower trimming */
            *opamp2_trimmingvalue -= delta;
          }
          else
          {
            /* If calibration output is has not toggled, try higher trimming */
            *opamp2_trimmingvalue += delta;
          }

          if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp3)) != tmp_Opa3calout_DefaultSate)
          {
            /* If calibration output is has toggled, try lower trimming */
            *opamp3_trimmingvalue -= delta;
          }
          else
          {
            /* If calibration output is has not toggled, try higher trimming */
            *opamp3_trimmingvalue += delta;
          }
        }
        
        /* Check trimming result of the selected step and perform final fine  */
        /* trimming.                                                          */
        /*  - If calibration output is has toggled: the current step is       */
        /*    already optimized.                                              */
        /*  - If calibration output is has not toggled: the current step can  */
        /*    be optimized by incrementing it of one step.                    */
        if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp1)) == tmp_Opa1calout_DefaultSate)
        {
          *opamp1_trimmingvalue += 1;
          
          /* Set final fine trimming */
          MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
                                               OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, *opamp1_trimmingvalue) | tmp_opamp1_otr_otuser);
        }
        if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp2)) == tmp_Opa2calout_DefaultSate)
        {
          *opamp2_trimmingvalue += 1;
          
          /* Set final fine trimming */
          MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
                                               OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, *opamp2_trimmingvalue) | tmp_opamp2_otr_otuser);
        }
        if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp3)) == tmp_Opa3calout_DefaultSate)
        {
          *opamp3_trimmingvalue += 1;
          
          /* Set final fine trimming */
          MODIFY_REG(*tmp_opamp3_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
                                               OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, *opamp3_trimmingvalue) | tmp_opamp3_otr_otuser);
        }
        
      }
       

      /* Disable calibration for P and N differential pairs */
      /* Disable the selected opamp */
      CLEAR_BIT (OPAMP->CSR, (OPAMP_CSR_OPAXCAL_H_ALL | 
                              OPAMP_CSR_OPAXCAL_L_ALL |
                              OPAMP_CSR_OPAXPD_ALL     ));
      
      /* Backup of switches configuration to restore it at the end of the     */
      /* calibration.                                                         */
      SET_BIT(OPAMP->CSR, tmp_OpaxSwitchesContextBackup);
      
      /* Self calibration is successful */
      /* Store calibration (user trimming) results in init structure. */
      
      /* Set user trimming mode */  
      hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER;
      hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER;
      hopamp3->Init.UserTrimming = OPAMP_TRIMMING_USER;
      
      /* Affect calibration parameters depending on mode normal/low power */
      if (hopamp1->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
      {
        /* Write calibration result N */
        hopamp1->Init.TrimmingValueN = opamp1_trimmingvaluen;
        /* Write calibration result P */
        hopamp1->Init.TrimmingValueP = opamp1_trimmingvaluep;
      }
      else
      {
        /* Write calibration result N */
        hopamp1->Init.TrimmingValueNLowPower = opamp1_trimmingvaluen;
        /* Write calibration result P */
        hopamp1->Init.TrimmingValuePLowPower = opamp1_trimmingvaluep;
      }
      
      if (hopamp2->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
      {
        /* Write calibration result N */
        hopamp2->Init.TrimmingValueN = opamp2_trimmingvaluen;
        /* Write calibration result P */
        hopamp2->Init.TrimmingValueP = opamp2_trimmingvaluep;
      }
      else
      {
        /* Write calibration result N */
        hopamp2->Init.TrimmingValueNLowPower = opamp2_trimmingvaluen;
        /* Write calibration result P */
        hopamp2->Init.TrimmingValuePLowPower = opamp2_trimmingvaluep;
      }
      
      if (hopamp3->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
      {
        /* Write calibration result N */
        hopamp3->Init.TrimmingValueN = opamp3_trimmingvaluen;
        /* Write calibration result P */
        hopamp3->Init.TrimmingValueP = opamp3_trimmingvaluep;
      }
      else
      {
        /* Write calibration result N */
        hopamp3->Init.TrimmingValueNLowPower = opamp3_trimmingvaluen;
        /* Write calibration result P */
        hopamp3->Init.TrimmingValuePLowPower = opamp3_trimmingvaluep;
      }

      /* Update OPAMP state */
      hopamp1->State = HAL_OPAMP_STATE_READY;
      hopamp2->State = HAL_OPAMP_STATE_READY;
      hopamp3->State = HAL_OPAMP_STATE_READY;

    }
    else
    {
/**
  * @brief  Initializes the OPAMP according to the specified
  *         parameters in the OPAMP_InitTypeDef and initialize the associated handle.
  * @note   If the selected opamp is locked, initialization can't be performed.
  *         To unlock the configuration, perform a system reset.
  * @param  hopamp: OPAMP handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_OPAMP_Init(OPAMP_HandleTypeDef *hopamp)
{ 
  HAL_StatusTypeDef status = HAL_OK;
  uint32_t updateotrlpotr = 0;

  /* Check the OPAMP handle allocation and lock status */
  /* Init not allowed if calibration is ongoing */
  if((hopamp == NULL) || (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
                      || (hopamp->State == HAL_OPAMP_STATE_CALIBBUSY))
  {
    return HAL_ERROR;
  }
  else
  {
    /* Check the parameter */
    assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
       
    /* Set OPAMP parameters */
    assert_param(IS_OPAMP_POWER_SUPPLY_RANGE(hopamp->Init.PowerSupplyRange));
    assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode));
    assert_param(IS_OPAMP_FUNCTIONAL_NORMALMODE(hopamp->Init.Mode));
    assert_param(IS_OPAMP_NONINVERTING_INPUT(hopamp->Init.NonInvertingInput));
    
    if ((hopamp->Init.Mode) == OPAMP_STANDALONE_MODE)
    {
      assert_param(IS_OPAMP_INVERTING_INPUT_STANDALONE(hopamp->Init.InvertingInput));
    }

    if ((hopamp->Init.Mode) == OPAMP_PGA_MODE)      
    {
      assert_param(IS_OPAMP_INVERTING_INPUT_PGA(hopamp->Init.InvertingInput));
    }
    
    if ((hopamp->Init.Mode) == OPAMP_PGA_MODE)
    {
      assert_param(IS_OPAMP_PGA_GAIN(hopamp->Init.PgaGain));
    }
    
    assert_param(IS_OPAMP_TRIMMING(hopamp->Init.UserTrimming)); 
    if ((hopamp->Init.UserTrimming) == OPAMP_TRIMMING_USER)
    {
      if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
      {
        assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueP));
        assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueN));
      }
    else
      {
        assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValuePLowPower));
        assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueNLowPower));
      }
    }
     
    if(hopamp->State == HAL_OPAMP_STATE_RESET)
    {
      /* Allocate lock resource and initialize it */
      hopamp->Lock = HAL_UNLOCKED;
    }

    /* Call MSP init function */
    HAL_OPAMP_MspInit(hopamp);

    /* Set operating mode */
    CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALON);
                                              
    if (hopamp->Init.Mode == OPAMP_PGA_MODE)
    {
      MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_INIT_MASK_PGA, \
                                        hopamp->Init.PowerMode | \
                                        hopamp->Init.Mode | \
                                        hopamp->Init.PgaGain | \
                                        hopamp->Init.InvertingInput    | \
                                        hopamp->Init.NonInvertingInput | \
                                        hopamp->Init.UserTrimming);
    }
    
    if (hopamp->Init.Mode == OPAMP_FOLLOWER_MODE)
    {
    /* In Follower mode InvertingInput is Not Applicable  */
    MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_INIT_MASK_FOLLOWER, \
                                        hopamp->Init.PowerMode | \
                                        hopamp->Init.Mode | \
                                        hopamp->Init.NonInvertingInput | \
                                        hopamp->Init.UserTrimming);     
    }     
    
    if (hopamp->Init.Mode == OPAMP_STANDALONE_MODE)
    {
      MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_INIT_MASK_STANDALONE, \
                                        hopamp->Init.PowerMode | \
                                        hopamp->Init.Mode | \
                                        hopamp->Init.InvertingInput    | \
                                        hopamp->Init.NonInvertingInput | \
                                        hopamp->Init.UserTrimming);
    } 
    
    if (hopamp->Init.UserTrimming == OPAMP_TRIMMING_USER)
    {
      /* Set power mode and associated calibration parameters */
      if (hopamp->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
      {
        /* OPAMP_POWERMODE_NORMAL */
        /* Set calibration mode (factory or user) and values for            */
        /* transistors differential pair high (PMOS) and low (NMOS) for     */
        /* normal mode.                                                     */
        updateotrlpotr = (((hopamp->Init.TrimmingValueP) << (OPAMP_INPUT_NONINVERTING)) \
                         | (hopamp->Init.TrimmingValueN)); 
        MODIFY_REG(hopamp->Instance->OTR, OPAMP_OTR_TRIMOFFSETN | OPAMP_OTR_TRIMOFFSETP, updateotrlpotr);
      }
      else
      {
        /* OPAMP_POWERMODE_LOWPOWER */
        /* transistors differential pair high (PMOS) and low (NMOS) for     */
        /* low power mode.                                                     */
        updateotrlpotr = (((hopamp->Init.TrimmingValuePLowPower) << (OPAMP_INPUT_NONINVERTING)) \
                         | (hopamp->Init.TrimmingValueNLowPower)); 
        MODIFY_REG(hopamp->Instance->LPOTR, OPAMP_OTR_TRIMOFFSETN | OPAMP_OTR_TRIMOFFSETP, updateotrlpotr);     
      }
    } 

    /* Configure the power supply range */
    /* The OPAMP_CSR_OPARANGE is common configuration for all OPAMPs */
    /* bit OPAMP1_CSR_OPARANGE is used for both OPAMPs */
    MODIFY_REG(OPAMP1->CSR, OPAMP1_CSR_OPARANGE, hopamp->Init.PowerSupplyRange);
    
    /* Update the OPAMP state*/
    if (hopamp->State == HAL_OPAMP_STATE_RESET)
    {
      /* From RESET state to READY State */
      hopamp->State = HAL_OPAMP_STATE_READY;
    }
    /* else: remain in READY or BUSY state (no update) */
    return status;
  }
}
/**
  * @brief  Run the self calibration of one OPAMP
  * @note   Trimming values (PMOS & NMOS) are updated and user trimming is 
  *         enabled is calibration is succesful.
  * @note   Calibration is performed in the mode specified in OPAMP init
  *         structure (mode normal or low-power). To perform calibration for
  *         both modes, repeat this function twice after OPAMP init structure
  *         accordingly updated.
  * @note   Calibration runs about 10 ms (5 dichotmy steps, repeated for P  
  *         and N transistors: 10 steps with 1 ms for each step).
  * @param  hopamp: handle
  * @retval Updated offset trimming values (PMOS & NMOS), user trimming is enabled
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_OPAMP_SelfCalibrate(OPAMP_HandleTypeDef* hopamp)
{ 
  HAL_StatusTypeDef status = HAL_OK;
  
  uint32_t* opamp_trimmingvalue = 0;
  uint32_t opamp_trimmingvaluen = 0;
  uint32_t opamp_trimmingvaluep = 0;
  
  uint32_t trimming_diff_pair = 0;           /* Selection of differential transistors pair high or low */

  __IO uint32_t* tmp_opamp_reg_trimming;     /* Selection of register of trimming depending on power mode: OTR or LPOTR */
  uint32_t tmp_opamp_otr_otuser = 0;         /* Selection of bit OPAMP_OTR_OT_USER depending on trimming register pointed: OTR or LPOTR */

  uint32_t tmp_Opaxcalout_DefaultSate = 0;   /* Bit OPAMP_CSR_OPAXCALOUT default state when trimming value is 00000b. Used to detect the bit toggling */

  uint32_t tmp_OpaxSwitchesContextBackup = 0;
  
  uint8_t trimming_diff_pair_iteration_count = 0;
  uint8_t delta = 0;

  
  /* Check the OPAMP handle allocation */
  /* Check if OPAMP locked */
  if((hopamp == NULL) || (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED))
  {
    status = HAL_ERROR;
  }
  else
  {
  
    /* Check if OPAMP in calibration mode and calibration not yet enable */
    if(hopamp->State == HAL_OPAMP_STATE_READY)
    {
      /* Check the parameter */
      assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
      assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode));
      
      /* Update OPAMP state */
      hopamp->State = HAL_OPAMP_STATE_CALIBBUSY;
      
      /* Backup of switches configuration to restore it at the end of the     */
      /* calibration.                                                         */
      tmp_OpaxSwitchesContextBackup = READ_BIT(OPAMP->CSR, __OPAMP_CSR_ALL_SWITCHES(hopamp));
  
      /* Open all switches on non-inverting input, inverting input and output */
      /* feedback.                                                            */
      CLEAR_BIT(OPAMP->CSR, __OPAMP_CSR_ALL_SWITCHES(hopamp));

      /* Set calibration mode to user programmed trimming values */
      SET_BIT(OPAMP->OTR, OPAMP_OTR_OT_USER);

      
      /* Select trimming settings depending on power mode */
      if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
      {
        tmp_opamp_otr_otuser = OPAMP_OTR_OT_USER;
        tmp_opamp_reg_trimming = &OPAMP->OTR;
      }
      else
      {
        tmp_opamp_otr_otuser = 0x00000000;
        tmp_opamp_reg_trimming = &OPAMP->LPOTR;
      }

      
      /* Enable the selected opamp */
      CLEAR_BIT (OPAMP->CSR, __OPAMP_CSR_OPAXPD(hopamp));

      /* Perform trimming for both differential transistors pair high and low */
      for (trimming_diff_pair_iteration_count = 0; trimming_diff_pair_iteration_count <=1; trimming_diff_pair_iteration_count++)
      {
        if (trimming_diff_pair_iteration_count == 0)
        {
          /* Calibration of transistors differential pair high (NMOS) */
          trimming_diff_pair = OPAMP_FACTORYTRIMMING_N;
          opamp_trimmingvalue = &opamp_trimmingvaluen;
          
          /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value   */
          /* is 00000b. Used to detect the bit toggling during trimming.      */
          tmp_Opaxcalout_DefaultSate = RESET;

          /* Enable calibration for N differential pair */
          MODIFY_REG(OPAMP->CSR, __OPAMP_CSR_OPAXCAL_L(hopamp),
                                 __OPAMP_CSR_OPAXCAL_H(hopamp) );
        }
        else /* (trimming_diff_pair_iteration_count == 1) */
        {
          /* Calibration of transistors differential pair low (PMOS) */
          trimming_diff_pair = OPAMP_FACTORYTRIMMING_P;
          opamp_trimmingvalue = &opamp_trimmingvaluep;
          
          /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value   */
          /* is 00000b. Used to detect the bit toggling during trimming.      */
          tmp_Opaxcalout_DefaultSate = __OPAMP_CSR_OPAXCALOUT(hopamp);
          
          /* Enable calibration for P differential pair */
          MODIFY_REG(OPAMP->CSR, __OPAMP_CSR_OPAXCAL_H(hopamp),
                                 __OPAMP_CSR_OPAXCAL_L(hopamp) );
        }
        
      
        /* Perform calibration parameter search by dichotomy sweep */
        /*  - Delta initial value 16: for 5 dichotomy steps: 16 for the       */
        /*    initial range, then successive delta sweeps (8, 4, 2, 1).       */
        /*    can extend the search range to +/- 15 units.                    */
        /*  - Trimming initial value 15: search range will go from 0 to 30    */
        /*    (Trimming value 31 is forbidden).                               */
        *opamp_trimmingvalue = 15;
        delta = 16;

        while (delta != 0)
        {
          /* Set candidate trimming */               
          MODIFY_REG(*tmp_opamp_reg_trimming, __OPAMP_OFFSET_TRIM_SET(hopamp, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
                                              __OPAMP_OFFSET_TRIM_SET(hopamp, trimming_diff_pair, *opamp_trimmingvalue) | tmp_opamp_otr_otuser);
          
          /* Offset trimming time: during calibration, minimum time needed    */
          /* between two steps to have 1 mV accuracy.                         */
          HAL_Delay(OPAMP_TRIMMING_DELAY);

          /* Divide range by 2 to continue dichotomy sweep */
          delta >>= 1;
            
          /* Set trimming values for next iteration in function of trimming   */
          /* result toggle (versus initial state).                            */
          if (READ_BIT(OPAMP->CSR, __OPAMP_CSR_OPAXCALOUT(hopamp)) != tmp_Opaxcalout_DefaultSate)
          {
            /* If calibration output is has toggled, try lower trimming */
            *opamp_trimmingvalue -= delta;
          }
          else
          {
            /* If calibration output is has not toggled, try higher trimming */
            *opamp_trimmingvalue += delta;
          }
        }
        
      }
       
      /* Disable calibration for P and N differential pairs */
      /* Disable the selected opamp */
      CLEAR_BIT (OPAMP->CSR, (__OPAMP_CSR_OPAXCAL_H(hopamp) | 
                              __OPAMP_CSR_OPAXCAL_L(hopamp) |
                              __OPAMP_CSR_OPAXPD(hopamp))    );

      /* Backup of switches configuration to restore it at the end of the     */
      /* calibration.                                                         */
      SET_BIT(OPAMP->CSR, tmp_OpaxSwitchesContextBackup);
      
      /* Self calibration is successful */
      /* Store calibration (user trimming) results in init structure. */
      
      /* Set user trimming mode */  
      hopamp->Init.UserTrimming = OPAMP_TRIMMING_USER;
      
      /* Affect calibration parameters depending on mode normal/low power */
      if (hopamp->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
      {
        /* Write calibration result N */
        hopamp->Init.TrimmingValueN = opamp_trimmingvaluen;
        /* Write calibration result P */
        hopamp->Init.TrimmingValueP = opamp_trimmingvaluep;
      }
      else
      {
        /* Write calibration result N */
        hopamp->Init.TrimmingValueNLowPower = opamp_trimmingvaluen;
        /* Write calibration result P */
        hopamp->Init.TrimmingValuePLowPower = opamp_trimmingvaluep;
      }
      
      /* Update OPAMP state */
      hopamp->State = HAL_OPAMP_STATE_READY;

    }
    else
    {
HAL_StatusTypeDef HAL_OPAMP_SelfCalibrate(OPAMP_HandleTypeDef *hopamp)
{ 

  HAL_StatusTypeDef status = HAL_OK;
  
  uint32_t trimmingvaluen = 0;
  uint32_t trimmingvaluep = 0;
  uint32_t delta;
  uint32_t opampmode;
  
  __IO uint32_t* tmp_opamp_reg_trimming;   /* Selection of register of trimming depending on power mode: OTR or LPOTR */
    
  /* Check the OPAMP handle allocation */
  /* Check if OPAMP locked */
  if((hopamp == NULL) || (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED))
  {
    status = HAL_ERROR;
  }
  else
  {
    /* Check if OPAMP in calibration mode and calibration not yet enable */
    if(hopamp->State ==  HAL_OPAMP_STATE_READY)
    {
      /* Check the parameter */
      assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
      assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode));

      /* Save OPAMP mode as in                                       */
      /* STM32L471xx STM32L475xx STM32L476xx STM32L485xx STM32L486xx */
      /* the calibration is not working in PGA mode                  */
      opampmode = READ_BIT(hopamp->Instance->CSR,OPAMP_CSR_OPAMODE);
      
      /* Use of standalone mode */ 
      MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_OPAMODE, OPAMP_STANDALONE_MODE); 

      /*  user trimming values are used for offset calibration */
      SET_BIT(hopamp->Instance->CSR, OPAMP_CSR_USERTRIM);
      
      /* Select trimming settings depending on power mode */
      if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
      {
        tmp_opamp_reg_trimming = &hopamp->Instance->OTR;
      }
      else
      {
        tmp_opamp_reg_trimming = &hopamp->Instance->LPOTR;
      }
      
      /* Enable calibration */
      SET_BIT (hopamp->Instance->CSR, OPAMP_CSR_CALON);
  
      /* 1st calibration - N */
      CLEAR_BIT (hopamp->Instance->CSR, OPAMP_CSR_CALSEL);
      
      /* Enable the selected opamp */
      SET_BIT (hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
      
      /* Init trimming counter */    
      /* Medium value */
      trimmingvaluen = 16; 
      delta = 8;
           
      while (delta != 0)
      {
        /* Set candidate trimming */
        /* OPAMP_POWERMODE_NORMAL */
        MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen);
        
        /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */ 
        /* Offset trim time: during calibration, minimum time needed between */
        /* two steps to have 1 mV accuracy */
        HAL_Delay(OPAMP_TRIMMING_DELAY);

        if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT) != RESET)
        { 
          /* OPAMP_CSR_CALOUT is HIGH try higher trimming */
          trimmingvaluen -= delta;
        }
        else
        {
          /* OPAMP_CSR_CALOUT is LOW try lower trimming */
          trimmingvaluen += delta;
        }
        /* Divide range by 2 to continue dichotomy sweep */       
        delta >>= 1;
      }

      /* Still need to check if right calibration is current value or one step below */
      /* Indeed the first value that causes the OUTCAL bit to change from 0 to 1  */
      /* Set candidate trimming */
      MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen);
           
      /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */ 
      /* Offset trim time: during calibration, minimum time needed between */
      /* two steps to have 1 mV accuracy */
      HAL_Delay(OPAMP_TRIMMING_DELAY);
      
      if ((READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT)) == 0)
      { 
        /* Trimming value is actually one value more */
        trimmingvaluen++;
        /* Set right trimming */
        MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen);
      }

      /* 2nd calibration - P */
      SET_BIT (hopamp->Instance->CSR, OPAMP_CSR_CALSEL);
      
      /* Init trimming counter */    
      /* Medium value */
      trimmingvaluep = 16; 
      delta = 8;
      
      while (delta != 0)
      {
        /* Set candidate trimming */
        /* OPAMP_POWERMODE_NORMAL */
        MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep<<OPAMP_INPUT_NONINVERTING));

        /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */ 
        /* Offset trim time: during calibration, minimum time needed between */
        /* two steps to have 1 mV accuracy */
        HAL_Delay(OPAMP_TRIMMING_DELAY);

        if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT) != RESET)
        { 
          /* OPAMP_CSR_CALOUT is HIGH try higher trimming */
          trimmingvaluep += delta;
        }
        else
        {
          /* OPAMP_CSR_CALOUT  is LOW try lower trimming */
          trimmingvaluep -= delta;
        }
        
        /* Divide range by 2 to continue dichotomy sweep */
        delta >>= 1;
      }
      
      /* Still need to check if right calibration is current value or one step below */
      /* Indeed the first value that causes the OUTCAL bit to change from 1 to 0  */
      /* Set candidate trimming */
      MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep<<OPAMP_INPUT_NONINVERTING));

      /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */ 
      /* Offset trim time: during calibration, minimum time needed between */
      /* two steps to have 1 mV accuracy */
      HAL_Delay(OPAMP_TRIMMING_DELAY);
      
      if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT) != RESET)
      {
        /* Trimming value is actually one value more */
        trimmingvaluep++;
        MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep<<OPAMP_INPUT_NONINVERTING));
      }
      
      /* Disable the OPAMP */
      CLEAR_BIT (hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
      
      /* Disable calibration & set normal mode (operating mode) */
      CLEAR_BIT (hopamp->Instance->CSR, OPAMP_CSR_CALON);
                 
      /* Self calibration is successful  */
      /* Store calibration(user trimming) results in init structure. */

      /* Set user trimming mode */  
      hopamp->Init.UserTrimming = OPAMP_TRIMMING_USER;

      /* Affect calibration parameters depending on mode normal/low power */
      if (hopamp->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
      {
        /* Write calibration result N */
        hopamp->Init.TrimmingValueN = trimmingvaluen;
        /* Write calibration result P */
        hopamp->Init.TrimmingValueP = trimmingvaluep;
      }
      else
      {
        /* Write calibration result N */
        hopamp->Init.TrimmingValueNLowPower = trimmingvaluen;
        /* Write calibration result P */
        hopamp->Init.TrimmingValuePLowPower = trimmingvaluep;
      }
    
    /* Restore OPAMP mode after calibration */
    MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_OPAMODE, opampmode);
    }
    else
    {