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