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