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