1 /**
2 ******************************************************************************
3 * @file stm32f3xx_hal_opamp_ex.c
4 * @author MCD Application Team
5 * @brief Extended OPAMP HAL module driver.
6 *
7 * This file provides firmware functions to manage the following
8 * functionalities of the operational amplifier(s) peripheral:
9 * + Extended Initialization and de-initialization functions
10 * + Extended Peripheral Control functions
11 *
12 @verbatim
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 */
25
26 /* Includes ------------------------------------------------------------------*/
27 #include "stm32f3xx_hal.h"
28
29 /** @addtogroup STM32F3xx_HAL_Driver
30 * @{
31 */
32
33 #ifdef HAL_OPAMP_MODULE_ENABLED
34
35 #if defined (OPAMP1) || defined (OPAMP2) || defined (OPAMP3) || defined (OPAMP4)
36
37 /** @defgroup OPAMPEx OPAMPEx
38 * @brief OPAMP Extended HAL module driver.
39 * @{
40 */
41
42
43 /* Private typedef -----------------------------------------------------------*/
44 /* Private define ------------------------------------------------------------*/
45 /* Private macro -------------------------------------------------------------*/
46 /* Private variables ---------------------------------------------------------*/
47 /* Private function prototypes -----------------------------------------------*/
48 /* Exported functions ---------------------------------------------------------*/
49
50 /** @defgroup OPAMPEx_Exported_Functions OPAMP Extended Exported Functions
51 * @{
52 */
53
54
55 /** @defgroup OPAMPEx_Exported_Functions_Group1 Extended Input and Output operation functions
56 * @brief Extended Self calibration functions
57 *
58 @verbatim
59 ===============================================================================
60 ##### Extended IO operation functions #####
61 ===============================================================================
62 [..]
63
64 @endverbatim
65 * @{
66 */
67
68 #if defined(STM32F302xE) || \
69 defined(STM32F302xC)
70 /* 2 OPAMPS available */
71 /* 2 OPAMPS can be calibrated in parallel */
72
73 /**
74 * @brief Run the self calibration of 2 OPAMPs in parallel.
75 * @param hopamp1 handle
76 * @param hopamp2 handle
77 * @retval HAL status
78 * @note Updated offset trimming values (PMOS & NMOS), user trimming is enabled
79 * @note Calibration runs about 25 ms.
80 */
81
HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef * hopamp1,OPAMP_HandleTypeDef * hopamp2)82 HAL_StatusTypeDef HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef *hopamp1, OPAMP_HandleTypeDef *hopamp2)
83 {
84 HAL_StatusTypeDef status = HAL_OK;
85
86 uint32_t trimmingvaluen1;
87 uint32_t trimmingvaluep1;
88 uint32_t trimmingvaluen2;
89 uint32_t trimmingvaluep2;
90
91 uint32_t delta;
92
93 if ((hopamp1 == NULL) || (hopamp2 == NULL))
94 {
95 status = HAL_ERROR;
96 }
97 /* Check if OPAMP in calibration mode and calibration not yet enable */
98 else if (hopamp1->State != HAL_OPAMP_STATE_READY)
99 {
100 status = HAL_ERROR;
101 }
102 else if (hopamp2->State != HAL_OPAMP_STATE_READY)
103 {
104 status = HAL_ERROR;
105 }
106 else
107 {
108 /* Check the parameter */
109 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp1->Instance));
110 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp2->Instance));
111
112 /* Set Calibration mode */
113 /* Non-inverting input connected to calibration reference voltage. */
114 SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_FORCEVP);
115 SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_FORCEVP);
116
117 /* user trimming values are used for offset calibration */
118 SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_USERTRIM);
119 SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_USERTRIM);
120
121 /* Enable calibration */
122 SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALON);
123 SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALON);
124
125 /* 1st calibration - N */
126 /* Select 90U% VREF */
127 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_90VDDA);
128 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_90VDDA);
129
130 /* Enable the opamps */
131 SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_OPAMPxEN);
132 SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_OPAMPxEN);
133
134 /* Init trimming counter */
135 /* Medium value */
136 trimmingvaluen1 = 16U;
137 trimmingvaluen2 = 16U;
138 delta = 8U;
139
140 while (delta != 0U)
141 {
142 /* Set candidate trimming */
143 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen1 << OPAMP_INPUT_INVERTING);
144 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen2 << OPAMP_INPUT_INVERTING);
145
146 /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
147 /* Offset trim time: during calibration, minimum time needed between */
148 /* two steps to have 1 mV accuracy */
149 HAL_Delay(2U);
150
151 if (hopamp1->Instance->CSR & OPAMP_CSR_OUTCAL)
152 {
153 /* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
154 trimmingvaluen1 += delta;
155 }
156 else
157 {
158 /* OPAMP_CSR_OUTCAL is LOW try lower trimming */
159 trimmingvaluen1 -= delta;
160 }
161
162 if (hopamp2->Instance->CSR & OPAMP_CSR_OUTCAL)
163 {
164 /* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
165 trimmingvaluen2 += delta;
166 }
167 else
168 {
169 /* OPAMP_CSR_OUTCAL is LOW try lower trimming */
170 trimmingvaluen2 -= delta;
171 }
172
173 delta >>= 1U;
174 }
175
176 // Still need to check if right calibration is current value or un step below
177 // Indeed the first value that causes the OUTCAL bit to change from 1 to 0
178 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen1 << OPAMP_INPUT_INVERTING);
179 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen2 << OPAMP_INPUT_INVERTING);
180
181 /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
182 /* Offset trim time: during calibration, minimum time needed between */
183 /* two steps to have 1 mV accuracy */
184 HAL_Delay(2U);
185
186 if (hopamp1->Instance->CSR & OPAMP_CSR_OUTCAL)
187 {
188 /* OPAMP_CSR_OUTCAL is actually one value more */
189 trimmingvaluen1++;
190 /* Set right trimming */
191 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen1 << OPAMP_INPUT_INVERTING);
192 }
193
194 if (hopamp2->Instance->CSR & OPAMP_CSR_OUTCAL)
195 {
196 /* OPAMP_CSR_OUTCAL is actually one value more */
197 trimmingvaluen2++;
198 /* Set right trimming */
199 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen2 << OPAMP_INPUT_INVERTING);
200 }
201
202 /* 2nd calibration - P */
203 /* Select 10U% VREF */
204 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_10VDDA);
205 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_10VDDA);
206
207 /* Init trimming counter */
208 /* Medium value */
209 trimmingvaluep1 = 16U;
210 trimmingvaluep2 = 16U;
211 delta = 8U;
212
213 while (delta != 0U)
214 {
215 /* Set candidate trimming */
216 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep1 << OPAMP_INPUT_NONINVERTING);
217 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep2 << OPAMP_INPUT_NONINVERTING);
218
219 /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
220 /* Offset trim time: during calibration, minimum time needed between */
221 /* two steps to have 1 mV accuracy */
222 HAL_Delay(2U);
223
224 if (hopamp1->Instance->CSR & OPAMP_CSR_OUTCAL)
225 {
226 /* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
227 trimmingvaluep1 += delta;
228 }
229 else
230 {
231 trimmingvaluep1 -= delta;
232 }
233
234 if (hopamp2->Instance->CSR & OPAMP_CSR_OUTCAL)
235 {
236 /* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
237 trimmingvaluep2 += delta;
238 }
239 else
240 {
241 trimmingvaluep2 -= delta;
242 }
243
244 delta >>= 1U;
245 }
246
247 // Still need to check if right calibration is current value or un step below
248 // Indeed the first value that causes the OUTCAL bit to change from 1 to 0
249 /* Set candidate trimming */
250 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep1 << OPAMP_INPUT_NONINVERTING);
251 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep2 << OPAMP_INPUT_NONINVERTING);
252
253 /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
254 /* Offset trim time: during calibration, minimum time needed between */
255 /* two steps to have 1 mV accuracy */
256 HAL_Delay(2U);
257
258 if (hopamp1->Instance->CSR & OPAMP_CSR_OUTCAL)
259 {
260 /* OPAMP_CSR_OUTCAL is actually one value more */
261 trimmingvaluep1++;
262 /* Set right trimming */
263 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep1 << OPAMP_INPUT_NONINVERTING);
264 }
265
266 if (hopamp2->Instance->CSR & OPAMP_CSR_OUTCAL)
267 {
268 /* OPAMP_CSR_OUTCAL is actually one value more */
269 trimmingvaluep2++;
270 /* Set right trimming */
271 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep2 << OPAMP_INPUT_NONINVERTING);
272 }
273
274 /* Disable calibration */
275 CLEAR_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALON);
276 CLEAR_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALON);
277
278 /* Disable the OPAMPs */
279 CLEAR_BIT(hopamp1->Instance->CSR, OPAMP_CSR_OPAMPxEN);
280 CLEAR_BIT(hopamp2->Instance->CSR, OPAMP_CSR_OPAMPxEN);
281
282 /* Set operating mode back */
283 CLEAR_BIT(hopamp1->Instance->CSR, OPAMP_CSR_FORCEVP);
284 CLEAR_BIT(hopamp2->Instance->CSR, OPAMP_CSR_FORCEVP);
285
286 /* Self calibration is successful */
287 /* Store calibration(user trimming) results in init structure. */
288 /* Select user trimming mode */
289
290 /* Write calibration result N */
291 hopamp1->Init.TrimmingValueN = trimmingvaluen1;
292 hopamp2->Init.TrimmingValueN = trimmingvaluen2;
293
294 /* Write calibration result P */
295 hopamp1->Init.TrimmingValueP = trimmingvaluep1;
296 hopamp2->Init.TrimmingValueP = trimmingvaluep2;
297
298 /* Calibration */
299 hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER;
300 hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER;
301
302 /* Select user trimming mode */
303 /* And updated with calibrated settings */
304 hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER;
305 hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER;
306
307 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen1 << OPAMP_INPUT_INVERTING);
308 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen2 << OPAMP_INPUT_INVERTING);
309
310 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep1 << OPAMP_INPUT_NONINVERTING);
311 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep2 << OPAMP_INPUT_NONINVERTING);
312
313 }
314 return status;
315 }
316 #endif /* STM32F302xE || */
317 /* STM32F302xC */
318
319 #if defined(STM32F303xE) || defined(STM32F398xx) || \
320 defined(STM32F303xC) || defined(STM32F358xx)
321 /* 4 OPAMPS available */
322 /* 4 OPAMPS can be calibrated in parallel */
323
324 /**
325 * @brief Run the self calibration of 4 OPAMPs in parallel.
326 * @param hopamp1 handle
327 * @param hopamp2 handle
328 * @param hopamp3 handle
329 * @param hopamp4 handle
330 * @retval HAL status
331 * @note Updated offset trimming values (PMOS & NMOS), user trimming is enabled
332 * @note Calibration runs about 25 ms.
333 */
334
HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef * hopamp1,OPAMP_HandleTypeDef * hopamp2,OPAMP_HandleTypeDef * hopamp3,OPAMP_HandleTypeDef * hopamp4)335 HAL_StatusTypeDef HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef *hopamp1, OPAMP_HandleTypeDef *hopamp2, OPAMP_HandleTypeDef *hopamp3, OPAMP_HandleTypeDef *hopamp4)
336 {
337 HAL_StatusTypeDef status = HAL_OK;
338
339 uint32_t trimmingvaluen1;
340 uint32_t trimmingvaluep1;
341 uint32_t trimmingvaluen2;
342 uint32_t trimmingvaluep2;
343 uint32_t trimmingvaluen3;
344 uint32_t trimmingvaluep3;
345 uint32_t trimmingvaluen4;
346 uint32_t trimmingvaluep4;
347
348 uint32_t delta;
349
350 if ((hopamp1 == NULL) || (hopamp2 == NULL) || (hopamp3 == NULL) || (hopamp4 == NULL))
351 {
352 status = HAL_ERROR;
353 }
354 /* Check if OPAMP in calibration mode and calibration not yet enable */
355 else if (hopamp1->State != HAL_OPAMP_STATE_READY)
356 {
357 status = HAL_ERROR;
358 }
359 else if (hopamp2->State != HAL_OPAMP_STATE_READY)
360 {
361 status = HAL_ERROR;
362 }
363 else if (hopamp3->State != HAL_OPAMP_STATE_READY)
364 {
365 status = HAL_ERROR;
366 }
367 else if (hopamp3->State != HAL_OPAMP_STATE_READY)
368 {
369 status = HAL_ERROR;
370 }
371 else
372 {
373 /* Check the parameter */
374 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp1->Instance));
375 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp2->Instance));
376 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp3->Instance));
377 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp4->Instance));
378
379 /* Set Calibration mode */
380 /* Non-inverting input connected to calibration reference voltage. */
381 SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_FORCEVP);
382 SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_FORCEVP);
383 SET_BIT(hopamp3->Instance->CSR, OPAMP_CSR_FORCEVP);
384 SET_BIT(hopamp4->Instance->CSR, OPAMP_CSR_FORCEVP);
385
386 /* user trimming values are used for offset calibration */
387 SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_USERTRIM);
388 SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_USERTRIM);
389 SET_BIT(hopamp3->Instance->CSR, OPAMP_CSR_USERTRIM);
390 SET_BIT(hopamp4->Instance->CSR, OPAMP_CSR_USERTRIM);
391
392 /* Enable calibration */
393 SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALON);
394 SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALON);
395 SET_BIT(hopamp3->Instance->CSR, OPAMP_CSR_CALON);
396 SET_BIT(hopamp4->Instance->CSR, OPAMP_CSR_CALON);
397
398 /* 1st calibration - N */
399 /* Select 90U% VREF */
400 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_90VDDA);
401 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_90VDDA);
402 MODIFY_REG(hopamp3->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_90VDDA);
403 MODIFY_REG(hopamp4->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_90VDDA);
404
405 /* Enable the opamps */
406 SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_OPAMPxEN);
407 SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_OPAMPxEN);
408 SET_BIT(hopamp3->Instance->CSR, OPAMP_CSR_OPAMPxEN);
409 SET_BIT(hopamp4->Instance->CSR, OPAMP_CSR_OPAMPxEN);
410
411 /* Init trimming counter */
412 /* Medium value */
413 trimmingvaluen1 = 16U;
414 trimmingvaluen2 = 16U;
415 trimmingvaluen3 = 16U;
416 trimmingvaluen4 = 16U;
417 delta = 8U;
418
419 while (delta != 0U)
420 {
421 /* Set candidate trimming */
422 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen1 << OPAMP_INPUT_INVERTING);
423 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen2 << OPAMP_INPUT_INVERTING);
424 MODIFY_REG(hopamp3->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen3 << OPAMP_INPUT_INVERTING);
425 MODIFY_REG(hopamp4->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen4 << OPAMP_INPUT_INVERTING);
426
427 /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
428 /* Offset trim time: during calibration, minimum time needed between */
429 /* two steps to have 1 mV accuracy */
430 HAL_Delay(2U);
431
432 if ((hopamp1->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
433 {
434 /* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
435 trimmingvaluen1 += delta;
436 }
437 else
438 {
439 /* OPAMP_CSR_OUTCAL is LOW try lower trimming */
440 trimmingvaluen1 -= delta;
441 }
442
443 if ((hopamp2->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
444 {
445 /* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
446 trimmingvaluen2 += delta;
447 }
448 else
449 {
450 /* OPAMP_CSR_OUTCAL is LOW try lower trimming */
451 trimmingvaluen2 -= delta;
452 }
453
454 if ((hopamp3->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
455 {
456 /* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
457 trimmingvaluen3 += delta;
458 }
459 else
460 {
461 /* OPAMP_CSR_OUTCAL is LOW try lower trimming */
462 trimmingvaluen3 -= delta;
463 }
464
465 if ((hopamp4->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
466 {
467 /* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
468 trimmingvaluen4 += delta;
469 }
470 else
471 {
472 /* OPAMP_CSR_OUTCAL is LOW try lower trimming */
473 trimmingvaluen4 -= delta;
474 }
475
476 delta >>= 1U;
477 }
478
479 /* Still need to check if right calibration is current value or un step below */
480 /* Indeed the first value that causes the OUTCAL bit to change from 1 to 0U */
481 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen1 << OPAMP_INPUT_INVERTING);
482 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen2 << OPAMP_INPUT_INVERTING);
483 MODIFY_REG(hopamp3->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen3 << OPAMP_INPUT_INVERTING);
484 MODIFY_REG(hopamp4->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen4 << OPAMP_INPUT_INVERTING);
485
486 /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
487 /* Offset trim time: during calibration, minimum time needed between */
488 /* two steps to have 1 mV accuracy */
489 HAL_Delay(2U);
490
491 if ((hopamp1->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
492 {
493 /* OPAMP_CSR_OUTCAL is actually one value more */
494 trimmingvaluen1++;
495 /* Set right trimming */
496 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen1 << OPAMP_INPUT_INVERTING);
497 }
498
499 if ((hopamp2->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
500 {
501 /* OPAMP_CSR_OUTCAL is actually one value more */
502 trimmingvaluen2++;
503 /* Set right trimming */
504 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen2 << OPAMP_INPUT_INVERTING);
505 }
506
507 if ((hopamp3->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
508 {
509 /* OPAMP_CSR_OUTCAL is actually one value more */
510 trimmingvaluen3++;
511 /* Set right trimming */
512 MODIFY_REG(hopamp3->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen3 << OPAMP_INPUT_INVERTING);
513 }
514
515 if ((hopamp4->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
516 {
517 /* OPAMP_CSR_OUTCAL is actually one value more */
518 trimmingvaluen4++;
519 /* Set right trimming */
520 MODIFY_REG(hopamp4->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen4 << OPAMP_INPUT_INVERTING);
521 }
522
523 /* 2nd calibration - P */
524 /* Select 10U% VREF */
525 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_10VDDA);
526 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_10VDDA);
527 MODIFY_REG(hopamp3->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_10VDDA);
528 MODIFY_REG(hopamp4->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_10VDDA);
529
530 /* Init trimming counter */
531 /* Medium value */
532 trimmingvaluep1 = 16U;
533 trimmingvaluep2 = 16U;
534 trimmingvaluep3 = 16U;
535 trimmingvaluep4 = 16U;
536
537 delta = 8U;
538
539 while (delta != 0U)
540 {
541 /* Set candidate trimming */
542 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep1 << OPAMP_INPUT_NONINVERTING);
543 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep2 << OPAMP_INPUT_NONINVERTING);
544 MODIFY_REG(hopamp3->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep3 << OPAMP_INPUT_NONINVERTING);
545 MODIFY_REG(hopamp4->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep4 << OPAMP_INPUT_NONINVERTING);
546
547 /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
548 /* Offset trim time: during calibration, minimum time needed between */
549 /* two steps to have 1 mV accuracy */
550 HAL_Delay(2U);
551
552 if ((hopamp1->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
553 {
554 /* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
555 trimmingvaluep1 += delta;
556 }
557 else
558 {
559 trimmingvaluep1 -= delta;
560 }
561
562 if ((hopamp2->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
563 {
564 /* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
565 trimmingvaluep2 += delta;
566 }
567 else
568 {
569 trimmingvaluep2 -= delta;
570 }
571
572 if ((hopamp3->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
573 {
574 /* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
575 trimmingvaluep3 += delta;
576 }
577 else
578 {
579 trimmingvaluep3 -= delta;
580 }
581
582 if ((hopamp4->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
583 {
584 /* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
585 trimmingvaluep4 += delta;
586 }
587 else
588 {
589 trimmingvaluep4 -= delta;
590 }
591
592 delta >>= 1U;
593 }
594
595 /* Still need to check if right calibration is current value or un step below */
596 /* Indeed the first value that causes the OUTCAL bit to change from 1 to 0U */
597 /* Set candidate trimming */
598 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep1 << OPAMP_INPUT_NONINVERTING);
599 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep2 << OPAMP_INPUT_NONINVERTING);
600 MODIFY_REG(hopamp3->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep3 << OPAMP_INPUT_NONINVERTING);
601 MODIFY_REG(hopamp4->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep4 << OPAMP_INPUT_NONINVERTING);
602
603 /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
604 /* Offset trim time: during calibration, minimum time needed between */
605 /* two steps to have 1 mV accuracy */
606 HAL_Delay(2U);
607
608 if ((hopamp1->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
609 {
610 /* Trimming value is actually one value more */
611 trimmingvaluep1++;
612 /* Set right trimming */
613 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep1 << OPAMP_INPUT_NONINVERTING);
614 }
615
616 if ((hopamp2->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
617 {
618 /* Trimming value is actually one value more */
619 trimmingvaluep2++;
620 /* Set right trimming */
621 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep2 << OPAMP_INPUT_NONINVERTING);
622 }
623
624 if ((hopamp3->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
625 {
626 /* Trimming value is actually one value more */
627 trimmingvaluep3++;
628 /* Set right trimming */
629 MODIFY_REG(hopamp3->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep3 << OPAMP_INPUT_NONINVERTING);
630 }
631
632 if ((hopamp4->Instance->CSR & OPAMP_CSR_OUTCAL) != RESET)
633 {
634 /* Trimming value is actually one value more */
635 trimmingvaluep4++;
636 /* Set right trimming */
637 MODIFY_REG(hopamp4->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep4 << OPAMP_INPUT_NONINVERTING);
638 }
639
640 /* Disable calibration */
641 CLEAR_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALON);
642 CLEAR_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALON);
643 CLEAR_BIT(hopamp3->Instance->CSR, OPAMP_CSR_CALON);
644 CLEAR_BIT(hopamp4->Instance->CSR, OPAMP_CSR_CALON);
645
646 /* Disable the OPAMPs */
647 CLEAR_BIT(hopamp1->Instance->CSR, OPAMP_CSR_OPAMPxEN);
648 CLEAR_BIT(hopamp2->Instance->CSR, OPAMP_CSR_OPAMPxEN);
649 CLEAR_BIT(hopamp3->Instance->CSR, OPAMP_CSR_OPAMPxEN);
650 CLEAR_BIT(hopamp4->Instance->CSR, OPAMP_CSR_OPAMPxEN);
651
652 /* Set normal operating mode back */
653 CLEAR_BIT(hopamp1->Instance->CSR, OPAMP_CSR_FORCEVP);
654 CLEAR_BIT(hopamp2->Instance->CSR, OPAMP_CSR_FORCEVP);
655 CLEAR_BIT(hopamp3->Instance->CSR, OPAMP_CSR_FORCEVP);
656 CLEAR_BIT(hopamp4->Instance->CSR, OPAMP_CSR_FORCEVP);
657
658 /* Self calibration is successful */
659 /* Store calibration(user trimming) results in init structure. */
660 /* Select user trimming mode */
661
662 /* Write calibration result N */
663 hopamp1->Init.TrimmingValueN = trimmingvaluen1;
664 hopamp2->Init.TrimmingValueN = trimmingvaluen2;
665 hopamp3->Init.TrimmingValueN = trimmingvaluen3;
666 hopamp4->Init.TrimmingValueN = trimmingvaluen4;
667
668 /* Write calibration result P */
669 hopamp1->Init.TrimmingValueP = trimmingvaluep1;
670 hopamp2->Init.TrimmingValueP = trimmingvaluep2;
671 hopamp3->Init.TrimmingValueP = trimmingvaluep3;
672 hopamp4->Init.TrimmingValueP = trimmingvaluep4;
673
674 /* Select user trimming mode */
675 /* And updated with calibrated settings */
676 hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER;
677 hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER;
678 hopamp3->Init.UserTrimming = OPAMP_TRIMMING_USER;
679 hopamp4->Init.UserTrimming = OPAMP_TRIMMING_USER;
680
681 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen1 << OPAMP_INPUT_INVERTING);
682 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen2 << OPAMP_INPUT_INVERTING);
683 MODIFY_REG(hopamp3->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen3 << OPAMP_INPUT_INVERTING);
684 MODIFY_REG(hopamp4->Instance->CSR, OPAMP_CSR_TRIMOFFSETN, trimmingvaluen4 << OPAMP_INPUT_INVERTING);
685
686 MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep1 << OPAMP_INPUT_NONINVERTING);
687 MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep2 << OPAMP_INPUT_NONINVERTING);
688 MODIFY_REG(hopamp3->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep3 << OPAMP_INPUT_NONINVERTING);
689 MODIFY_REG(hopamp4->Instance->CSR, OPAMP_CSR_TRIMOFFSETP, trimmingvaluep4 << OPAMP_INPUT_NONINVERTING);
690 }
691 return status;
692 }
693 #endif /* STM32F303xE || STM32F398xx || */
694 /* STM32F303xC || STM32F358xx */
695
696 /**
697 * @}
698 */
699
700 /**
701 * @}
702 */
703
704 /**
705 * @}
706 */
707
708 #endif /* OPAMP1 || OPAMP2 || OPAMP3 || OPAMP4 */
709
710 #endif /* HAL_OPAMP_MODULE_ENABLED */
711
712 /**
713 * @}
714 */
715
716