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