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