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