Subversion Repositories DashDisplay

Rev

Rev 56 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /**
  2.   ******************************************************************************
  3.   * @file    stm32l1xx_hal_opamp_ex.c
  4.   * @author  MCD Application Team
  5.   * @brief   Extended OPAMP HAL module driver.
  6.   *
  7.   *          This file provides firmware functions to manage the following
  8.   *          functionalities of the operational amplifier(s) peripheral:
  9.   *           + Extended Initialization and de-initialization functions
  10.   *           + Extended Peripheral Control functions
  11.   *
  12.   ******************************************************************************
  13.   * @attention
  14.   *
  15.   * Copyright (c) 2017 STMicroelectronics.
  16.   * All rights reserved.
  17.   *
  18.   * This software is licensed under terms that can be found in the LICENSE file
  19.   * in the root directory of this software component.
  20.   * If no LICENSE file comes with this software, it is provided AS-IS.
  21.   *
  22.   ******************************************************************************
  23.   */
  24.  
  25. /* Includes ------------------------------------------------------------------*/
  26. #include "stm32l1xx_hal.h"
  27.  
  28. #ifdef HAL_OPAMP_MODULE_ENABLED
  29.  
  30. #if defined (STM32L151xCA) || defined (STM32L151xD) || defined (STM32L152xCA) || defined (STM32L152xD) || defined (STM32L162xCA) || defined (STM32L162xD) || defined (STM32L151xE) || defined (STM32L151xDX) || defined (STM32L152xE) || defined (STM32L152xDX) || defined (STM32L162xE) || defined (STM32L162xDX) || defined (STM32L162xC) || defined (STM32L152xC) || defined (STM32L151xC)
  31.  
  32. /** @addtogroup STM32L1xx_HAL_Driver
  33.   * @{
  34.   */
  35.  
  36. /** @defgroup OPAMPEx OPAMPEx
  37.   * @brief OPAMP Extended HAL module driver.
  38.   * @{
  39.   */
  40.  
  41. /* Private typedef -----------------------------------------------------------*/
  42. /* Private define ------------------------------------------------------------*/
  43. /* Private macro -------------------------------------------------------------*/
  44. /* Private variables ---------------------------------------------------------*/
  45. /* Private function prototypes -----------------------------------------------*/
  46. /* Exported functions --------------------------------------------------------*/
  47.  
  48. /** @addtogroup OPAMPEx_Exported_Functions OPAMPEx Exported Functions
  49.   * @{
  50.   */
  51.  
  52. /** @addtogroup OPAMPEx_Exported_Functions_Group1
  53.   * @brief    Extended operation functions
  54.   *
  55. @verbatim
  56.  ===============================================================================
  57.               ##### Extended IO operation functions #####
  58.  ===============================================================================
  59.   [..]
  60.       (+) OPAMP Self calibration.
  61.  
  62. @endverbatim
  63.   * @{
  64.   */
  65.  
  66. #if defined (STM32L151xD) || defined (STM32L152xD) || defined (STM32L162xD)
  67.  
  68. /*  3 OPAMPS available */
  69. /*  3 OPAMPS can be calibrated in parallel */
  70.  
  71. /**
  72.   * @brief  Run the self calibration of the 3 OPAMPs in parallel.
  73.   * @note   Trimming values (PMOS & NMOS) are updated and user trimming is
  74.   *         enabled is calibration is successful.
  75.   * @note   Calibration is performed in the mode specified in OPAMP init
  76.   *         structure (mode normal or low-power). To perform calibration for
  77.   *         both modes, repeat this function twice after OPAMP init structure
  78.   *         accordingly updated.
  79.   * @note   Calibration runs about 10 ms (5 dichotmy steps, repeated for P  
  80.   *         and N transistors: 10 steps with 1 ms for each step).
  81.   * @param  hopamp1 handle
  82.   * @param  hopamp2 handle
  83.   * @param  hopamp3 handle
  84.   * @retval HAL status
  85.   */
  86. HAL_StatusTypeDef HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef *hopamp1, OPAMP_HandleTypeDef *hopamp2, OPAMP_HandleTypeDef *hopamp3)
  87. {
  88.   HAL_StatusTypeDef status = HAL_OK;
  89.  
  90.   uint32_t* opamp1_trimmingvalue;
  91.   uint32_t opamp1_trimmingvaluen = 0;
  92.   uint32_t opamp1_trimmingvaluep = 0;
  93.  
  94.   uint32_t* opamp2_trimmingvalue;
  95.   uint32_t opamp2_trimmingvaluen = 0;
  96.   uint32_t opamp2_trimmingvaluep = 0;
  97.  
  98.   uint32_t* opamp3_trimmingvalue;
  99.   uint32_t opamp3_trimmingvaluen = 0;
  100.   uint32_t opamp3_trimmingvaluep = 0;
  101.  
  102.   uint32_t trimming_diff_pair;              /* Selection of differential transistors pair high or low */
  103.  
  104.   __IO uint32_t* tmp_opamp1_reg_trimming;   /* Selection of register of trimming depending on power mode: OTR or LPOTR */
  105.   __IO uint32_t* tmp_opamp2_reg_trimming;
  106.   __IO uint32_t* tmp_opamp3_reg_trimming;
  107.   uint32_t tmp_opamp1_otr_otuser;           /* Selection of bit OPAMP_OTR_OT_USER depending on trimming register pointed: OTR or LPOTR */
  108.   uint32_t tmp_opamp2_otr_otuser;
  109.   uint32_t tmp_opamp3_otr_otuser;
  110.  
  111.   uint32_t tmp_Opa1calout_DefaultSate;      /* Bit OPAMP_CSR_OPA1CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
  112.   uint32_t tmp_Opa2calout_DefaultSate;      /* Bit OPAMP_CSR_OPA2CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
  113.   uint32_t tmp_Opa3calout_DefaultSate;      /* Bit OPAMP_CSR_OPA3CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
  114.  
  115.   uint32_t tmp_OpaxSwitchesContextBackup = 0x0U;
  116.  
  117.   uint8_t trimming_diff_pair_iteration_count = 0x0U;    /* For calibration loop algorithm: to repeat the calibration loop for both differential transistors pair high and low */
  118.   uint8_t delta;                                        /* For calibration loop algorithm: Variable for dichotomy steps value */
  119.   uint8_t final_step_check = 0x0U;                      /* For calibration loop algorithm: Flag for additional check of last trimming step */
  120.  
  121.  
  122.   if((hopamp1 == NULL) || (hopamp2 == NULL) || (hopamp3 == NULL))
  123.   {
  124.     status = HAL_ERROR;
  125.   }
  126.   /* Check if OPAMP in calibration mode and calibration not yet enable */
  127.   else if(hopamp1->State !=  HAL_OPAMP_STATE_READY)
  128.   {
  129.     status = HAL_ERROR;
  130.   }
  131.   else if(hopamp2->State != HAL_OPAMP_STATE_READY)
  132.   {
  133.     status = HAL_ERROR;
  134.   }
  135.   else if(hopamp3->State != HAL_OPAMP_STATE_READY)
  136.   {
  137.     status = HAL_ERROR;
  138.   }
  139.  
  140.   else
  141.   {
  142.       /* Check the parameter */
  143.       assert_param(IS_OPAMP_ALL_INSTANCE(hopamp1->Instance));
  144.       assert_param(IS_OPAMP_ALL_INSTANCE(hopamp2->Instance));
  145.       assert_param(IS_OPAMP_ALL_INSTANCE(hopamp3->Instance));
  146.       assert_param(IS_OPAMP_POWERMODE(hopamp1->Init.PowerMode));
  147.       assert_param(IS_OPAMP_POWERMODE(hopamp2->Init.PowerMode));
  148.       assert_param(IS_OPAMP_POWERMODE(hopamp3->Init.PowerMode));
  149.      
  150.       /* Update OPAMP state */
  151.       hopamp1->State = HAL_OPAMP_STATE_CALIBBUSY;
  152.       hopamp2->State = HAL_OPAMP_STATE_CALIBBUSY;
  153.       hopamp3->State = HAL_OPAMP_STATE_CALIBBUSY;
  154.      
  155.       /* Backup of switches configuration to restore it at the end of the     */
  156.       /* calibration.                                                         */
  157.       tmp_OpaxSwitchesContextBackup = READ_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES_ALL_OPAMPS);
  158.      
  159.       /* Open all switches on non-inverting input, inverting input and output */
  160.       /* feedback.                                                            */
  161.       CLEAR_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES_ALL_OPAMPS);
  162.      
  163.       /* Set calibration mode to user programmed trimming values */
  164.       SET_BIT(OPAMP->OTR, OPAMP_OTR_OT_USER);
  165.      
  166.       /* Select trimming settings depending on power mode */
  167.       if (hopamp1->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
  168.       {
  169.         tmp_opamp1_otr_otuser = OPAMP_OTR_OT_USER;
  170.         tmp_opamp1_reg_trimming = &OPAMP->OTR;
  171.       }
  172.       else
  173.       {
  174.         tmp_opamp1_otr_otuser = 0x00000000;
  175.         tmp_opamp1_reg_trimming = &OPAMP->LPOTR;
  176.       }
  177.      
  178.       if (hopamp2->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
  179.       {
  180.         tmp_opamp2_otr_otuser = OPAMP_OTR_OT_USER;
  181.         tmp_opamp2_reg_trimming = &OPAMP->OTR;
  182.       }
  183.       else
  184.       {
  185.         tmp_opamp2_otr_otuser = 0x00000000;
  186.         tmp_opamp2_reg_trimming = &OPAMP->LPOTR;
  187.       }
  188.      
  189.       if (hopamp3->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
  190.       {
  191.         tmp_opamp3_otr_otuser = OPAMP_OTR_OT_USER;
  192.         tmp_opamp3_reg_trimming = &OPAMP->OTR;
  193.       }
  194.       else
  195.       {
  196.         tmp_opamp3_otr_otuser = 0x00000000;
  197.         tmp_opamp3_reg_trimming = &OPAMP->LPOTR;
  198.       }
  199.      
  200.       /* Enable the selected opamp */
  201.       CLEAR_BIT (OPAMP->CSR, OPAMP_CSR_OPAXPD_ALL);
  202.      
  203.       /* Perform trimming for both differential transistors pair high and low */
  204.       for (trimming_diff_pair_iteration_count = 0U; trimming_diff_pair_iteration_count <= 1U; trimming_diff_pair_iteration_count++)
  205.       {
  206.         if (trimming_diff_pair_iteration_count == 0U)
  207.         {
  208.           /* Calibration of transistors differential pair high (NMOS) */
  209.           trimming_diff_pair = OPAMP_FACTORYTRIMMING_N;
  210.           opamp1_trimmingvalue = &opamp1_trimmingvaluen;
  211.           opamp2_trimmingvalue = &opamp2_trimmingvaluen;
  212.           opamp3_trimmingvalue = &opamp3_trimmingvaluen;
  213.          
  214.           /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value   */
  215.           /* is 00000b. Used to detect the bit toggling during trimming.      */
  216.           tmp_Opa1calout_DefaultSate = RESET;
  217.           tmp_Opa2calout_DefaultSate = RESET;
  218.           tmp_Opa3calout_DefaultSate = RESET;
  219.          
  220.           /* Enable calibration for N differential pair */
  221.           MODIFY_REG(OPAMP->CSR, OPAMP_CSR_OPAXCAL_L_ALL,
  222.                                  OPAMP_CSR_OPAXCAL_H_ALL);
  223.         }
  224.         else /* (trimming_diff_pair_iteration_count == 1) */
  225.         {
  226.           /* Calibration of transistors differential pair low (PMOS) */
  227.           trimming_diff_pair = OPAMP_FACTORYTRIMMING_P;
  228.           opamp1_trimmingvalue = &opamp1_trimmingvaluep;
  229.           opamp2_trimmingvalue = &opamp2_trimmingvaluep;
  230.           opamp3_trimmingvalue = &opamp3_trimmingvaluep;
  231.          
  232.           /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value   */
  233.           /* is 00000b. Used to detect the bit toggling during trimming.      */
  234.           tmp_Opa1calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp1);
  235.           tmp_Opa2calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp2);
  236.           tmp_Opa3calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp3);
  237.          
  238.           /* Enable calibration for P differential pair */
  239.           MODIFY_REG(OPAMP->CSR, OPAMP_CSR_OPAXCAL_H_ALL,
  240.                                  OPAMP_CSR_OPAXCAL_L_ALL);
  241.         }
  242.        
  243.      
  244.         /* Perform calibration parameter search by dichotomy sweep */
  245.         /*  - Delta initial value 16: for 5 dichotomy steps: 16 for the       */
  246.         /*    initial range, then successive delta sweeps (8, 4, 2, 1).       */
  247.         /*    can extend the search range to +/- 15 units.                    */
  248.         /*  - Trimming initial value 15: search range will go from 0 to 30    */
  249.         /*    (Trimming value 31 is forbidden).                               */
  250.         /* Note: After dichotomy sweep, the trimming result is determined.    */
  251.         /*       However, the final trimming step is deduced from previous    */
  252.         /*       trimming steps tested but is not effectively tested.         */
  253.         /*       An additional test step (using variable "final_step_check")  */
  254.         /*       allow to Test the final trimming step.                       */
  255.         *opamp1_trimmingvalue = 15U;
  256.         *opamp2_trimmingvalue = 15U;
  257.         *opamp3_trimmingvalue = 15U;
  258.         delta = 16U;
  259.        
  260.         while ((delta != 0U) || (final_step_check == 1U))
  261.         {
  262.           /* Set candidate trimming */
  263.           MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  264.                                                OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, *opamp1_trimmingvalue) | tmp_opamp1_otr_otuser);
  265.  
  266.           MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  267.                                                OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, *opamp2_trimmingvalue) | tmp_opamp2_otr_otuser);
  268.  
  269.           MODIFY_REG(*tmp_opamp3_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  270.                                                OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, *opamp3_trimmingvalue) | tmp_opamp3_otr_otuser);
  271.          
  272.           /* Offset trimming time: during calibration, minimum time needed    */
  273.           /* between two steps to have 1 mV accuracy.                         */
  274.           HAL_Delay(OPAMP_TRIMMING_DELAY);
  275.          
  276.           /* Set flag for additional check of last trimming step equal to     */
  277.           /* dichotomy step before its division by 2 (equivalent to previous  */
  278.           /* value of dichotomy step).                                        */
  279.           final_step_check = delta;
  280.          
  281.           /* Divide range by 2 to continue dichotomy sweep */
  282.           delta >>= 1U;
  283.          
  284.           /* Set trimming values for next iteration in function of trimming   */
  285.           /* result toggle (versus initial state).                            */
  286.           /* Trimming values update with dichotomy delta of previous          */
  287.           /* iteration.                                                       */
  288.           /* Note: on the last trimming loop, delta is equal to 0 and         */
  289.           /*       therefore has no effect.                                   */
  290.           if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp1)) != tmp_Opa1calout_DefaultSate)
  291.           {
  292.             /* If calibration output is has toggled, try lower trimming */
  293.             *opamp1_trimmingvalue -= delta;
  294.           }
  295.           else
  296.           {
  297.             /* If calibration output is has not toggled, try higher trimming */
  298.             *opamp1_trimmingvalue += delta;
  299.           }
  300.          
  301.           if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp2)) != tmp_Opa2calout_DefaultSate)
  302.           {
  303.             /* If calibration output is has toggled, try lower trimming */
  304.             *opamp2_trimmingvalue -= delta;
  305.           }
  306.           else
  307.           {
  308.             /* If calibration output is has not toggled, try higher trimming */
  309.             *opamp2_trimmingvalue += delta;
  310.           }
  311.  
  312.         if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp3)) != tmp_Opa3calout_DefaultSate)
  313.         {
  314.           /* If calibration output is has toggled, try lower trimming */
  315.           *opamp3_trimmingvalue -= delta;
  316.         }
  317.         else
  318.         {
  319.           /* If calibration output is has not toggled, try higher trimming */
  320.           *opamp3_trimmingvalue += delta;
  321.         }
  322.       }
  323.      
  324.       /* Check trimming result of the selected step and perform final fine  */
  325.       /* trimming.                                                          */
  326.       /*  - If calibration output is has toggled: the current step is       */
  327.       /*    already optimized.                                              */
  328.       /*  - If calibration output is has not toggled: the current step can  */
  329.       /*    be optimized by incrementing it of one step.                    */
  330.       if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp1)) == tmp_Opa1calout_DefaultSate)
  331.       {
  332.         *opamp1_trimmingvalue += 1U;
  333.        
  334.         /* Set final fine trimming */
  335.         MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  336.                                              OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, *opamp1_trimmingvalue) | tmp_opamp1_otr_otuser);
  337.       }
  338.       if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp2)) == tmp_Opa2calout_DefaultSate)
  339.       {
  340.         *opamp2_trimmingvalue += 1U;
  341.        
  342.         /* Set final fine trimming */
  343.         MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  344.                                              OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, *opamp2_trimmingvalue) | tmp_opamp2_otr_otuser);
  345.       }
  346.       if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp3)) == tmp_Opa3calout_DefaultSate)
  347.       {
  348.         *opamp3_trimmingvalue += 1U;
  349.        
  350.         /* Set final fine trimming */
  351.         MODIFY_REG(*tmp_opamp3_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  352.                                              OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, *opamp3_trimmingvalue) | tmp_opamp3_otr_otuser);
  353.       }
  354.      
  355.     }
  356.      
  357.  
  358.     /* Disable calibration for P and N differential pairs */
  359.     /* Disable the selected opamp */
  360.     CLEAR_BIT (OPAMP->CSR, (OPAMP_CSR_OPAXCAL_H_ALL |
  361.                             OPAMP_CSR_OPAXCAL_L_ALL |
  362.                             OPAMP_CSR_OPAXPD_ALL     ));
  363.    
  364.     /* Backup of switches configuration to restore it at the end of the     */
  365.     /* calibration.                                                         */
  366.     SET_BIT(OPAMP->CSR, tmp_OpaxSwitchesContextBackup);
  367.    
  368.     /* Self calibration is successful */
  369.     /* Store calibration (user trimming) results in init structure. */
  370.    
  371.     /* Set user trimming mode */  
  372.     hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER;
  373.     hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER;
  374.     hopamp3->Init.UserTrimming = OPAMP_TRIMMING_USER;
  375.    
  376.     /* Affect calibration parameters depending on mode normal/low power */
  377.     if (hopamp1->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
  378.     {
  379.       /* Write calibration result N */
  380.       hopamp1->Init.TrimmingValueN = opamp1_trimmingvaluen;
  381.       /* Write calibration result P */
  382.       hopamp1->Init.TrimmingValueP = opamp1_trimmingvaluep;
  383.     }
  384.     else
  385.     {
  386.       /* Write calibration result N */
  387.       hopamp1->Init.TrimmingValueNLowPower = opamp1_trimmingvaluen;
  388.       /* Write calibration result P */
  389.       hopamp1->Init.TrimmingValuePLowPower = opamp1_trimmingvaluep;
  390.     }
  391.    
  392.     if (hopamp2->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
  393.     {
  394.       /* Write calibration result N */
  395.       hopamp2->Init.TrimmingValueN = opamp2_trimmingvaluen;
  396.       /* Write calibration result P */
  397.       hopamp2->Init.TrimmingValueP = opamp2_trimmingvaluep;
  398.     }
  399.     else
  400.     {
  401.       /* Write calibration result N */
  402.       hopamp2->Init.TrimmingValueNLowPower = opamp2_trimmingvaluen;
  403.       /* Write calibration result P */
  404.       hopamp2->Init.TrimmingValuePLowPower = opamp2_trimmingvaluep;
  405.     }
  406.    
  407.     if (hopamp3->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
  408.     {
  409.       /* Write calibration result N */
  410.       hopamp3->Init.TrimmingValueN = opamp3_trimmingvaluen;
  411.       /* Write calibration result P */
  412.       hopamp3->Init.TrimmingValueP = opamp3_trimmingvaluep;
  413.     }
  414.     else
  415.     {
  416.       /* Write calibration result N */
  417.       hopamp3->Init.TrimmingValueNLowPower = opamp3_trimmingvaluen;
  418.       /* Write calibration result P */
  419.       hopamp3->Init.TrimmingValuePLowPower = opamp3_trimmingvaluep;
  420.     }
  421.  
  422.     /* Update OPAMP state */
  423.     hopamp1->State = HAL_OPAMP_STATE_READY;
  424.     hopamp2->State = HAL_OPAMP_STATE_READY;
  425.     hopamp3->State = HAL_OPAMP_STATE_READY;
  426.   }
  427.   return status;
  428. }
  429.  
  430. #else
  431.  
  432. /*  2 OPAMPS available */
  433. /*  2 OPAMPS can be calibrated in parallel */
  434.  
  435. /**
  436.   * @brief  Run the self calibration of the 2 OPAMPs in parallel.
  437.   * @note   Trimming values (PMOS & NMOS) are updated and user trimming is
  438.   *         enabled is calibration is successful.
  439.   * @note   Calibration is performed in the mode specified in OPAMP init
  440.   *         structure (mode normal or low-power). To perform calibration for
  441.   *         both modes, repeat this function twice after OPAMP init structure
  442.   *         accordingly updated.
  443.   * @note   Calibration runs about 10 ms (5 dichotmy steps, repeated for P  
  444.   *         and N transistors: 10 steps with 1 ms for each step).
  445.   * @param  hopamp1 handle
  446.   * @param  hopamp2 handle
  447.   * @retval HAL status
  448.   */
  449. HAL_StatusTypeDef HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef *hopamp1, OPAMP_HandleTypeDef *hopamp2)
  450. {
  451.   HAL_StatusTypeDef status = HAL_OK;
  452.  
  453.   uint32_t* opamp1_trimmingvalue;
  454.   uint32_t opamp1_trimmingvaluen = 0;
  455.   uint32_t opamp1_trimmingvaluep = 0;
  456.  
  457.   uint32_t* opamp2_trimmingvalue;
  458.   uint32_t opamp2_trimmingvaluen = 0;
  459.   uint32_t opamp2_trimmingvaluep = 0;
  460.  
  461.   uint32_t trimming_diff_pair;          /* Selection of differential transistors pair high or low */
  462.  
  463.   __IO uint32_t* tmp_opamp1_reg_trimming;   /* Selection of register of trimming depending on power mode: OTR or LPOTR */
  464.   __IO uint32_t* tmp_opamp2_reg_trimming;
  465.   uint32_t tmp_opamp1_otr_otuser;       /* Selection of bit OPAMP_OTR_OT_USER depending on trimming register pointed: OTR or LPOTR */
  466.   uint32_t tmp_opamp2_otr_otuser;
  467.  
  468.   uint32_t tmp_Opa1calout_DefaultSate;  /* Bit OPAMP_CSR_OPA1CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
  469.   uint32_t tmp_Opa2calout_DefaultSate;  /* Bit OPAMP_CSR_OPA2CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
  470.  
  471.   uint32_t tmp_OpaxSwitchesContextBackup;
  472.  
  473.   uint8_t trimming_diff_pair_iteration_count;          /* For calibration loop algorithm: to repeat the calibration loop for both differential transistors pair high and low */
  474.   uint8_t delta;                                       /* For calibration loop algorithm: Variable for dichotomy steps value */
  475.   uint8_t final_step_check = 0x0U;                     /* For calibration loop algorithm: Flag for additional check of last trimming step */
  476.  
  477.  
  478.   if((hopamp1 == NULL) || (hopamp2 == NULL))
  479.   {
  480.     status = HAL_ERROR;
  481.   }
  482.   /* Check if OPAMP in calibration mode and calibration not yet enable */
  483.   else if(hopamp1->State !=  HAL_OPAMP_STATE_READY)
  484.   {
  485.     status = HAL_ERROR;
  486.   }
  487.   else if(hopamp2->State != HAL_OPAMP_STATE_READY)
  488.   {
  489.     status = HAL_ERROR;
  490.   }
  491.   else
  492.   {
  493.     /* Check the parameter */
  494.     assert_param(IS_OPAMP_ALL_INSTANCE(hopamp1->Instance));
  495.     assert_param(IS_OPAMP_ALL_INSTANCE(hopamp2->Instance));
  496.     assert_param(IS_OPAMP_POWERMODE(hopamp1->Init.PowerMode));
  497.     assert_param(IS_OPAMP_POWERMODE(hopamp2->Init.PowerMode));
  498.    
  499.     /* Update OPAMP state */
  500.     hopamp1->State = HAL_OPAMP_STATE_CALIBBUSY;
  501.     hopamp2->State = HAL_OPAMP_STATE_CALIBBUSY;
  502.    
  503.     /* Backup of switches configuration to restore it at the end of the     */
  504.     /* calibration.                                                         */
  505.     tmp_OpaxSwitchesContextBackup = READ_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES_ALL_OPAMPS);
  506.    
  507.     /* Open all switches on non-inverting input, inverting input and output */
  508.     /* feedback.                                                            */
  509.     CLEAR_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES_ALL_OPAMPS);
  510.    
  511.     /* Set calibration mode to user programmed trimming values */
  512.     SET_BIT(OPAMP->OTR, OPAMP_OTR_OT_USER);
  513.    
  514.     /* Select trimming settings depending on power mode */
  515.     if (hopamp1->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
  516.     {
  517.       tmp_opamp1_otr_otuser = OPAMP_OTR_OT_USER;
  518.       tmp_opamp1_reg_trimming = &OPAMP->OTR;
  519.     }
  520.     else
  521.     {
  522.       tmp_opamp1_otr_otuser = 0x00000000U;
  523.       tmp_opamp1_reg_trimming = &OPAMP->LPOTR;
  524.     }
  525.    
  526.     if (hopamp2->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
  527.     {
  528.       tmp_opamp2_otr_otuser = OPAMP_OTR_OT_USER;
  529.       tmp_opamp2_reg_trimming = &OPAMP->OTR;
  530.     }
  531.     else
  532.     {
  533.       tmp_opamp2_otr_otuser = 0x00000000U;
  534.       tmp_opamp2_reg_trimming = &OPAMP->LPOTR;
  535.     }
  536.    
  537.     /* Enable the selected opamp */
  538.     CLEAR_BIT (OPAMP->CSR, OPAMP_CSR_OPAXPD_ALL);
  539.    
  540.     /* Perform trimming for both differential transistors pair high and low */
  541.     for (trimming_diff_pair_iteration_count = 0U; trimming_diff_pair_iteration_count <= 1U; trimming_diff_pair_iteration_count++)
  542.     {
  543.       if (trimming_diff_pair_iteration_count == 0U)
  544.       {
  545.         /* Calibration of transistors differential pair high (NMOS) */
  546.         trimming_diff_pair = OPAMP_FACTORYTRIMMING_N;
  547.         opamp1_trimmingvalue = &opamp1_trimmingvaluen;
  548.         opamp2_trimmingvalue = &opamp2_trimmingvaluen;
  549.        
  550.         /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value   */
  551.         /* is 00000b. Used to detect the bit toggling during trimming.      */
  552.         tmp_Opa1calout_DefaultSate = 0U;
  553.         tmp_Opa2calout_DefaultSate = 0U;
  554.        
  555.         /* Enable calibration for N differential pair */
  556.         MODIFY_REG(OPAMP->CSR, OPAMP_CSR_OPAXCAL_L_ALL,
  557.                                OPAMP_CSR_OPAXCAL_H_ALL);
  558.       }
  559.       else /* (trimming_diff_pair_iteration_count == 1) */
  560.       {
  561.         /* Calibration of transistors differential pair low (PMOS) */
  562.         trimming_diff_pair = OPAMP_FACTORYTRIMMING_P;
  563.         opamp1_trimmingvalue = &opamp1_trimmingvaluep;
  564.         opamp2_trimmingvalue = &opamp2_trimmingvaluep;
  565.        
  566.         /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value   */
  567.         /* is 00000b. Used to detect the bit toggling during trimming.      */
  568.         tmp_Opa1calout_DefaultSate = (uint32_t) OPAMP_CSR_OPAXCALOUT(hopamp1);
  569.         tmp_Opa2calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp2);
  570.        
  571.         /* Enable calibration for P differential pair */
  572.         MODIFY_REG(OPAMP->CSR, OPAMP_CSR_OPAXCAL_H_ALL,
  573.                                OPAMP_CSR_OPAXCAL_L_ALL);
  574.       }
  575.      
  576.    
  577.       /* Perform calibration parameter search by dichotomy sweep */
  578.       /*  - Delta initial value 16: for 5 dichotomy steps: 16 for the       */
  579.       /*    initial range, then successive delta sweeps (8, 4, 2, 1).       */
  580.       /*    can extend the search range to +/- 15 units.                    */
  581.       /*  - Trimming initial value 15: search range will go from 0 to 30    */
  582.       /*    (Trimming value 31 is forbidden).                               */
  583.       /* Note: After dichotomy sweep, the trimming result is determined.    */
  584.       /*       However, the final trimming step is deduced from previous    */
  585.       /*       trimming steps tested but is not effectively tested.         */
  586.       /*       An additional test step (using variable "final_step_check")  */
  587.       /*       allow to Test the final trimming step.                       */
  588.       *opamp1_trimmingvalue = 15U;
  589.       *opamp2_trimmingvalue = 15U;
  590.       delta = 16U;
  591.      
  592.       while ((delta != 0U) || (final_step_check == 1U))
  593.       {
  594.         /* Set candidate trimming */
  595.         MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  596.                                              OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, *opamp1_trimmingvalue) | tmp_opamp1_otr_otuser);
  597.  
  598.         MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  599.                                              OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, *opamp2_trimmingvalue) | tmp_opamp2_otr_otuser);
  600.  
  601.        
  602.         /* Offset trimming time: during calibration, minimum time needed    */
  603.         /* between two steps to have 1 mV accuracy.                         */
  604.         HAL_Delay(OPAMP_TRIMMING_DELAY);
  605.        
  606.         /* Set flag for additional check of last trimming step equal to     */
  607.         /* dichotomy step before its division by 2 (equivalent to previous  */
  608.         /* value of dichotomy step).                                        */
  609.         final_step_check = delta;
  610.        
  611.         /* Divide range by 2 to continue dichotomy sweep */
  612.         delta >>= 1U;
  613.        
  614.         /* Set trimming values for next iteration in function of trimming   */
  615.         /* result toggle (versus initial state).                            */
  616.         /* Trimming values update with dichotomy delta of previous          */
  617.         /* iteration.                                                       */
  618.         /* Note: on the last trimming loop, delta is equal to 0 and         */
  619.         /*       therefore has no effect.                                   */
  620.         if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp1)) != tmp_Opa1calout_DefaultSate)
  621.         {
  622.           /* If calibration output is has toggled, try lower trimming */
  623.           *opamp1_trimmingvalue -= delta;
  624.         }
  625.         else
  626.         {
  627.           /* If calibration output is has not toggled, try higher trimming */
  628.           *opamp1_trimmingvalue += delta;
  629.         }
  630.        
  631.         if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp2)) != tmp_Opa2calout_DefaultSate)
  632.         {
  633.           /* If calibration output is has toggled, try lower trimming */
  634.           *opamp2_trimmingvalue -= delta;
  635.         }
  636.         else
  637.         {
  638.           /* If calibration output is has not toggled, try higher trimming */
  639.           *opamp2_trimmingvalue += delta;
  640.         }
  641.       }
  642.      
  643.       /* Check trimming result of the selected step and perform final fine  */
  644.       /* trimming.                                                          */
  645.       /*  - If calibration output is has toggled: the current step is       */
  646.       /*    already optimized.                                              */
  647.       /*  - If calibration output is has not toggled: the current step can  */
  648.       /*    be optimized by incrementing it of one step.                    */
  649.       if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp1)) == tmp_Opa1calout_DefaultSate)
  650.       {
  651.         *opamp1_trimmingvalue += 1U;
  652.        
  653.         /* Set final fine trimming */
  654.         MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  655.                                              OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, *opamp1_trimmingvalue) | tmp_opamp1_otr_otuser);
  656.       }
  657.       if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp2)) == tmp_Opa2calout_DefaultSate)
  658.       {
  659.         *opamp2_trimmingvalue += 1U;
  660.        
  661.         /* Set final fine trimming */
  662.         MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
  663.                                              OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, *opamp2_trimmingvalue) | tmp_opamp2_otr_otuser);
  664.  
  665.       }
  666.      
  667.     }
  668.      
  669.  
  670.     /* Disable calibration for P and N differential pairs */
  671.     /* Disable the selected opamp */
  672.     CLEAR_BIT (OPAMP->CSR, (OPAMP_CSR_OPAXCAL_H_ALL |
  673.                             OPAMP_CSR_OPAXCAL_L_ALL |
  674.                             OPAMP_CSR_OPAXPD_ALL     ));
  675.    
  676.     /* Backup of switches configuration to restore it at the end of the     */
  677.     /* calibration.                                                         */
  678.     SET_BIT(OPAMP->CSR, tmp_OpaxSwitchesContextBackup);
  679.    
  680.     /* Self calibration is successful */
  681.     /* Store calibration (user trimming) results in init structure. */
  682.    
  683.     /* Set user trimming mode */  
  684.     hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER;
  685.     hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER;
  686.    
  687.     /* Affect calibration parameters depending on mode normal/low power */
  688.     if (hopamp1->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
  689.     {
  690.       /* Write calibration result N */
  691.       hopamp1->Init.TrimmingValueN = opamp1_trimmingvaluen;
  692.       /* Write calibration result P */
  693.       hopamp1->Init.TrimmingValueP = opamp1_trimmingvaluep;
  694.     }
  695.     else
  696.     {
  697.       /* Write calibration result N */
  698.       hopamp1->Init.TrimmingValueNLowPower = opamp1_trimmingvaluen;
  699.       /* Write calibration result P */
  700.       hopamp1->Init.TrimmingValuePLowPower = opamp1_trimmingvaluep;
  701.     }
  702.    
  703.     if (hopamp2->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
  704.     {
  705.       /* Write calibration result N */
  706.       hopamp2->Init.TrimmingValueN = opamp2_trimmingvaluen;
  707.       /* Write calibration result P */
  708.       hopamp2->Init.TrimmingValueP = opamp2_trimmingvaluep;
  709.     }
  710.     else
  711.     {
  712.       /* Write calibration result N */
  713.       hopamp2->Init.TrimmingValueNLowPower = opamp2_trimmingvaluen;
  714.       /* Write calibration result P */
  715.       hopamp2->Init.TrimmingValuePLowPower = opamp2_trimmingvaluep;
  716.     }
  717.  
  718.     /* Update OPAMP state */
  719.     hopamp1->State = HAL_OPAMP_STATE_READY;
  720.     hopamp2->State = HAL_OPAMP_STATE_READY;
  721.   }
  722.   return status;
  723. }
  724.  
  725. #endif /* STM32L151xD || STM32L152xD || STM32L162xD */
  726.  
  727. /**
  728.   * @}
  729.   */
  730.  
  731. /** @defgroup OPAMPEx_Exported_Functions_Group2 Extended Peripheral Control functions
  732.  *  @brief   Extended peripheral control functions
  733.  *
  734. @verbatim  
  735.  ===============================================================================
  736.              ##### Peripheral Control functions #####
  737.  ===============================================================================
  738.     [..]
  739.       (+) OPAMP unlock.
  740.  
  741. @endverbatim
  742.   * @{
  743.   */
  744.  
  745. /**
  746.   * @brief  Unlock the selected OPAMP configuration.
  747.   *         This function must be called only when OPAMP is in state "locked".
  748.   * @param  hopamp OPAMP handle
  749.   * @retval HAL status
  750.   */
  751. HAL_StatusTypeDef HAL_OPAMPEx_Unlock(OPAMP_HandleTypeDef* hopamp)
  752. {
  753.   HAL_StatusTypeDef status = HAL_OK;
  754.  
  755.   /* Check the OPAMP handle allocation */
  756.   /* Check if OPAMP locked */
  757.   if(hopamp == NULL)
  758.   {
  759.     status = HAL_ERROR;
  760.   }
  761.   /* Check the OPAMP handle allocation */
  762.   /* Check if OPAMP locked */
  763.   else if(hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
  764.   {
  765.     /* Check the parameter */
  766.     assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
  767.  
  768.    /* OPAMP state changed to locked */
  769.     hopamp->State = HAL_OPAMP_STATE_BUSY;
  770.   }
  771.   else
  772.   {
  773.     status = HAL_ERROR;
  774.   }
  775.  
  776.   return status;
  777. }
  778.  
  779. /**
  780.   * @}
  781.   */
  782.  
  783. /**
  784.   * @}
  785.   */
  786.  
  787. #endif /* STM32L151xCA || STM32L151xD || STM32L152xCA || STM32L152xD || STM32L162xCA || STM32L162xD || STM32L151xE || STM32L151xDX || STM32L152xE || STM32L152xDX || STM32L162xE || STM32L162xDX || STM32L162xC || STM32L152xC || STM32L151xC */
  788.  
  789. #endif /* HAL_OPAMP_MODULE_ENABLED */
  790. /**
  791.   * @}
  792.   */
  793.  
  794. /**
  795.   * @}
  796.   */
  797.  
  798.