1 /**
2   ******************************************************************************
3   * @file    stm32l5xx_hal_opamp.c
4   * @author  MCD Application Team
5   * @brief   OPAMP HAL module driver.
6   *          This file provides firmware functions to manage the following
7   *          functionalities of the operational amplifier(s) peripheral:
8   *           + Initialization and de-initialization functions
9   *           + IO operation functions
10   *           + Peripheral Control functions
11   *           + Peripheral State functions
12   *
13   ******************************************************************************
14   * @attention
15   *
16   * Copyright (c) 2019 STMicroelectronics.
17   * All rights reserved.
18   *
19   * This software is licensed under terms that can be found in the LICENSE file
20   * in the root directory of this software component.
21   * If no LICENSE file comes with this software, it is provided AS-IS.
22   *
23   ******************************************************************************
24   @verbatim
25 ================================================================================
26           ##### OPAMP Peripheral Features #####
27 ================================================================================
28 
29   [..] The device integrates 1 or 2 operational amplifiers OPAMP1 & OPAMP2
30 
31        (#) The OPAMP(s) provide(s) several exclusive running modes.
32        (++) 2 OPAMP are available.
33 
34        (#) The OPAMP(s) provide(s) several exclusive running modes.
35        (++) Standalone mode
36        (++) Programmable Gain Amplifier (PGA) mode (Resistor feedback output)
37        (++) Follower mode
38 
39        (#) All OPAMP (same for all OPAMPs) can operate in
40        (++) Either Low range (VDDA < 2.4V) power supply
41        (++) Or High range (VDDA > 2.4V) power supply
42 
43        (#) Each OPAMP(s) can be configured in normal and low power mode.
44 
45        (#) The OPAMP(s) provide(s) calibration capabilities.
46        (++) Calibration aims at correcting some offset for running mode.
47        (++) The OPAMP uses either factory calibration settings OR user defined
48            calibration (trimming) settings (i.e. trimming mode).
49        (++) The user defined settings can be figured out using self calibration
50            handled by HAL_OPAMP_SelfCalibrate, HAL_OPAMPEx_SelfCalibrateAll
51        (++) HAL_OPAMP_SelfCalibrate:
52        (+++) Runs automatically the calibration.
53        (+++) Enables the user trimming mode
54        (+++) Updates the init structure with trimming values with fresh calibration
55             results.
56             The user may store the calibration results for larger
57             (ex monitoring the trimming as a function of temperature
58             for instance)
59        (+++) HAL_OPAMPEx_SelfCalibrateAll
60             runs calibration of all OPAMPs in parallel to save search time.
61 
62        (#) Running mode: Standalone mode
63        (++) Gain is set externally (gain depends on external loads).
64        (++) Follower mode also possible externally by connecting the inverting input to
65            the output.
66 
67        (#) Running mode: Follower mode
68        (++) No Inverting Input is connected.
69 
70        (#) Running mode: Programmable Gain Amplifier (PGA) mode
71            (Resistor feedback output)
72        (++) The OPAMP(s) output(s) can be internally connected to resistor feedback
73            output.
74        (++) OPAMP gain is either 2, 4, 8 or 16.
75 
76        (#) The OPAMPs inverting input can be selected according to the Reference Manual
77            "OPAMP function description" chapter.
78 
79        (#) The OPAMPs non inverting input can be selected according to the Reference Manual
80            "OPAMP function description" chapter.
81 
82 
83             ##### How to use this driver #####
84 ================================================================================
85   [..]
86 
87     *** Power supply range ***
88     ============================================
89     [..] To run in low power mode:
90 
91       (#) Configure the OPAMP using HAL_OPAMP_Init() function:
92       (++) Select OPAMP_POWERSUPPLY_LOW (VDDA lower than 2.4V)
93       (++) Otherwise select OPAMP_POWERSUPPLY_HIGH (VDDA higher than 2.4V)
94 
95     *** Low / normal power mode ***
96     ============================================
97     [..] To run in low power mode:
98 
99       (#) Configure the OPAMP using HAL_OPAMP_Init() function:
100       (++) Select OPAMP_POWERMODE_LOWPOWER
101       (++) Otherwise select OPAMP_POWERMODE_NORMALPOWER
102 
103     *** Calibration ***
104     ============================================
105     [..] To run the OPAMP calibration self calibration:
106 
107       (#) Start calibration using HAL_OPAMP_SelfCalibrate.
108            Store the calibration results.
109 
110     *** Running mode ***
111     ============================================
112 
113     [..] To use the OPAMP, perform the following steps:
114 
115       (#) Fill in the HAL_OPAMP_MspInit() to
116       (++) Enable the OPAMP Peripheral clock using macro __HAL_RCC_OPAMP_CLK_ENABLE()
117       (++) Configure the OPAMP input AND output in analog mode using
118            HAL_GPIO_Init() to map the OPAMP output to the GPIO pin.
119 
120       (#) Registrate Callbacks
121       (++) The compilation define  USE_HAL_OPAMP_REGISTER_CALLBACKS when set to 1
122            allows the user to configure dynamically the driver callbacks.
123 
124       (++) Use Functions HAL_OPAMP_RegisterCallback() to register a user callback,
125            it allows to register following callbacks:
126       (+++) MspInitCallback         : OPAMP MspInit.
127       (+++) MspDeInitCallback       : OPAMP MspFeInit.
128            This function takes as parameters the HAL peripheral handle, the Callback ID
129            and a pointer to the user callback function.
130 
131       (++) Use function HAL_OPAMP_UnRegisterCallback() to reset a callback to the default
132            weak (surcharged) function. It allows to reset following callbacks:
133       (+++) MspInitCallback         : OPAMP MspInit.
134       (+++) MspDeInitCallback       : OPAMP MspdeInit.
135       (+++) All Callbacks
136 
137       (#) Configure the OPAMP using HAL_OPAMP_Init() function:
138       (++) Select the mode
139       (++) Select the inverting input
140       (++) Select the non-inverting input
141       (++) If PGA mode is enabled, Select if inverting input is connected.
142       (++) Select either factory or user defined trimming mode.
143       (++) If the user-defined trimming mode is enabled, select PMOS & NMOS trimming values
144           (typically values set by HAL_OPAMP_SelfCalibrate function).
145 
146       (#) Enable the OPAMP using HAL_OPAMP_Start() function.
147 
148       (#) Disable the OPAMP using HAL_OPAMP_Stop() function.
149 
150       (#) Lock the OPAMP in running mode using HAL_OPAMP_Lock() function.
151           Caution: On STM32L5, HAL OPAMP lock is software lock only (not
152           hardware lock as on some other STM32 devices)
153 
154       (#) If needed, unlock the OPAMP using HAL_OPAMPEx_Unlock() function.
155 
156     *** Running mode: change of configuration while OPAMP ON  ***
157     ============================================
158     [..] To Re-configure OPAMP when OPAMP is ON (change on the fly)
159       (#) If needed, fill in the HAL_OPAMP_MspInit()
160       (++) This is the case for instance if you wish to use new OPAMP I/O
161 
162       (#) Configure the OPAMP using HAL_OPAMP_Init() function:
163       (++) As in configure case, select first the parameters you wish to modify.
164 
165       (#) Change from low power mode to normal power mode (& vice versa) requires
166           first HAL_OPAMP_DeInit() (force OPAMP OFF) and then HAL_OPAMP_Init().
167           In other words, of OPAMP is ON, HAL_OPAMP_Init can NOT change power mode
168           alone.
169 
170   @endverbatim
171   ******************************************************************************
172 
173       Table 1.  OPAMPs inverting/non-inverting inputs for the STM32L5 devices:
174       +------------------------------------------------------------------------|
175       |                 |         | OPAMP1               | OPAMP2              |
176       |-----------------|---------|----------------------|---------------------|
177       | Inverting Input | VM_SEL  |                      |                     |
178       |                 |         |  IO0-> PA1           | IO0-> PA7           |
179       |                 |         |  LOW LEAKAGE IO (2)  | LOW LEAKAGE IO (2)  |
180       |                 |         |  Not connected       | Not connected       |
181       | (1)             |         |    PGA mode only     |   PGA mode only     |
182       |-----------------|---------|----------------------|---------------------|
183       |  Non Inverting  | VP_SEL  |                      |                     |
184       |                 |         |  IO0-> PA0 (GPIO)    | IO0-> PA6  (GPIO)   |
185       |    Input        |         |  DAC1_OUT1 internal  | DAC1_OUT2 internal  |
186       +------------------------------------------------------------------------|
187        (1): NA in follower mode.
188        (2): Available on some package only (ex. BGA132).
189 
190 
191       Table 2.  OPAMPs outputs for the STM32L5 devices:
192 
193       +-------------------------------------------------------------------------
194       |                 |        | OPAMP1                | OPAMP2              |
195       |-----------------|--------|-----------------------|---------------------|
196       | Output          |  VOUT  |  PA3                  |  PB0                |
197       |                 |        |  & (1) ADC12_IN if    | & (1) ADC12_IN if   |
198       |                 |        |  connected internally | connected internally|
199       |-----------------|--------|-----------------------|---------------------|
200        (1): ADC1 or ADC2 shall select IN15.
201   */
202 
203 /* Includes ------------------------------------------------------------------*/
204 #include "stm32l5xx_hal.h"
205 
206 /** @addtogroup STM32L5xx_HAL_Driver
207   * @{
208   */
209 
210 /** @defgroup OPAMP OPAMP
211   * @brief OPAMP module driver
212   * @{
213   */
214 
215 #ifdef HAL_OPAMP_MODULE_ENABLED
216 
217 /* Private types -------------------------------------------------------------*/
218 /* Private variables ---------------------------------------------------------*/
219 /* Private constants ---------------------------------------------------------*/
220 /** @addtogroup OPAMP_Private_Constants
221   * @{
222   */
223 
224 /* CSR register reset value */
225 #define OPAMP_CSR_RESET_VALUE             ((uint32_t)0x00000000)
226 
227 #define OPAMP_CSR_RESET_BITS    (OPAMP_CSR_OPAMPxEN | OPAMP_CSR_OPALPM | OPAMP_CSR_OPAMODE \
228                                | OPAMP_CSR_PGGAIN | OPAMP_CSR_VMSEL | OPAMP_CSR_VPSEL \
229                                | OPAMP_CSR_CALON | OPAMP_CSR_USERTRIM)
230 
231 /* CSR Init masks */
232 #define OPAMP_CSR_INIT_MASK_PGA (OPAMP_CSR_OPALPM | OPAMP_CSR_OPAMODE| OPAMP_CSR_PGGAIN \
233                                | OPAMP_CSR_VMSEL | OPAMP_CSR_VPSEL | OPAMP_CSR_USERTRIM)
234 
235 #define OPAMP_CSR_INIT_MASK_FOLLOWER (OPAMP_CSR_OPALPM | OPAMP_CSR_OPAMODE| OPAMP_CSR_VPSEL \
236                                     | OPAMP_CSR_USERTRIM)
237 
238 #define OPAMP_CSR_INIT_MASK_STANDALONE (OPAMP_CSR_OPALPM | OPAMP_CSR_OPAMODE| OPAMP_CSR_VPSEL \
239                                       | OPAMP_CSR_VMSEL | OPAMP_CSR_USERTRIM)
240 
241 
242 /**
243   * @}
244   */
245 
246 /* Private macros ------------------------------------------------------------*/
247 /* Private functions ---------------------------------------------------------*/
248 /* Exported functions --------------------------------------------------------*/
249 
250 /** @defgroup OPAMP_Exported_Functions OPAMP Exported Functions
251   * @{
252   */
253 
254 /** @defgroup OPAMP_Exported_Functions_Group1 Initialization and de-initialization functions
255  *  @brief    Initialization and Configuration functions
256  *
257 @verbatim
258   ==============================================================================
259               ##### Initialization and de-initialization functions #####
260   ==============================================================================
261 
262 @endverbatim
263   * @{
264   */
265 
266 /**
267   * @brief  Initializes the OPAMP according to the specified
268   *         parameters in the OPAMP_InitTypeDef and initialize the associated handle.
269   * @note   If the selected opamp is locked, initialization can't be performed.
270   *         To unlock the configuration, perform a system reset.
271   * @param  hopamp OPAMP handle
272   * @retval HAL status
273   */
HAL_OPAMP_Init(OPAMP_HandleTypeDef * hopamp)274 HAL_StatusTypeDef HAL_OPAMP_Init(OPAMP_HandleTypeDef *hopamp)
275 {
276   HAL_StatusTypeDef status = HAL_OK;
277   uint32_t updateotrlpotr;
278 
279   /* Check the OPAMP handle allocation and lock status */
280   /* Init not allowed if calibration is ongoing */
281   if(hopamp == NULL)
282   {
283     return HAL_ERROR;
284   }
285   else if(hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
286   {
287     return HAL_ERROR;
288   }
289   else if(hopamp->State == HAL_OPAMP_STATE_CALIBBUSY)
290   {
291     return HAL_ERROR;
292   }
293   else
294   {
295     /* Check the parameter */
296     assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
297 
298     /* Set OPAMP parameters */
299     assert_param(IS_OPAMP_POWER_SUPPLY_RANGE(hopamp->Init.PowerSupplyRange));
300     assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode));
301     assert_param(IS_OPAMP_FUNCTIONAL_NORMALMODE(hopamp->Init.Mode));
302     assert_param(IS_OPAMP_NONINVERTING_INPUT(hopamp->Init.NonInvertingInput));
303 
304 #if (USE_HAL_OPAMP_REGISTER_CALLBACKS == 1)
305     if(hopamp->State == HAL_OPAMP_STATE_RESET)
306     {
307       if(hopamp->MspInitCallback == NULL)
308       {
309         hopamp->MspInitCallback               = HAL_OPAMP_MspInit;
310       }
311     }
312 #endif /* USE_HAL_OPAMP_REGISTER_CALLBACKS */
313 
314     if ((hopamp->Init.Mode) == OPAMP_STANDALONE_MODE)
315     {
316       assert_param(IS_OPAMP_INVERTING_INPUT_STANDALONE(hopamp->Init.InvertingInput));
317     }
318 
319     if ((hopamp->Init.Mode) == OPAMP_PGA_MODE)
320     {
321       assert_param(IS_OPAMP_INVERTING_INPUT_PGA(hopamp->Init.InvertingInput));
322     }
323 
324     if ((hopamp->Init.Mode) == OPAMP_PGA_MODE)
325     {
326       assert_param(IS_OPAMP_PGA_GAIN(hopamp->Init.PgaGain));
327     }
328 
329     assert_param(IS_OPAMP_TRIMMING(hopamp->Init.UserTrimming));
330     if ((hopamp->Init.UserTrimming) == OPAMP_TRIMMING_USER)
331     {
332       if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMALPOWER)
333       {
334         assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueP));
335         assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueN));
336       }
337     else
338       {
339         assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValuePLowPower));
340         assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueNLowPower));
341       }
342     }
343 
344     if(hopamp->State == HAL_OPAMP_STATE_RESET)
345     {
346       /* Allocate lock resource and initialize it */
347       hopamp->Lock = HAL_UNLOCKED;
348     }
349 
350 #if (USE_HAL_OPAMP_REGISTER_CALLBACKS == 1)
351     hopamp->MspInitCallback(hopamp);
352 #else
353     /* Call MSP init function */
354     HAL_OPAMP_MspInit(hopamp);
355 #endif /* USE_HAL_OPAMP_REGISTER_CALLBACKS */
356 
357     /* Set operating mode */
358     CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALON);
359 
360     if (hopamp->Init.Mode == OPAMP_PGA_MODE)
361     {
362       MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_INIT_MASK_PGA, \
363                                         hopamp->Init.PowerMode | \
364                                         hopamp->Init.Mode | \
365                                         hopamp->Init.PgaGain | \
366                                         hopamp->Init.InvertingInput    | \
367                                         hopamp->Init.NonInvertingInput | \
368                                         hopamp->Init.UserTrimming);
369     }
370 
371     if (hopamp->Init.Mode == OPAMP_FOLLOWER_MODE)
372     {
373     /* In Follower mode InvertingInput is Not Applicable  */
374     MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_INIT_MASK_FOLLOWER, \
375                                         hopamp->Init.PowerMode | \
376                                         hopamp->Init.Mode | \
377                                         hopamp->Init.NonInvertingInput | \
378                                         hopamp->Init.UserTrimming);
379     }
380 
381     if (hopamp->Init.Mode == OPAMP_STANDALONE_MODE)
382     {
383       MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_INIT_MASK_STANDALONE, \
384                                         hopamp->Init.PowerMode | \
385                                         hopamp->Init.Mode | \
386                                         hopamp->Init.InvertingInput    | \
387                                         hopamp->Init.NonInvertingInput | \
388                                         hopamp->Init.UserTrimming);
389     }
390 
391     if (hopamp->Init.UserTrimming == OPAMP_TRIMMING_USER)
392     {
393       /* Set power mode and associated calibration parameters */
394       if (hopamp->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
395       {
396         /* OPAMP_POWERMODE_NORMALPOWER */
397         /* Set calibration mode (factory or user) and values for            */
398         /* transistors differential pair high (PMOS) and low (NMOS) for     */
399         /* normal mode.                                                     */
400         updateotrlpotr = (((hopamp->Init.TrimmingValueP) << (OPAMP_INPUT_NONINVERTING)) \
401                          | (hopamp->Init.TrimmingValueN));
402         MODIFY_REG(hopamp->Instance->OTR, OPAMP_OTR_TRIMOFFSETN | OPAMP_OTR_TRIMOFFSETP, updateotrlpotr);
403       }
404       else
405       {
406         /* OPAMP_POWERMODE_LOWPOWER */
407         /* transistors differential pair high (PMOS) and low (NMOS) for     */
408         /* low power mode.                                                     */
409         updateotrlpotr = (((hopamp->Init.TrimmingValuePLowPower) << (OPAMP_INPUT_NONINVERTING)) \
410                          | (hopamp->Init.TrimmingValueNLowPower));
411         MODIFY_REG(hopamp->Instance->LPOTR, OPAMP_OTR_TRIMOFFSETN | OPAMP_OTR_TRIMOFFSETP, updateotrlpotr);
412       }
413     }
414 
415     /* Configure the power supply range */
416     /* The OPAMP_CSR_OPARANGE is common configuration for all OPAMPs */
417     /* bit OPAMP1_CSR_OPARANGE is used for both OPAMPs */
418     MODIFY_REG(OPAMP1->CSR, OPAMP1_CSR_OPARANGE, hopamp->Init.PowerSupplyRange);
419 
420     /* Update the OPAMP state*/
421     if (hopamp->State == HAL_OPAMP_STATE_RESET)
422     {
423       /* From RESET state to READY State */
424       hopamp->State = HAL_OPAMP_STATE_READY;
425     }
426     /* else: remain in READY or BUSY state (no update) */
427     return status;
428   }
429 }
430 
431 /**
432   * @brief  DeInitialize the OPAMP peripheral.
433   * @note   Deinitialization can be performed if the OPAMP configuration is locked.
434   *         (the lock is SW in L5)
435   * @param  hopamp OPAMP handle
436   * @retval HAL status
437   */
HAL_OPAMP_DeInit(OPAMP_HandleTypeDef * hopamp)438 HAL_StatusTypeDef HAL_OPAMP_DeInit(OPAMP_HandleTypeDef *hopamp)
439 {
440   HAL_StatusTypeDef status = HAL_OK;
441 
442   /* Check the OPAMP handle allocation */
443   /* DeInit not allowed if calibration is ongoing */
444   if(hopamp == NULL)
445   {
446     status = HAL_ERROR;
447   }
448   else if(hopamp->State == HAL_OPAMP_STATE_CALIBBUSY)
449   {
450     status = HAL_ERROR;
451   }
452   else
453   {
454     /* Check the parameter */
455     assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
456 
457     /* Set OPAMP_CSR register to reset value */
458     /* Mind that OPAMP1_CSR_OPARANGE of CSR of OPAMP1 remains unchanged (applies to both OPAMPs) */
459     /* OPAMP shall be disabled first separately */
460     CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
461     MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_RESET_BITS, OPAMP_CSR_RESET_VALUE);
462 
463 #if (USE_HAL_OPAMP_REGISTER_CALLBACKS == 1)
464   if(hopamp->MspDeInitCallback == NULL)
465   {
466     hopamp->MspDeInitCallback = HAL_OPAMP_MspDeInit;
467   }
468   /* DeInit the low level hardware */
469   hopamp->MspDeInitCallback(hopamp);
470 #else
471     /* DeInit the low level hardware: GPIO, CLOCK and NVIC */
472     HAL_OPAMP_MspDeInit(hopamp);
473 #endif /* USE_HAL_OPAMP_REGISTER_CALLBACKS */
474     /* Update the OPAMP state*/
475     hopamp->State = HAL_OPAMP_STATE_RESET;
476 
477     /* Process unlocked */
478     __HAL_UNLOCK(hopamp);
479   }
480   return status;
481 }
482 
483 /**
484   * @brief  Initialize the OPAMP MSP.
485   * @param  hopamp OPAMP handle
486   * @retval None
487   */
HAL_OPAMP_MspInit(OPAMP_HandleTypeDef * hopamp)488 __weak void HAL_OPAMP_MspInit(OPAMP_HandleTypeDef *hopamp)
489 {
490   /* Prevent unused argument(s) compilation warning */
491   UNUSED(hopamp);
492 
493   /* NOTE : This function should not be modified, when the callback is needed,
494             the function "HAL_OPAMP_MspInit()" must be implemented in the user file.
495    */
496 }
497 
498 /**
499   * @brief  DeInitialize OPAMP MSP.
500   * @param  hopamp OPAMP handle
501   * @retval None
502   */
HAL_OPAMP_MspDeInit(OPAMP_HandleTypeDef * hopamp)503 __weak void HAL_OPAMP_MspDeInit(OPAMP_HandleTypeDef *hopamp)
504 {
505   /* Prevent unused argument(s) compilation warning */
506   UNUSED(hopamp);
507 
508   /* NOTE : This function should not be modified, when the callback is needed,
509             the function "HAL_OPAMP_MspDeInit()" must be implemented in the user file.
510    */
511 }
512 
513 /**
514   * @}
515   */
516 
517 
518 /** @defgroup OPAMP_Exported_Functions_Group2 IO operation functions
519  *  @brief   IO operation functions
520  *
521 @verbatim
522  ===============================================================================
523                         ##### IO operation functions #####
524  ===============================================================================
525     [..]
526     This subsection provides a set of functions allowing to manage the OPAMP
527     start, stop and calibration actions.
528 
529 @endverbatim
530   * @{
531   */
532 
533 /**
534   * @brief  Start the OPAMP.
535   * @param  hopamp OPAMP handle
536   * @retval HAL status
537   */
538 
HAL_OPAMP_Start(OPAMP_HandleTypeDef * hopamp)539 HAL_StatusTypeDef HAL_OPAMP_Start(OPAMP_HandleTypeDef *hopamp)
540 {
541   HAL_StatusTypeDef status = HAL_OK;
542 
543   /* Check the OPAMP handle allocation */
544   /* Check if OPAMP locked */
545   if(hopamp == NULL)
546   {
547     status = HAL_ERROR;
548   }
549   else if(hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
550   {
551     status = HAL_ERROR;
552   }
553   else
554   {
555     /* Check the parameter */
556     assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
557 
558     if(hopamp->State == HAL_OPAMP_STATE_READY)
559     {
560       /* Enable the selected opamp */
561       SET_BIT (hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
562 
563       /* Update the OPAMP state*/
564       /* From HAL_OPAMP_STATE_READY to HAL_OPAMP_STATE_BUSY */
565       hopamp->State = HAL_OPAMP_STATE_BUSY;
566     }
567     else
568     {
569       status = HAL_ERROR;
570     }
571 
572    }
573   return status;
574 }
575 
576 /**
577   * @brief  Stop the OPAMP.
578   * @param  hopamp OPAMP handle
579   * @retval HAL status
580   */
HAL_OPAMP_Stop(OPAMP_HandleTypeDef * hopamp)581 HAL_StatusTypeDef HAL_OPAMP_Stop(OPAMP_HandleTypeDef *hopamp)
582 {
583   HAL_StatusTypeDef status = HAL_OK;
584 
585   /* Check the OPAMP handle allocation */
586   /* Check if OPAMP locked */
587   /* Check if OPAMP calibration ongoing */
588   if(hopamp == NULL)
589   {
590     status = HAL_ERROR;
591   }
592   else if(hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
593   {
594     status = HAL_ERROR;
595   }
596   else if(hopamp->State == HAL_OPAMP_STATE_CALIBBUSY)
597   {
598     status = HAL_ERROR;
599   }
600   else
601   {
602     /* Check the parameter */
603     assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
604 
605     if(hopamp->State == HAL_OPAMP_STATE_BUSY)
606     {
607       /* Disable the selected opamp */
608       CLEAR_BIT (hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
609 
610       /* Update the OPAMP state*/
611       /* From  HAL_OPAMP_STATE_BUSY to HAL_OPAMP_STATE_READY*/
612       hopamp->State = HAL_OPAMP_STATE_READY;
613     }
614     else
615     {
616       status = HAL_ERROR;
617     }
618   }
619   return status;
620 }
621 
622 /**
623   * @brief  Run the self calibration of one OPAMP.
624   * @note   Calibration is performed in the mode specified in OPAMP init
625   *         structure (mode normal or low-power). To perform calibration for
626   *         both modes, repeat this function twice after OPAMP init structure
627   *         accordingly updated.
628   * @note   Calibration runs about 10 ms.
629   * @param  hopamp handle
630   * @retval Updated offset trimming values (PMOS & NMOS), user trimming is enabled
631   * @retval HAL status
632 
633   */
634 
HAL_OPAMP_SelfCalibrate(OPAMP_HandleTypeDef * hopamp)635 HAL_StatusTypeDef HAL_OPAMP_SelfCalibrate(OPAMP_HandleTypeDef *hopamp)
636 {
637 
638   HAL_StatusTypeDef status = HAL_OK;
639 
640   uint32_t trimmingvaluen;
641   uint32_t trimmingvaluep;
642   uint32_t delta;
643   uint32_t opampmode;
644 
645   __IO uint32_t* tmp_opamp_reg_trimming;   /* Selection of register of trimming depending on power mode: OTR or LPOTR */
646 
647   /* Check the OPAMP handle allocation */
648   /* Check if OPAMP locked */
649   if(hopamp == NULL)
650   {
651     status = HAL_ERROR;
652   }
653   else if(hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
654   {
655     status = HAL_ERROR;
656   }
657   else
658   {
659     /* Check if OPAMP in calibration mode and calibration not yet enable */
660     if(hopamp->State ==  HAL_OPAMP_STATE_READY)
661     {
662       /* Check the parameter */
663       assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
664       assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode));
665 
666       /* The calibration is not working in PGA mode                  */
667       opampmode = READ_BIT(hopamp->Instance->CSR,OPAMP_CSR_OPAMODE);
668 
669       /* Use of standalone mode */
670       MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_OPAMODE, OPAMP_STANDALONE_MODE);
671 
672       /*  user trimming values are used for offset calibration */
673       SET_BIT(hopamp->Instance->CSR, OPAMP_CSR_USERTRIM);
674 
675       /* Select trimming settings depending on power mode */
676       if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMALPOWER)
677       {
678         tmp_opamp_reg_trimming = &hopamp->Instance->OTR;
679       }
680       else
681       {
682         tmp_opamp_reg_trimming = &hopamp->Instance->LPOTR;
683       }
684 
685       /* Enable calibration */
686       SET_BIT (hopamp->Instance->CSR, OPAMP_CSR_CALON);
687 
688       /* 1st calibration - N */
689       CLEAR_BIT (hopamp->Instance->CSR, OPAMP_CSR_CALSEL);
690 
691       /* Enable the selected opamp */
692       SET_BIT (hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
693 
694       /* Init trimming counter */
695       /* Medium value */
696       trimmingvaluen = 16U;
697       delta = 8U;
698 
699       while (delta != 0U)
700       {
701         /* Set candidate trimming */
702         /* OPAMP_POWERMODE_NORMALPOWER */
703         MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen);
704 
705         /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */
706         /* Offset trim time: during calibration, minimum time needed between */
707         /* two steps to have 1 mV accuracy */
708         HAL_Delay(OPAMP_TRIMMING_DELAY);
709 
710         if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
711         {
712           /* OPAMP_CSR_CALOUT is HIGH try higher trimming */
713           trimmingvaluen -= delta;
714         }
715         else
716         {
717           /* OPAMP_CSR_CALOUT is LOW try lower trimming */
718           trimmingvaluen += delta;
719         }
720         /* Divide range by 2 to continue dichotomy sweep */
721         delta >>= 1U;
722       }
723 
724       /* Still need to check if right calibration is current value or one step below */
725       /* Indeed the first value that causes the OUTCAL bit to change from 0 to 1  */
726       /* Set candidate trimming */
727       MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen);
728 
729       /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */
730       /* Offset trim time: during calibration, minimum time needed between */
731       /* two steps to have 1 mV accuracy */
732       HAL_Delay(OPAMP_TRIMMING_DELAY);
733 
734       if ((READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT)) == 0U)
735       {
736         /* Trimming value is actually one value more */
737         trimmingvaluen++;
738         /* Set right trimming */
739         MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen);
740       }
741 
742       /* 2nd calibration - P */
743       SET_BIT (hopamp->Instance->CSR, OPAMP_CSR_CALSEL);
744 
745       /* Init trimming counter */
746       /* Medium value */
747       trimmingvaluep = 16U;
748       delta = 8U;
749 
750       while (delta != 0U)
751       {
752         /* Set candidate trimming */
753         /* OPAMP_POWERMODE_NORMALPOWER */
754         MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep<<OPAMP_INPUT_NONINVERTING));
755 
756         /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */
757         /* Offset trim time: during calibration, minimum time needed between */
758         /* two steps to have 1 mV accuracy */
759         HAL_Delay(OPAMP_TRIMMING_DELAY);
760 
761         if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
762         {
763           /* OPAMP_CSR_CALOUT is HIGH try higher trimming */
764           trimmingvaluep += delta;
765         }
766         else
767         {
768           /* OPAMP_CSR_CALOUT  is LOW try lower trimming */
769           trimmingvaluep -= delta;
770         }
771 
772         /* Divide range by 2 to continue dichotomy sweep */
773         delta >>= 1U;
774       }
775 
776       /* Still need to check if right calibration is current value or one step below */
777       /* Indeed the first value that causes the OUTCAL bit to change from 1 to 0  */
778       /* Set candidate trimming */
779       MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep<<OPAMP_INPUT_NONINVERTING));
780 
781       /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */
782       /* Offset trim time: during calibration, minimum time needed between */
783       /* two steps to have 1 mV accuracy */
784       HAL_Delay(OPAMP_TRIMMING_DELAY);
785 
786       if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
787       {
788         /* Trimming value is actually one value more */
789         trimmingvaluep++;
790         MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep<<OPAMP_INPUT_NONINVERTING));
791       }
792 
793       /* Disable the OPAMP */
794       CLEAR_BIT (hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
795 
796       /* Disable calibration & set normal mode (operating mode) */
797       CLEAR_BIT (hopamp->Instance->CSR, OPAMP_CSR_CALON);
798 
799       /* Self calibration is successful  */
800       /* Store calibration(user trimming) results in init structure. */
801 
802       /* Set user trimming mode */
803       hopamp->Init.UserTrimming = OPAMP_TRIMMING_USER;
804 
805       /* Affect calibration parameters depending on mode normal/low power */
806       if (hopamp->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
807       {
808         /* Write calibration result N */
809         hopamp->Init.TrimmingValueN = trimmingvaluen;
810         /* Write calibration result P */
811         hopamp->Init.TrimmingValueP = trimmingvaluep;
812       }
813       else
814       {
815         /* Write calibration result N */
816         hopamp->Init.TrimmingValueNLowPower = trimmingvaluen;
817         /* Write calibration result P */
818         hopamp->Init.TrimmingValuePLowPower = trimmingvaluep;
819       }
820 
821     /* Restore OPAMP mode after calibration */
822     MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_OPAMODE, opampmode);
823     }
824     else
825     {
826       /* OPAMP can not be calibrated from this mode */
827       status = HAL_ERROR;
828     }
829   }
830   return status;
831 }
832 
833 /**
834   * @}
835   */
836 
837 /** @defgroup OPAMP_Exported_Functions_Group3 Peripheral Control functions
838  *  @brief   Peripheral Control functions
839  *
840 @verbatim
841  ===============================================================================
842                       ##### Peripheral Control functions #####
843  ===============================================================================
844     [..]
845     This subsection provides a set of functions allowing to control the OPAMP data
846     transfers.
847 
848 
849 
850 @endverbatim
851   * @{
852   */
853 
854 /**
855   * @brief  Lock the selected OPAMP configuration.
856   * @note   On STM32L5, HAL OPAMP lock is software lock only (in
857   *         contrast of hardware lock available on some other STM32
858   *         devices).
859   * @param  hopamp OPAMP handle
860   * @retval HAL status
861   */
HAL_OPAMP_Lock(OPAMP_HandleTypeDef * hopamp)862 HAL_StatusTypeDef HAL_OPAMP_Lock(OPAMP_HandleTypeDef *hopamp)
863 {
864   HAL_StatusTypeDef status = HAL_OK;
865 
866   /* Check the OPAMP handle allocation */
867   /* Check if OPAMP locked */
868   /* OPAMP can be locked when enabled and running in normal mode */
869   /*   It is meaningless otherwise */
870   if(hopamp == NULL)
871   {
872     status = HAL_ERROR;
873   }
874   else if(hopamp->State == HAL_OPAMP_STATE_BUSY)
875   {
876     /* Check the parameter */
877     assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
878 
879    /* OPAMP state changed to locked */
880     hopamp->State = HAL_OPAMP_STATE_BUSYLOCKED;
881   }
882   else
883   {
884     status = HAL_ERROR;
885   }
886   return status;
887 }
888 
889 /**
890   * @brief  Return the OPAMP factory trimming value.
891   * @note            On STM32L5 OPAMP, user can retrieve factory trimming if
892   *                  OPAMP has never been set to user trimming before.
893   *                  Therefore, this function must be called when OPAMP init
894   *                  parameter "UserTrimming" is set to trimming factory,
895   *                  and before OPAMP  calibration (function
896   *                  "HAL_OPAMP_SelfCalibrate()").
897   *                  Otherwise, factory trimming value cannot be retrieved and
898   *                  error status is returned.
899   * @param  hopamp : OPAMP handle
900   * @param  trimmingoffset : Trimming offset (P or N)
901   *         This parameter must be a value of @ref OPAMP_FactoryTrimming
902   * @note   Calibration parameter retrieved is corresponding to the mode
903   *         specified in OPAMP init structure (mode normal or low-power).
904   *         To retrieve calibration parameters for both modes, repeat this
905   *         function after OPAMP init structure accordingly updated.
906   * @retval Trimming value (P or N): range: 0->31
907   *         or OPAMP_FACTORYTRIMMING_DUMMY if trimming value is not available
908   *
909   */
910 
HAL_OPAMP_GetTrimOffset(OPAMP_HandleTypeDef * hopamp,uint32_t trimmingoffset)911 HAL_OPAMP_TrimmingValueTypeDef HAL_OPAMP_GetTrimOffset (OPAMP_HandleTypeDef *hopamp, uint32_t trimmingoffset)
912 {
913   HAL_OPAMP_TrimmingValueTypeDef trimmingvalue;
914   __IO uint32_t* tmp_opamp_reg_trimming;  /* Selection of register of trimming depending on power mode: OTR or LPOTR */
915 
916   /* Check the OPAMP handle allocation */
917   /* Value can be retrieved in HAL_OPAMP_STATE_READY state */
918   if(hopamp == NULL)
919   {
920     return OPAMP_FACTORYTRIMMING_DUMMY;
921   }
922 
923   /* Check the OPAMP handle allocation */
924   /* Value can be retrieved in HAL_OPAMP_STATE_READY state */
925   if(hopamp->State == HAL_OPAMP_STATE_READY)
926   {
927     /* Check the parameter */
928     assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
929     assert_param(IS_OPAMP_FACTORYTRIMMING(trimmingoffset));
930     assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode));
931 
932     /* Check the trimming mode */
933     if (READ_BIT(hopamp->Instance->CSR,OPAMP_CSR_USERTRIM) != 0U)
934     {
935       /* This function must called when OPAMP init parameter "UserTrimming"   */
936       /* is set to trimming factory, and before OPAMP calibration (function   */
937       /* "HAL_OPAMP_SelfCalibrate()").                                        */
938       /* Otherwise, factory trimming value cannot be retrieved and error       */
939       /* status is returned.                                                  */
940       trimmingvalue = OPAMP_FACTORYTRIMMING_DUMMY;
941     }
942     else
943     {
944       /* Select trimming settings depending on power mode */
945       if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMALPOWER)
946       {
947         tmp_opamp_reg_trimming = &OPAMP->OTR;
948       }
949       else
950       {
951         tmp_opamp_reg_trimming = &OPAMP->LPOTR;
952       }
953 
954       /* Get factory trimming  */
955       if (trimmingoffset == OPAMP_FACTORYTRIMMING_P)
956       {
957         /* OPAMP_FACTORYTRIMMING_P */
958         trimmingvalue = ((*tmp_opamp_reg_trimming) & OPAMP_OTR_TRIMOFFSETP) >> OPAMP_INPUT_NONINVERTING;
959       }
960       else
961       {
962         /* OPAMP_FACTORYTRIMMING_N */
963         trimmingvalue = (*tmp_opamp_reg_trimming) & OPAMP_OTR_TRIMOFFSETN;
964       }
965     }
966   }
967   else
968   {
969     return OPAMP_FACTORYTRIMMING_DUMMY;
970   }
971   return trimmingvalue;
972 }
973 
974 /**
975   * @}
976   */
977 
978 
979 /** @defgroup OPAMP_Exported_Functions_Group4 Peripheral State functions
980  *  @brief   Peripheral State functions
981  *
982 @verbatim
983  ===============================================================================
984                       ##### Peripheral State functions #####
985  ===============================================================================
986     [..]
987     This subsection permits to get in run-time the status of the peripheral.
988 
989 @endverbatim
990   * @{
991   */
992 
993 /**
994   * @brief  Return the OPAMP handle state.
995   * @param  hopamp : OPAMP handle
996   * @retval HAL state
997   */
HAL_OPAMP_GetState(OPAMP_HandleTypeDef * hopamp)998 HAL_OPAMP_StateTypeDef HAL_OPAMP_GetState(OPAMP_HandleTypeDef *hopamp)
999 {
1000   /* Check the OPAMP handle allocation */
1001   if(hopamp == NULL)
1002   {
1003     return HAL_OPAMP_STATE_RESET;
1004   }
1005 
1006   /* Check the parameter */
1007   assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
1008 
1009   /* Return OPAMP handle state */
1010   return hopamp->State;
1011 }
1012 
1013 /**
1014   * @}
1015   */
1016 
1017 #if (USE_HAL_OPAMP_REGISTER_CALLBACKS == 1)
1018 /**
1019   * @brief  Register a User OPAMP Callback
1020   *         To be used instead of the weak (surcharged) predefined callback
1021   * @param hopamp : OPAMP handle
1022   * @param CallbackID : ID of the callback to be registered
1023   *        This parameter can be one of the following values:
1024   *          @arg @ref HAL_OPAMP_MSPINIT_CB_ID       OPAMP MspInit callback ID
1025   *          @arg @ref HAL_OPAMP_MSPDEINIT_CB_ID     OPAMP MspDeInit callback ID
1026   * @param pCallback : pointer to the Callback function
1027   * @retval status
1028   */
HAL_OPAMP_RegisterCallback(OPAMP_HandleTypeDef * hopamp,HAL_OPAMP_CallbackIDTypeDef CallbackID,pOPAMP_CallbackTypeDef pCallback)1029 HAL_StatusTypeDef HAL_OPAMP_RegisterCallback (OPAMP_HandleTypeDef *hopamp, HAL_OPAMP_CallbackIDTypeDef CallbackID, pOPAMP_CallbackTypeDef pCallback)
1030 {
1031   HAL_StatusTypeDef status = HAL_OK;
1032 
1033   if(pCallback == NULL)
1034   {
1035     return HAL_ERROR;
1036   }
1037 
1038   /* Process locked */
1039   __HAL_LOCK(hopamp);
1040 
1041   if(hopamp->State == HAL_OPAMP_STATE_READY)
1042   {
1043     switch (CallbackID)
1044     {
1045     case HAL_OPAMP_MSPINIT_CB_ID :
1046       hopamp->MspInitCallback = pCallback;
1047       break;
1048     case HAL_OPAMP_MSPDEINIT_CB_ID :
1049       hopamp->MspDeInitCallback = pCallback;
1050       break;
1051     default :
1052       /* update return status */
1053       status =  HAL_ERROR;
1054       break;
1055     }
1056   }
1057   else if (hopamp->State == HAL_OPAMP_STATE_RESET)
1058   {
1059     switch (CallbackID)
1060     {
1061     case HAL_OPAMP_MSPINIT_CB_ID :
1062       hopamp->MspInitCallback = pCallback;
1063       break;
1064     case HAL_OPAMP_MSPDEINIT_CB_ID :
1065       hopamp->MspDeInitCallback = pCallback;
1066       break;
1067     default :
1068       /* update return status */
1069       status =  HAL_ERROR;
1070       break;
1071     }
1072   }
1073   else
1074   {
1075     /* update return status */
1076     status =  HAL_ERROR;
1077   }
1078 
1079   /* Release Lock */
1080   __HAL_UNLOCK(hopamp);
1081   return status;
1082 }
1083 
1084 /**
1085   * @brief  Unregister a User OPAMP Callback
1086   *         OPAMP Callback is redirected to the weak (surcharged) predefined callback
1087   * @param hopamp : OPAMP handle
1088   * @param CallbackID : ID of the callback to be unregistered
1089   *        This parameter can be one of the following values:
1090   *          @arg @ref HAL_OPAMP_MSPINIT_CB_ID              OPAMP MSP Init Callback ID
1091   *          @arg @ref HAL_OPAMP_MSPDEINIT_CB_ID            OPAMP MSP DeInit Callback ID
1092   *          @arg @ref HAL_OPAMP_ALL_CB_ID                   OPAMP All Callbacks
1093   * @retval status
1094   */
1095 
HAL_OPAMP_UnRegisterCallback(OPAMP_HandleTypeDef * hopamp,HAL_OPAMP_CallbackIDTypeDef CallbackID)1096 HAL_StatusTypeDef HAL_OPAMP_UnRegisterCallback (OPAMP_HandleTypeDef *hopamp, HAL_OPAMP_CallbackIDTypeDef CallbackID)
1097 {
1098   HAL_StatusTypeDef status = HAL_OK;
1099 
1100   /* Process locked */
1101   __HAL_LOCK(hopamp);
1102 
1103   if(hopamp->State == HAL_OPAMP_STATE_READY)
1104   {
1105     switch (CallbackID)
1106     {
1107       case HAL_OPAMP_MSPINIT_CB_ID :
1108       hopamp->MspInitCallback = HAL_OPAMP_MspInit;
1109       break;
1110     case HAL_OPAMP_MSPDEINIT_CB_ID :
1111       hopamp->MspDeInitCallback = HAL_OPAMP_MspDeInit;
1112       break;
1113     case HAL_OPAMP_ALL_CB_ID :
1114       hopamp->MspInitCallback = HAL_OPAMP_MspInit;
1115       hopamp->MspDeInitCallback = HAL_OPAMP_MspDeInit;
1116       break;
1117     default :
1118       /* update return status */
1119       status =  HAL_ERROR;
1120       break;
1121     }
1122   }
1123   else if (hopamp->State == HAL_OPAMP_STATE_RESET)
1124   {
1125     switch (CallbackID)
1126     {
1127     case HAL_OPAMP_MSPINIT_CB_ID :
1128       hopamp->MspInitCallback = HAL_OPAMP_MspInit;
1129       break;
1130     case HAL_OPAMP_MSPDEINIT_CB_ID :
1131       hopamp->MspDeInitCallback = HAL_OPAMP_MspDeInit;
1132       break;
1133     default :
1134       /* update return status */
1135       status =  HAL_ERROR;
1136       break;
1137     }
1138   }
1139   else
1140   {
1141     /* update return status */
1142     status =  HAL_ERROR;
1143   }
1144 
1145   /* Release Lock */
1146   __HAL_UNLOCK(hopamp);
1147   return status;
1148 }
1149 
1150 #endif /* USE_HAL_OPAMP_REGISTER_CALLBACKS */
1151 
1152   /**
1153   * @}
1154   */
1155 
1156 #endif /* HAL_OPAMP_MODULE_ENABLED */
1157 /**
1158   * @}
1159   */
1160 
1161 /**
1162   * @}
1163   */
1164 
1165