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   */
HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef * hopamp1,OPAMP_HandleTypeDef * hopamp2,OPAMP_HandleTypeDef * hopamp3)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   */
HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef * hopamp1,OPAMP_HandleTypeDef * hopamp2)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   */
HAL_OPAMPEx_Unlock(OPAMP_HandleTypeDef * hopamp)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