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) 2022 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 (surcharged) 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 /* Private types -----------------------------------------------------------------------------------------------------*/
231 /* Private variables -------------------------------------------------------------------------------------------------*/
232 /* Private constants -------------------------------------------------------------------------------------------------*/
233 /** @addtogroup OPAMP_Private_Constants
234   * @{
235   */
236 
237 /* CSR register reset value */
238 #define OPAMP_CSR_RESET_VALUE             0x00000000U
239 
240 /* CSR Init masks */
241 #define OPAMP_CSR_INIT_MASK_PGA (OPAMP_CSR_OPAHSM | OPAMP_CSR_VMSEL | OPAMP_CSR_PGGAIN | OPAMP_CSR_PGGAIN  \
242                                  | OPAMP_CSR_VPSEL | OPAMP_CSR_USERTRIM)
243 
244 
245 #define OPAMP_CSR_INIT_MASK_FOLLOWER (OPAMP_CSR_OPAHSM | OPAMP_CSR_VMSEL| OPAMP_CSR_VPSEL \
246                                       | OPAMP_CSR_USERTRIM)
247 
248 
249 #define OPAMP_CSR_INIT_MASK_STANDALONE (OPAMP_CSR_OPAHSM | OPAMP_CSR_VMSEL | OPAMP_CSR_VPSEL  \
250                                         | OPAMP_CSR_VMSEL | OPAMP_CSR_USERTRIM)
251 /**
252   * @}
253   */
254 
255 /* Private macros ----------------------------------------------------------------------------------------------------*/
256 /* Private functions -------------------------------------------------------------------------------------------------*/
257 /* Exported functions ------------------------------------------------------------------------------------------------*/
258 
259 /** @defgroup OPAMP_Exported_Functions OPAMP Exported Functions
260   * @{
261   */
262 
263 /** @defgroup OPAMP_Exported_Functions_Group1 Initialization and de-initialization functions
264   *  @brief    Initialization and Configuration functions
265   *
266 @verbatim
267   ======================================================================================================================
268                            ##### Initialization and de-initialization functions #####
269   ======================================================================================================================
270 
271 @endverbatim
272   * @{
273   */
274 
275 /**
276   * @brief  Initialize the OPAMP according to the specified
277   *         parameters in the OPAMP_InitTypeDef and initialize the associated handle.
278   * @note   If the selected opamp is locked, initialization can't be performed.
279   *         To unlock the configuration, perform a system reset.
280   * @param  hopamp OPAMP handle
281   * @retval HAL status
282   */
HAL_OPAMP_Init(OPAMP_HandleTypeDef * hopamp)283 HAL_StatusTypeDef HAL_OPAMP_Init(OPAMP_HandleTypeDef *hopamp)
284 {
285   HAL_StatusTypeDef status = HAL_OK;
286   uint32_t updateotrlpotr;
287 
288   /* Check the OPAMP handle allocation and lock status */
289   /* Init not allowed if calibration is ongoing */
290   if (hopamp == NULL)
291   {
292     return HAL_ERROR;
293   }
294   else if (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
295   {
296     return HAL_ERROR;
297   }
298   else if (hopamp->State == HAL_OPAMP_STATE_CALIBBUSY)
299   {
300     return HAL_ERROR;
301   }
302   else
303   {
304     /* Check the parameter */
305     assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
306 
307     /* Set OPAMP parameters */
308     assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode));
309     assert_param(IS_OPAMP_FUNCTIONAL_NORMALMODE(hopamp->Init.Mode));
310     assert_param(IS_OPAMP_NONINVERTING_INPUT(hopamp->Init.NonInvertingInput));
311 
312 #if (USE_HAL_OPAMP_REGISTER_CALLBACKS == 1U)
313     if (hopamp->State == HAL_OPAMP_STATE_RESET)
314     {
315       if (hopamp->MspInitCallback == NULL)
316       {
317         hopamp->MspInitCallback               = HAL_OPAMP_MspInit;
318       }
319     }
320 #endif /* USE_HAL_OPAMP_REGISTER_CALLBACKS */
321     if ((hopamp->Init.Mode) == OPAMP_STANDALONE_MODE)
322     {
323       assert_param(IS_OPAMP_INVERTING_INPUT_STANDALONE(hopamp->Init.InvertingInput));
324     }
325 
326     if ((hopamp->Init.Mode) == OPAMP_PGA_MODE)
327     {
328       assert_param(IS_OPAMP_PGA_GAIN(hopamp->Init.PgaGain));
329       assert_param(IS_OPAMP_PGACONNECT(hopamp->Init.PgaConnect));
330     }
331 
332 
333     assert_param(IS_OPAMP_TRIMMING(hopamp->Init.UserTrimming));
334 
335     if ((hopamp->Init.UserTrimming) == OPAMP_TRIMMING_USER)
336     {
337       if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
338       {
339         assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueP));
340         assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueN));
341       }
342       else
343       {
344         assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValuePHighSpeed));
345         assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueNHighSpeed));
346       }
347     }
348 
349     if (hopamp->State == HAL_OPAMP_STATE_RESET)
350     {
351       /* Allocate lock resource and initialize it */
352       hopamp->Lock = HAL_UNLOCKED;
353     }
354 
355 #if (USE_HAL_OPAMP_REGISTER_CALLBACKS == 1U)
356     hopamp->MspInitCallback(hopamp);
357 #else
358     /* Call MSP init function */
359     HAL_OPAMP_MspInit(hopamp);
360 #endif /* USE_HAL_OPAMP_REGISTER_CALLBACKS */
361 
362     /* Set operating mode */
363     CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALON);
364     /* In PGA mode InvertingInput is Not Applicable  */
365     if (hopamp->Init.Mode == OPAMP_PGA_MODE)
366     {
367       MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_INIT_MASK_PGA, \
368                  hopamp->Init.PowerMode | \
369                  hopamp->Init.Mode | \
370                  hopamp->Init.PgaGain | \
371                  hopamp->Init.PgaConnect | \
372                  hopamp->Init.NonInvertingInput | \
373                  hopamp->Init.UserTrimming);
374     }
375 
376     if (hopamp->Init.Mode == OPAMP_FOLLOWER_MODE)
377     {
378       /* In Follower mode InvertingInput is Not Applicable  */
379       MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_INIT_MASK_FOLLOWER, \
380                  hopamp->Init.PowerMode | \
381                  hopamp->Init.Mode | \
382                  hopamp->Init.NonInvertingInput | \
383                  hopamp->Init.UserTrimming);
384     }
385 
386     if (hopamp->Init.Mode == OPAMP_STANDALONE_MODE)
387     {
388       MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_INIT_MASK_STANDALONE, \
389                  hopamp->Init.PowerMode | \
390                  hopamp->Init.Mode | \
391                  hopamp->Init.InvertingInput    | \
392                  hopamp->Init.NonInvertingInput | \
393                  hopamp->Init.UserTrimming);
394     }
395 
396     if (hopamp->Init.UserTrimming == OPAMP_TRIMMING_USER)
397     {
398       /* Set power mode and associated calibration parameters */
399       if (hopamp->Init.PowerMode != OPAMP_POWERMODE_HIGHSPEED)
400       {
401         /* OPAMP_POWERMODE_NORMAL */
402         /* Set calibration mode (factory or user) and values for            */
403         /* transistors differential pair high (PMOS) and low (NMOS) for     */
404         /* normal mode.                                                     */
405         updateotrlpotr = (((hopamp->Init.TrimmingValueP) << (OPAMP_INPUT_NONINVERTING)) \
406                           | (hopamp->Init.TrimmingValueN));
407         MODIFY_REG(hopamp->Instance->OTR, OPAMP_OTR_TRIMOFFSETN | OPAMP_OTR_TRIMOFFSETP, updateotrlpotr);
408       }
409       else
410       {
411         /* OPAMP_POWERMODE_HIGHSPEED*/
412         /* transistors differential pair high (PMOS) and low (NMOS) for     */
413         /* high speed mode.                                                     */
414         updateotrlpotr = (((hopamp->Init.TrimmingValuePHighSpeed) << (OPAMP_INPUT_NONINVERTING)) \
415                           | (hopamp->Init.TrimmingValueNHighSpeed));
416         MODIFY_REG(hopamp->Instance->HSOTR, OPAMP_OTR_TRIMOFFSETN | OPAMP_OTR_TRIMOFFSETP, updateotrlpotr);
417       }
418     }
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 H7)
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 on going */
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     WRITE_REG(hopamp->Instance->CSR, OPAMP_CSR_RESET_VALUE);
459 
460     /* DeInit the low level hardware */
461 #if (USE_HAL_OPAMP_REGISTER_CALLBACKS == 1U)
462     if (hopamp->MspDeInitCallback == NULL)
463     {
464       hopamp->MspDeInitCallback = HAL_OPAMP_MspDeInit;
465     }
466     /* DeInit the low level hardware */
467     hopamp->MspDeInitCallback(hopamp);
468 #else
469     HAL_OPAMP_MspDeInit(hopamp);
470 #endif /* USE_HAL_OPAMP_REGISTER_CALLBACKS */
471 
472     /* Update the OPAMP state*/
473     hopamp->State = HAL_OPAMP_STATE_RESET;
474     /* Process unlocked */
475     __HAL_UNLOCK(hopamp);
476 
477   }
478 
479   return status;
480 }
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   /* NOTE : This function should not be modified, when the callback is needed,
508             the function "HAL_OPAMP_MspDeInit()" must be implemented in the user file.
509    */
510 }
511 
512 /**
513   * @}
514   */
515 
516 
517 /** @defgroup OPAMP_Exported_Functions_Group2 IO operation functions
518   *  @brief   IO operation functions
519   *
520 @verbatim
521  =======================================================================================================================
522                                           ##### IO operation functions #####
523  =======================================================================================================================
524     [..]
525     This subsection provides a set of functions allowing to manage the OPAMP
526     start, stop and calibration actions.
527 
528 @endverbatim
529   * @{
530   */
531 
532 /**
533   * @brief  Start the OPAMP.
534   * @param  hopamp OPAMP handle
535   * @retval HAL status
536   */
HAL_OPAMP_Start(OPAMP_HandleTypeDef * hopamp)537 HAL_StatusTypeDef HAL_OPAMP_Start(OPAMP_HandleTypeDef *hopamp)
538 {
539   HAL_StatusTypeDef status = HAL_OK;
540 
541   /* Check the OPAMP handle allocation */
542   /* Check if OPAMP locked */
543   if (hopamp == NULL)
544   {
545     status = HAL_ERROR;
546   }
547   else if (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
548   {
549     status = HAL_ERROR;
550   }
551   else
552   {
553     /* Check the parameter */
554     assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
555 
556     if (hopamp->State == HAL_OPAMP_STATE_READY)
557     {
558       /* Enable the selected opamp */
559       SET_BIT(hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
560 
561       /* Update the OPAMP state*/
562       /* From HAL_OPAMP_STATE_READY to HAL_OPAMP_STATE_BUSY */
563       hopamp->State = HAL_OPAMP_STATE_BUSY;
564     }
565     else
566     {
567       status = HAL_ERROR;
568     }
569 
570   }
571   return status;
572 }
573 
574 /**
575   * @brief  Stop the OPAMP.
576   * @param  hopamp OPAMP handle
577   * @retval HAL status
578   */
HAL_OPAMP_Stop(OPAMP_HandleTypeDef * hopamp)579 HAL_StatusTypeDef HAL_OPAMP_Stop(OPAMP_HandleTypeDef *hopamp)
580 {
581   HAL_StatusTypeDef status = HAL_OK;
582 
583   /* Check the OPAMP handle allocation */
584   /* Check if OPAMP locked */
585   /* Check if OPAMP calibration ongoing */
586   if (hopamp == NULL)
587   {
588     status = HAL_ERROR;
589   }
590   else if (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
591   {
592     status = HAL_ERROR;
593   }
594   else if (hopamp->State == HAL_OPAMP_STATE_CALIBBUSY)
595   {
596     status = HAL_ERROR;
597   }
598   else
599   {
600     /* Check the parameter */
601     assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
602 
603     if (hopamp->State == HAL_OPAMP_STATE_BUSY)
604     {
605       /* Disable the selected opamp */
606       CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
607 
608       /* Update the OPAMP state*/
609       /* From  HAL_OPAMP_STATE_BUSY to HAL_OPAMP_STATE_READY*/
610       hopamp->State = HAL_OPAMP_STATE_READY;
611     }
612     else
613     {
614       status = HAL_ERROR;
615     }
616   }
617   return status;
618 }
619 
620 /**
621   * @brief  Run the self calibration of one OPAMP.
622   * @note   Calibration is performed in the mode specified in OPAMP init
623   *         structure (mode normal or high-speed). To perform calibration for
624   *         both modes, repeat this function twice after OPAMP init structure
625   *         accordingly updated.
626   * @param  hopamp handle
627   * @retval Updated offset trimming values (PMOS & NMOS), user trimming is enabled
628   * @retval HAL status
629   */
HAL_OPAMP_SelfCalibrate(OPAMP_HandleTypeDef * hopamp)630 HAL_StatusTypeDef HAL_OPAMP_SelfCalibrate(OPAMP_HandleTypeDef *hopamp)
631 {
632 
633   HAL_StatusTypeDef status = HAL_OK;
634 
635   uint32_t trimmingvaluen;
636   uint32_t trimmingvaluep;
637   uint32_t delta;
638   uint32_t opampmode;
639 
640   /* Selection of register of trimming depending on power mode: OTR or HSOTR */
641   __IO uint32_t *tmp_opamp_reg_trimming;
642 
643   /* Check the OPAMP handle allocation */
644   /* Check if OPAMP locked */
645   if (hopamp == NULL)
646   {
647     status = HAL_ERROR;
648   }
649   else if (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
650   {
651     status = HAL_ERROR;
652   }
653   else
654   {
655 
656     /* Check if OPAMP in calibration mode and calibration not yet enable */
657     if (hopamp->State ==  HAL_OPAMP_STATE_READY)
658     {
659       /* Check the parameter */
660       assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
661       assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode));
662 
663       opampmode = READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_VMSEL);
664 
665       /* Use of standalone mode */
666       MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_VMSEL, OPAMP_STANDALONE_MODE);
667       /*  user trimming values are used for offset calibration */
668       SET_BIT(hopamp->Instance->CSR, OPAMP_CSR_USERTRIM);
669 
670       /* Select trimming settings depending on power mode */
671       if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
672       {
673         tmp_opamp_reg_trimming = &hopamp->Instance->OTR;
674 
675       }
676       else
677       {
678         /* high speed Mode */
679         tmp_opamp_reg_trimming = &hopamp->Instance->HSOTR;
680       }
681 
682 
683       /* Enable calibration */
684       SET_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALON);
685 
686       /* Force internal reference on VP */
687       SET_BIT(hopamp->Instance->CSR, OPAMP_CSR_FORCEVP);
688 
689       /* 1st calibration - N */
690       MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_90VDDA);
691 
692       /* Enable the selected opamp */
693       SET_BIT(hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
694 
695       /* Init trimming counter */
696       /* Medium value */
697       trimmingvaluen = 16U;
698       delta = 8U;
699 
700       while (delta != 0U)
701       {
702         /* Set candidate trimming */
703         /* OPAMP_POWERMODE_NORMAL */
704         MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen);
705 
706         /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
707         /* Offset trim time: during calibration, minimum time needed between */
708         /* two steps to have 1 mV accuracy */
709         HAL_Delay(OPAMP_TRIMMING_DELAY);
710 
711         if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
712         {
713           /* OPAMP_CSR_CALOUT is HIGH try higher trimming */
714           trimmingvaluen += delta;
715         }
716         else
717         {
718           /* OPAMP_CSR_CALOUT is LOW try lower trimming */
719           trimmingvaluen -= delta;
720         }
721         /* Divide range by 2 to continue dichotomy sweep */
722         delta >>= 1;
723       }
724 
725       /* Still need to check if right calibration is current value or one step below */
726       /* Indeed the first value that causes the OUTCAL bit to change from 1  to 0  */
727 
728       MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen);
729 
730       /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
731       /* Offset trim time: during calibration, minimum time needed between */
732       /* two steps to have 1 mV accuracy */
733       HAL_Delay(OPAMP_TRIMMING_DELAY);
734 
735       if ((READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT)) != 0U)
736       {
737         /* Trimming value is actually one value more */
738         trimmingvaluen++;
739         /* Set right trimming */
740         MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen);
741       }
742 
743       /* 2nd calibration - P */
744       MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_10VDDA);
745 
746       /* Init trimming counter */
747       /* Medium value */
748       trimmingvaluep = 16U;
749       delta = 8U;
750 
751       while (delta != 0U)
752       {
753         /* Set candidate trimming */
754         /* OPAMP_POWERMODE_NORMAL */
755         MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep << OPAMP_INPUT_NONINVERTING));
756 
757         /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
758         /* Offset trim time: during calibration, minimum time needed between */
759         /* two steps to have 1 mV accuracy */
760         HAL_Delay(OPAMP_TRIMMING_DELAY);
761 
762         if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
763         {
764           /* OPAMP_CSR_CALOUT is HIGH try higher trimming */
765           trimmingvaluep += delta;
766         }
767         else
768         {
769           /* OPAMP_CSR_CALOUT  is LOW try lower trimming */
770           trimmingvaluep -= delta;
771         }
772 
773         /* Divide range by 2 to continue dichotomy sweep */
774         delta >>= 1U;
775       }
776 
777       /* Still need to check if right calibration is current value or one step below */
778       /* Indeed the first value that causes the OUTCAL bit to change from 1 to 0  */
779       /* Set candidate trimming */
780       MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep << OPAMP_INPUT_NONINVERTING));
781 
782       /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
783       /* Offset trim time: during calibration, minimum time needed between */
784       /* two steps to have 1 mV accuracy */
785       HAL_Delay(OPAMP_TRIMMING_DELAY);
786 
787       if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
788       {
789         /* Trimming value is actually one value more */
790         trimmingvaluep++;
791         MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep << OPAMP_INPUT_NONINVERTING));
792       }
793 
794       /* Disable calibration & set normal mode (operating mode) */
795       CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALON);
796 
797       /* Disable the OPAMP */
798       CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
799 
800       /* Set operating mode back */
801       CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_FORCEVP);
802 
803       /* Self calibration is successful  */
804       /* Store calibration(user trimming) results in init structure. */
805 
806       /* Set user trimming mode */
807       hopamp->Init.UserTrimming = OPAMP_TRIMMING_USER;
808 
809       /* Affect calibration parameters depending on mode normal/high speed */
810       if (hopamp->Init.PowerMode != OPAMP_POWERMODE_HIGHSPEED)
811       {
812         /* Write calibration result N */
813         hopamp->Init.TrimmingValueN = trimmingvaluen;
814         /* Write calibration result P */
815         hopamp->Init.TrimmingValueP = trimmingvaluep;
816       }
817       else
818       {
819         /* Write calibration result N */
820         hopamp->Init.TrimmingValueNHighSpeed = trimmingvaluen;
821         /* Write calibration result P */
822         hopamp->Init.TrimmingValuePHighSpeed = trimmingvaluep;
823       }
824       /* Restore OPAMP mode after calibration */
825       MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_VMSEL, opampmode);
826     }
827 
828     else
829     {
830       /* OPAMP can not be calibrated from this mode */
831       status = HAL_ERROR;
832     }
833   }
834   return status;
835 }
836 
837 /**
838   * @}
839   */
840 
841 /** @defgroup OPAMP_Exported_Functions_Group3 Peripheral Control functions
842   *  @brief   Peripheral Control functions
843   *
844 @verbatim
845  =======================================================================================================================
846                                    ##### Peripheral Control functions #####
847  =======================================================================================================================
848     [..]
849     This subsection provides a set of functions allowing to control the OPAMP data
850     transfers.
851 
852 
853 
854 @endverbatim
855   * @{
856   */
857 
858 /**
859   * @brief  Lock the selected OPAMP configuration.
860   * @note   On STM32H5, HAL OPAMP lock is software lock only (in
861   *         contrast of hardware lock available on some other STM32
862   *         devices)
863   * @param  hopamp OPAMP handle
864   * @retval HAL status
865   */
HAL_OPAMP_Lock(OPAMP_HandleTypeDef * hopamp)866 HAL_StatusTypeDef HAL_OPAMP_Lock(OPAMP_HandleTypeDef *hopamp)
867 {
868   HAL_StatusTypeDef status = HAL_OK;
869 
870   /* Check the OPAMP handle allocation */
871   /* Check if OPAMP locked */
872   /* OPAMP can be locked when enabled and running in normal mode */
873   /*   It is meaningless otherwise */
874   if (hopamp == NULL)
875   {
876     status = HAL_ERROR;
877   }
878 
879   else if (hopamp->State != HAL_OPAMP_STATE_BUSY)
880   {
881     status = HAL_ERROR;
882   }
883   else
884   {
885     /* Check the parameter */
886     assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
887 
888     /* OPAMP state changed to locked */
889     hopamp->State = HAL_OPAMP_STATE_BUSYLOCKED;
890   }
891   return status;
892 }
893 
894 /**
895   * @brief  Return the OPAMP factory trimming value.
896   * @note   On STM32H5 OPAMP, user can retrieve factory trimming if
897   *         OPAMP has never been set to user trimming before.
898   *         Therefore, this function must be called when OPAMP init
899   *         parameter "UserTrimming" is set to trimming factory,
900   *         and before OPAMP  calibration (function
901   *         "HAL_OPAMP_SelfCalibrate()").
902   *         Otherwise, factory trimming value cannot be retrieved and
903   *         error status is returned.
904   * @param  hopamp  OPAMP handle
905   * @param  trimmingoffset  Trimming offset (P or N)
906   *         This parameter must be a value of @ref OPAMP_FactoryTrimming
907   * @note   Calibration parameter retrieved is corresponding to the mode
908   *         specified in OPAMP init structure (mode normal or high-speed).
909   *         To retrieve calibration parameters for both modes, repeat this
910   *         function after OPAMP init structure accordingly updated.
911   * @retval Trimming value (P or N): range: 0->31
912   *         or OPAMP_FACTORYTRIMMING_DUMMY if trimming value is not available
913   *
914   */
HAL_OPAMP_GetTrimOffset(const OPAMP_HandleTypeDef * hopamp,uint32_t trimmingoffset)915 HAL_OPAMP_TrimmingValueTypeDef HAL_OPAMP_GetTrimOffset(const OPAMP_HandleTypeDef *hopamp, uint32_t trimmingoffset)
916 {
917   HAL_OPAMP_TrimmingValueTypeDef trimmingvalue;
918 
919   /* Selection of register of trimming depending on power mode: OTR or LPOTR */
920   __IO uint32_t *tmp_opamp_reg_trimming;
921 
922   /* Check the OPAMP handle allocation */
923   /* Value can be retrieved in HAL_OPAMP_STATE_READY state */
924   if (hopamp == NULL)
925   {
926     return OPAMP_FACTORYTRIMMING_DUMMY;
927   }
928 
929   if (hopamp->State == HAL_OPAMP_STATE_READY)
930   {
931     /* Check the parameter */
932     assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
933     assert_param(IS_OPAMP_FACTORYTRIMMING(trimmingoffset));
934     assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode));
935 
936     /* Check the trimming mode */
937     if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_USERTRIM) != 0U)
938     {
939       /* This function must called when OPAMP init parameter "UserTrimming"   */
940       /* is set to trimming factory, and before OPAMP calibration (function   */
941       /* "HAL_OPAMP_SelfCalibrate()").                                        */
942       /* Otherwise, factory trimming value cannot be retrieved and error       */
943       /* status is returned.                                                  */
944       trimmingvalue = OPAMP_FACTORYTRIMMING_DUMMY;
945     }
946     else
947     {
948       /* Select trimming settings depending on power mode */
949       if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
950       {
951         tmp_opamp_reg_trimming = &hopamp->Instance->OTR;
952       }
953       else
954       {
955         tmp_opamp_reg_trimming = &hopamp->Instance->HSOTR;
956       }
957 
958       /* Get factory trimming  */
959       if (trimmingoffset == OPAMP_FACTORYTRIMMING_P)
960       {
961         /* OPAMP_FACTORYTRIMMING_P */
962         trimmingvalue = ((*tmp_opamp_reg_trimming) & OPAMP_OTR_TRIMOFFSETP) >> OPAMP_INPUT_NONINVERTING;
963       }
964       else
965       {
966         /* OPAMP_FACTORYTRIMMING_N */
967         trimmingvalue = (*tmp_opamp_reg_trimming) & OPAMP_OTR_TRIMOFFSETN;
968       }
969     }
970   }
971   else
972   {
973     return OPAMP_FACTORYTRIMMING_DUMMY;
974   }
975 
976   return trimmingvalue;
977 }
978 
979 /**
980   * @}
981   */
982 
983 
984 /** @defgroup OPAMP_Exported_Functions_Group4 Peripheral State functions
985   *  @brief   Peripheral State functions
986   *
987 @verbatim
988  =======================================================================================================================
989                                    ##### Peripheral State functions #####
990  =======================================================================================================================
991     [..]
992     This subsection permits to get in run-time the status of the peripheral.
993 
994 @endverbatim
995   * @{
996   */
997 
998 /**
999   * @brief  Return the OPAMP handle state.
1000   * @param  hopamp  OPAMP handle
1001   * @retval HAL state
1002   */
HAL_OPAMP_GetState(const OPAMP_HandleTypeDef * hopamp)1003 HAL_OPAMP_StateTypeDef HAL_OPAMP_GetState(const OPAMP_HandleTypeDef *hopamp)
1004 {
1005   /* Check the OPAMP handle allocation */
1006   if (hopamp == NULL)
1007   {
1008     return HAL_OPAMP_STATE_RESET;
1009   }
1010 
1011   /* Check the parameter */
1012   assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
1013 
1014   /* Return OPAMP handle state */
1015   return hopamp->State;
1016 }
1017 
1018 /**
1019   * @}
1020   */
1021 
1022 #if (USE_HAL_OPAMP_REGISTER_CALLBACKS == 1U)
1023 /**
1024   * @brief Register a User OPAMP Callback
1025   *        To be used instead of the weak (surcharged) predefined callback
1026   * @note  The HAL_OPAMP_RegisterCallback() may be called before HAL_OPAMP_Init() in HAL_OPAMP_STATE_RESET to register
1027   *        callbacks for HAL_OPAMP_MSPINIT_CB_ID and HAL_OPAMP_MSPDEINIT_CB_ID
1028   * @param hopamp  OPAMP handle
1029   * @param CallbackId  ID of the callback to be registered
1030   *        This parameter can be one of the following values:
1031   *          @arg @ref HAL_OPAMP_MSPINIT_CB_ID       OPAMP MspInit callback ID
1032   *          @arg @ref HAL_OPAMP_MSPDEINIT_CB_ID     OPAMP MspDeInit callback ID
1033   * @param pCallback  pointer to the Callback function
1034   * @retval status
1035   */
HAL_OPAMP_RegisterCallback(OPAMP_HandleTypeDef * hopamp,HAL_OPAMP_CallbackIDTypeDef CallbackId,pOPAMP_CallbackTypeDef pCallback)1036 HAL_StatusTypeDef HAL_OPAMP_RegisterCallback(OPAMP_HandleTypeDef *hopamp, HAL_OPAMP_CallbackIDTypeDef CallbackId,
1037                                              pOPAMP_CallbackTypeDef pCallback)
1038 {
1039   HAL_StatusTypeDef status = HAL_OK;
1040 
1041   if (pCallback == NULL)
1042   {
1043     return HAL_ERROR;
1044   }
1045 
1046   if (hopamp->State == HAL_OPAMP_STATE_READY)
1047   {
1048     switch (CallbackId)
1049     {
1050       case HAL_OPAMP_MSPINIT_CB_ID :
1051         hopamp->MspInitCallback = pCallback;
1052         break;
1053       case HAL_OPAMP_MSPDEINIT_CB_ID :
1054         hopamp->MspDeInitCallback = pCallback;
1055         break;
1056       default :
1057         /* update return status */
1058         status =  HAL_ERROR;
1059         break;
1060     }
1061   }
1062   else if (hopamp->State == HAL_OPAMP_STATE_RESET)
1063   {
1064     switch (CallbackId)
1065     {
1066       case HAL_OPAMP_MSPINIT_CB_ID :
1067         hopamp->MspInitCallback = pCallback;
1068         break;
1069       case HAL_OPAMP_MSPDEINIT_CB_ID :
1070         hopamp->MspDeInitCallback = pCallback;
1071         break;
1072       default :
1073         /* update return status */
1074         status =  HAL_ERROR;
1075         break;
1076     }
1077   }
1078   else
1079   {
1080     /* update return status */
1081     status =  HAL_ERROR;
1082   }
1083 
1084   return status;
1085 }
1086 
1087 /**
1088   * @brief Unregister a User OPAMP Callback
1089   *        OPAMP Callback is redirected to the weak (surcharged) predefined callback
1090   * @note  The HAL_OPAMP_UnRegisterCallback() may be called before HAL_OPAMP_Init() in HAL_OPAMP_STATE_RESET to un-register
1091   *        callbacks for HAL_OPAMP_MSPINIT_CB_ID and HAL_OPAMP_MSPDEINIT_CB_ID
1092   * @param hopamp  OPAMP handle
1093   * @param CallbackId  ID of the callback to be unregistered
1094   *        This parameter can be one of the following values:
1095   *          @arg @ref HAL_OPAMP_MSPINIT_CB_ID    OPAMP MSP Init Callback ID
1096   *          @arg @ref HAL_OPAMP_MSPDEINIT_CB_ID  OPAMP MSP DeInit Callback ID
1097   *          @arg @ref HAL_OPAMP_ALL_CB_ID        OPAMP All Callbacks
1098   * @retval status
1099   */
HAL_OPAMP_UnRegisterCallback(OPAMP_HandleTypeDef * hopamp,HAL_OPAMP_CallbackIDTypeDef CallbackId)1100 HAL_StatusTypeDef HAL_OPAMP_UnRegisterCallback(OPAMP_HandleTypeDef *hopamp, HAL_OPAMP_CallbackIDTypeDef CallbackId)
1101 {
1102   HAL_StatusTypeDef status = HAL_OK;
1103 
1104   if (hopamp->State == HAL_OPAMP_STATE_READY)
1105   {
1106     switch (CallbackId)
1107     {
1108       case HAL_OPAMP_MSPINIT_CB_ID :
1109         hopamp->MspInitCallback = HAL_OPAMP_MspInit;
1110         break;
1111       case HAL_OPAMP_MSPDEINIT_CB_ID :
1112         hopamp->MspDeInitCallback = HAL_OPAMP_MspDeInit;
1113         break;
1114       case HAL_OPAMP_ALL_CB_ID :
1115         hopamp->MspInitCallback = HAL_OPAMP_MspInit;
1116         hopamp->MspDeInitCallback = HAL_OPAMP_MspDeInit;
1117         break;
1118       default :
1119         /* update return status */
1120         status =  HAL_ERROR;
1121         break;
1122     }
1123   }
1124   else if (hopamp->State == HAL_OPAMP_STATE_RESET)
1125   {
1126     switch (CallbackId)
1127     {
1128       case HAL_OPAMP_MSPINIT_CB_ID :
1129         hopamp->MspInitCallback = HAL_OPAMP_MspInit;
1130         break;
1131       case HAL_OPAMP_MSPDEINIT_CB_ID :
1132         hopamp->MspDeInitCallback = HAL_OPAMP_MspDeInit;
1133         break;
1134       default :
1135         /* update return status */
1136         status =  HAL_ERROR;
1137         break;
1138     }
1139   }
1140   else
1141   {
1142     /* update return status */
1143     status =  HAL_ERROR;
1144   }
1145 
1146   return status;
1147 }
1148 
1149 #endif /* USE_HAL_OPAMP_REGISTER_CALLBACKS */
1150 /**
1151   * @}
1152   */
1153 
1154 /**
1155   * @}
1156   */
1157 #endif /* HAL_OPAMP_MODULE_ENABLED */
1158 /**
1159   * @}
1160   */
1161 
1162 /**
1163   * @}
1164   */
1165