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