keyboard/qmk/lib/chibios-contrib/os/hal/ports/STM32/LLD/OPAMPv1/hal_opamp_lld.c

616 lines
18 KiB
C

/*
ChibiOS - Copyright (C) 2006..2019 Giovanni Di Sirio
Copyright (C) 2019 Fabien Poussin (fabien.poussin (at) google's mail)
Copyright (C) 2019 Alexandre Bustico
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file STM32/hal_opamp_lld.c
* @brief STM32 Operational Amplifier subsystem low level driver header.
*
* @addtogroup OPAMP
* @{
*/
#include "hal.h"
#if HAL_USE_OPAMP || defined(__DOXYGEN__)
#include "hal_opamp.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief OPAMPD1 driver identifier.
* @note The driver OPAMPD1 allocates the comparator OPAMP1 when enabled.
*/
#if STM32_OPAMP_USE_OPAMP1 || defined(__DOXYGEN__)
OPAMPDriver OPAMPD1;
#endif
/**
* @brief OPAMPD2 driver identifier.
* @note The driver OPAMPD2 allocates the comparator OPAMP2 when enabled.
*/
#if STM32_OPAMP_USE_OPAMP2 || defined(__DOXYGEN__)
OPAMPDriver OPAMPD2;
#endif
/**
* @brief OPAMPD3 driver identifier.
* @note The driver OPAMPD3 allocates the comparator OPAMP3 when enabled.
*/
#if STM32_OPAMP_USE_OPAMP3 || defined(__DOXYGEN__)
OPAMPDriver OPAMPD3;
#endif
/**
* @brief OPAMPD4 driver identifier.
* @note The driver OPAMPD4 allocates the comparator OPAMP4 when enabled.
*/
#if STM32_OPAMP_USE_OPAMP4 || defined(__DOXYGEN__)
OPAMPDriver OPAMPD4;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level OPAMP driver initialization.
*
* @notapi
*/
void opamp_lld_init(void) {
#if STM32_OPAMP_USE_OPAMP1
/* Driver initialization.*/
opampObjectInit(&OPAMPD1);
OPAMPD1.opamp = OPAMP;
OPAMPD1.opamp->CSR = 0;
#endif
#if STM32_OPAMP_USE_OPAMP2
/* Driver initialization.*/
opampObjectInit(&OPAMPD2);
OPAMPD2.opamp = OPAMP2;
OPAMPD2.opamp->CSR = 0;
#endif
#if STM32_OPAMP_USE_OPAMP3
/* Driver initialization.*/
opampObjectInit(&OPAMPD3);
OPAMPD3.opamp = OPAMP3;
OPAMPD3.opamp->CSR = 0;
#endif
#if STM32_OPAMP_USE_OPAMP4
/* Driver initialization.*/
opampObjectInit(&OPAMPD4);
OPAMPD4.opamp = OPAMP4;
OPAMPD4.opamp->CSR = 0;
#endif
}
/**
* @brief Configures and activates the OPAMP peripheral.
*
* @param[in] opampp pointer to the @p OPAMPDriver object
*
* @notapi
*/
void opamp_lld_start(OPAMPDriver *opampp) {
// Apply CSR Execpt the enable bit.
opampp->opamp->CSR = opampp->config->csr & ~OPAMP_CSR_OPAMPxEN;
}
/**
* @brief Deactivates the comp peripheral.
*
* @param[in] opampp pointer to the @p OPAMPDriver object
*
* @notapi
*/
void opamp_lld_stop(OPAMPDriver *opampp) {
if (opampp->state == OPAMP_ACTIVE) {
opampp->opamp->CSR = 0;
}
}
/**
* @brief Enables the output.
*
* @param[in] opampp pointer to the @p OPAMPDriver object
*
* @notapi
*/
void opamp_lld_enable(OPAMPDriver *opampp) {
opampp->opamp->CSR |= OPAMP_CSR_OPAMPxEN; /* Enable */
}
/**
* @brief Disables the output.
*
* @param[in] opampp pointer to the @p OPAMPDriver object
*
* @notapi
*/
void opamp_lld_disable(OPAMPDriver *opampp) {
opampp->opamp->CSR &= ~OPAMP_CSR_OPAMPxEN; /* Disable */
}
#if STM32_OPAMP_USER_TRIM_ENABLED
void opamp_lld_calibrate_once(void)
{
#if STM32_OPAMP_USE_OPAMP1
uint32_t trimmingvaluen1 = 16U;
uint32_t trimmingvaluep1 = 16U;
OPAMPD1.state = OPAMP_CALIBRATING;
#define CSRm OPAMPD1.opamp->CSR
/* Set Calibration mode */
/* Non-inverting input connected to calibration reference voltage. */
CSRm |= OPAMP_CSR_FORCEVP;
/* user trimming values are used for offset calibration */
CSRm |= OPAMP_CSR_USERTRIM;
/* Enable calibration */
CSRm |= OPAMP_CSR_CALON;
/* 1st calibration - N Select 90U% VREF */
MODIFY_REG(CSRm, OPAMP_CSR_CALSEL, OPAMPx_CSR_CALSEL_90P);
/* Enable the opamps */
CSRm |= OPAMP_CSR_OPAMPxEN;
#undef CSRm
#endif
#if STM32_OPAMP_USE_OPAMP2
uint32_t trimmingvaluen2 = 16U;
uint32_t trimmingvaluep2 = 16U;
OPAMPD2.state = OPAMP_CALIBRATING;
#define CSRm OPAMPD2.opamp->CSR
CSRm |= OPAMP_CSR_FORCEVP;
CSRm |= OPAMP_CSR_USERTRIM;
CSRm |= OPAMP_CSR_CALON;
MODIFY_REG(CSRm, OPAMP_CSR_CALSEL, OPAMPx_CSR_CALSEL_90P);
CSRm |= OPAMP_CSR_OPAMPxEN;
#undef CSRm
#endif
#if STM32_OPAMP_USE_OPAMP3
uint32_t trimmingvaluen3 = 16U;
uint32_t trimmingvaluep3 = 16U;
OPAMPD3.state = OPAMP_CALIBRATING;
#define CSRm OPAMPD3.opamp->CSR
CSRm |= OPAMP_CSR_FORCEVP;
CSRm |= OPAMP_CSR_USERTRIM;
CSRm |= OPAMP_CSR_CALON;
MODIFY_REG(CSRm, OPAMP_CSR_CALSEL, OPAMPx_CSR_CALSEL_90P);
CSRm |= OPAMP_CSR_OPAMPxEN;
#undef CSRm
#endif
#if STM32_OPAMP_USE_OPAMP4
uint32_t trimmingvaluen4 = 16U;
uint32_t trimmingvaluep4 = 16U;
OPAMPD4.state = OPAMP_CALIBRATING;
#define CSRm OPAMPD4.opamp->CSR
CSRm |= OPAMP_CSR_FORCEVP;
CSRm |= OPAMP_CSR_USERTRIM;
CSRm |= OPAMP_CSR_CALON;
MODIFY_REG(CSRm, OPAMP_CSR_CALSEL, OPAMPx_CSR_CALSEL_90P);
CSRm |= OPAMP_CSR_OPAMPxEN;
#undef CSRm
#endif
chSysPolledDelayX(MS2RTC(STM32_SYSCLK, 20));
uint32_t delta = 8U;
while (delta != 0U) {
#if STM32_OPAMP_USE_OPAMP1
MODIFY_REG(OPAMPD1.opamp->CSR, OPAMP_CSR_TRIMOFFSETN,
trimmingvaluen1<<OPAMP_CSR_TRIMOFFSETN_Pos);
#endif
#if STM32_OPAMP_USE_OPAMP2
MODIFY_REG(OPAMPD2.opamp->CSR, OPAMP_CSR_TRIMOFFSETN,
trimmingvaluen2<<OPAMP_CSR_TRIMOFFSETN_Pos);
#endif
#if STM32_OPAMP_USE_OPAMP3
MODIFY_REG(OPAMPD3.opamp->CSR, OPAMP_CSR_TRIMOFFSETN,
trimmingvaluen3<<OPAMP_CSR_TRIMOFFSETN_Pos);
#endif
#if STM32_OPAMP_USE_OPAMP4
MODIFY_REG(OPAMPD4.opamp->CSR, OPAMP_CSR_TRIMOFFSETN,
trimmingvaluen4<<OPAMP_CSR_TRIMOFFSETN_Pos);
#endif
/* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
/* Offset trim time: during calibration, minimum time needed between */
/* two steps to have 1 mV accuracy */
chSysPolledDelayX(MS2RTC(STM32_SYSCLK, 2));
#if STM32_OPAMP_USE_OPAMP1
if (OPAMPD1.opamp->CSR & OPAMP_CSR_OUTCAL) {
/* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
trimmingvaluen1 += delta;
} else {
/* OPAMP_CSR_OUTCAL is LOW try lower trimming */
trimmingvaluen1 -= delta;
}
#endif
#if STM32_OPAMP_USE_OPAMP2
if (OPAMPD2.opamp->CSR & OPAMP_CSR_OUTCAL) {
trimmingvaluen2 += delta;
} else {
trimmingvaluen2 -= delta;
}
#endif
#if STM32_OPAMP_USE_OPAMP3
if (OPAMPD3.opamp->CSR & OPAMP_CSR_OUTCAL) {
trimmingvaluen3 += delta;
} else {
trimmingvaluen3 -= delta;
}
#endif
#if STM32_OPAMP_USE_OPAMP4
if (OPAMPD4.opamp->CSR & OPAMP_CSR_OUTCAL) {
trimmingvaluen4 += delta;
} else {
trimmingvaluen4 -= delta;
}
#endif
delta >>= 1U;
}
/* Still need to check if righ calibration is current value or un step below */
/* Indeed the first value that causes the OUTCAL bit to change from 1 to 0U */
#if STM32_OPAMP_USE_OPAMP1
MODIFY_REG(OPAMPD1.opamp->CSR, OPAMP_CSR_TRIMOFFSETN,
trimmingvaluen1<<OPAMP_CSR_TRIMOFFSETN_Pos);
#endif
#if STM32_OPAMP_USE_OPAMP2
MODIFY_REG(OPAMPD2.opamp->CSR, OPAMP_CSR_TRIMOFFSETN,
trimmingvaluen2<<OPAMP_CSR_TRIMOFFSETN_Pos);
#endif
#if STM32_OPAMP_USE_OPAMP3
MODIFY_REG(OPAMPD3.opamp->CSR, OPAMP_CSR_TRIMOFFSETN,
trimmingvaluen3<<OPAMP_CSR_TRIMOFFSETN_Pos);
#endif
#if STM32_OPAMP_USE_OPAMP4
MODIFY_REG(OPAMPD4.opamp->CSR, OPAMP_CSR_TRIMOFFSETN,
trimmingvaluen4<<OPAMP_CSR_TRIMOFFSETN_Pos);
#endif
/* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
/* Offset trim time: during calibration, minimum time needed between */
/* two steps to have 1 mV accuracy */
chSysPolledDelayX(MS2RTC(STM32_SYSCLK, 2));
#if STM32_OPAMP_USE_OPAMP1
if (OPAMPD1.opamp->CSR & OPAMP_CSR_OUTCAL) {
/* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
trimmingvaluen1 += (trimmingvaluen1 != 31);
MODIFY_REG(OPAMPD1.opamp->CSR, OPAMP_CSR_TRIMOFFSETN,
trimmingvaluen1<<OPAMP_CSR_TRIMOFFSETN_Pos);
}
#endif
#if STM32_OPAMP_USE_OPAMP2
if (OPAMPD2.opamp->CSR & OPAMP_CSR_OUTCAL) {
trimmingvaluen2 += (trimmingvaluen2 != 31);
MODIFY_REG(OPAMPD2.opamp->CSR, OPAMP_CSR_TRIMOFFSETN,
trimmingvaluen2<<OPAMP_CSR_TRIMOFFSETN_Pos);
}
#endif
#if STM32_OPAMP_USE_OPAMP3
if (OPAMPD3.opamp->CSR & OPAMP_CSR_OUTCAL) {
trimmingvaluen3 += (trimmingvaluen3 != 31);
MODIFY_REG(OPAMPD3.opamp->CSR, OPAMP_CSR_TRIMOFFSETN,
trimmingvaluen3<<OPAMP_CSR_TRIMOFFSETN_Pos);
}
#endif
#if STM32_OPAMP_USE_OPAMP4
if (OPAMPD4.opamp->CSR & OPAMP_CSR_OUTCAL) {
trimmingvaluen4 += (trimmingvaluen4 != 31);
MODIFY_REG(OPAMPD4.opamp->CSR, OPAMP_CSR_TRIMOFFSETN,
trimmingvaluen4<<OPAMP_CSR_TRIMOFFSETN_Pos);
}
#endif
/* 2nd calibration - P */
/* Select 10U% VREF */
#if STM32_OPAMP_USE_OPAMP1
MODIFY_REG(OPAMPD1.opamp->CSR, OPAMP_CSR_CALSEL, OPAMPx_CSR_CALSEL_10P);
#endif
#if STM32_OPAMP_USE_OPAMP2
MODIFY_REG(OPAMPD2.opamp->CSR, OPAMP_CSR_CALSEL, OPAMPx_CSR_CALSEL_10P);
#endif
#if STM32_OPAMP_USE_OPAMP3
MODIFY_REG(OPAMPD3.opamp->CSR, OPAMP_CSR_CALSEL, OPAMPx_CSR_CALSEL_10P);
#endif
#if STM32_OPAMP_USE_OPAMP4
MODIFY_REG(OPAMPD4.opamp->CSR, OPAMP_CSR_CALSEL, OPAMPx_CSR_CALSEL_10P);
#endif
delta = 8U;
while (delta != 0U) {
#if STM32_OPAMP_USE_OPAMP1
MODIFY_REG(OPAMPD1.opamp->CSR, OPAMP_CSR_TRIMOFFSETP,
trimmingvaluep1<<OPAMP_CSR_TRIMOFFSETP_Pos);
#endif
#if STM32_OPAMP_USE_OPAMP2
MODIFY_REG(OPAMPD2.opamp->CSR, OPAMP_CSR_TRIMOFFSETP,
trimmingvaluep2<<OPAMP_CSR_TRIMOFFSETP_Pos);
#endif
#if STM32_OPAMP_USE_OPAMP3
MODIFY_REG(OPAMPD3.opamp->CSR, OPAMP_CSR_TRIMOFFSETP,
trimmingvaluep3<<OPAMP_CSR_TRIMOFFSETP_Pos);
#endif
#if STM32_OPAMP_USE_OPAMP4
MODIFY_REG(OPAMPD4.opamp->CSR, OPAMP_CSR_TRIMOFFSETP,
trimmingvaluep4<<OPAMP_CSR_TRIMOFFSETP_Pos);
#endif
/* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
/* Offset trim time: during calibration, minimum time needed between */
/* two steps to have 1 mV accuracy */
chSysPolledDelayX(MS2RTC(STM32_SYSCLK, 2));
#if STM32_OPAMP_USE_OPAMP1
if (OPAMPD1.opamp->CSR & OPAMP_CSR_OUTCAL) {
/* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
trimmingvaluep1 += delta;
} else {
/* OPAMP_CSR_OUTCAL is LOW try lower trimming */
trimmingvaluep1 -= delta;
}
#endif
#if STM32_OPAMP_USE_OPAMP2
if (OPAMPD2.opamp->CSR & OPAMP_CSR_OUTCAL) {
trimmingvaluep2 += delta;
} else {
trimmingvaluep2 -= delta;
}
#endif
#if STM32_OPAMP_USE_OPAMP3
if (OPAMPD3.opamp->CSR & OPAMP_CSR_OUTCAL) {
trimmingvaluep3 += delta;
} else {
trimmingvaluep3 -= delta;
}
#endif
#if STM32_OPAMP_USE_OPAMP4
if (OPAMPD4.opamp->CSR & OPAMP_CSR_OUTCAL) {
trimmingvaluep4 += delta;
} else {
trimmingvaluep4 -= delta;
}
#endif
delta >>= 1U;
}
/* Still need to check if righ calibration is current value or un step below */
/* Indeed the first value that causes the OUTCAL bit to change from 1 to 0U */
#if STM32_OPAMP_USE_OPAMP1
MODIFY_REG(OPAMPD1.opamp->CSR, OPAMP_CSR_TRIMOFFSETP,
trimmingvaluep1<<OPAMP_CSR_TRIMOFFSETP_Pos);
#endif
#if STM32_OPAMP_USE_OPAMP2
MODIFY_REG(OPAMPD2.opamp->CSR, OPAMP_CSR_TRIMOFFSETP,
trimmingvaluep2<<OPAMP_CSR_TRIMOFFSETP_Pos);
#endif
#if STM32_OPAMP_USE_OPAMP3
MODIFY_REG(OPAMPD3.opamp->CSR, OPAMP_CSR_TRIMOFFSETP,
trimmingvaluep3<<OPAMP_CSR_TRIMOFFSETP_Pos);
#endif
#if STM32_OPAMP_USE_OPAMP4
MODIFY_REG(OPAMPD4.opamp->CSR, OPAMP_CSR_TRIMOFFSETP,
trimmingvaluep4<<OPAMP_CSR_TRIMOFFSETP_Pos);
#endif
/* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
/* Offset trim time: during calibration, minimum time needed between */
/* two steps to have 1 mV accuracy */
chSysPolledDelayX(MS2RTC(STM32_SYSCLK, 2));
#if STM32_OPAMP_USE_OPAMP1
if (OPAMPD1.opamp->CSR & OPAMP_CSR_OUTCAL) {
/* OPAMP_CSR_OUTCAL is HIGH try higher trimming */
trimmingvaluep1 += (trimmingvaluep1 != 31);
MODIFY_REG(OPAMPD1.opamp->CSR, OPAMP_CSR_TRIMOFFSETP,
trimmingvaluep1<<OPAMP_CSR_TRIMOFFSETP_Pos);
}
#endif
#if STM32_OPAMP_USE_OPAMP2
if (OPAMPD2.opamp->CSR & OPAMP_CSR_OUTCAL) {
trimmingvaluep2 += (trimmingvaluep2 != 31);
MODIFY_REG(OPAMPD2.opamp->CSR, OPAMP_CSR_TRIMOFFSETP,
trimmingvaluep2<<OPAMP_CSR_TRIMOFFSETP_Pos);
}
#endif
#if STM32_OPAMP_USE_OPAMP3
if (OPAMPD3.opamp->CSR & OPAMP_CSR_OUTCAL) {
trimmingvaluep3 += (trimmingvaluep3 != 31);
MODIFY_REG(OPAMPD3.opamp->CSR, OPAMP_CSR_TRIMOFFSETP,
trimmingvaluep3<<OPAMP_CSR_TRIMOFFSETP_Pos);
}
#endif
#if STM32_OPAMP_USE_OPAMP4
if (OPAMPD4.opamp->CSR & OPAMP_CSR_OUTCAL) {
trimmingvaluep4 += (trimmingvaluep4 != 31);
MODIFY_REG(OPAMPD4.opamp->CSR, OPAMP_CSR_TRIMOFFSETP,
trimmingvaluep4<<OPAMP_CSR_TRIMOFFSETP_Pos);
}
#endif
#if STM32_OPAMP_USE_OPAMP1
#define CSRm OPAMPD1.opamp->CSR
/* Disable calibration */
CSRm &= ~OPAMP_CSR_CALON;
/* Disable the OPAMPs */
CSRm &= ~OPAMP_CSR_OPAMPxEN;
/* Set normal operating mode back */
CSRm &= ~OPAMP_CSR_FORCEVP;
/* Write calibration result N */
OPAMPD1.trim_n = trimmingvaluen1;
/* Write calibration result P */
OPAMPD1.trim_p = trimmingvaluep1;
MODIFY_REG(CSRm, OPAMP_CSR_TRIMOFFSETN,
trimmingvaluen1<<OPAMP_CSR_TRIMOFFSETN_Pos);
MODIFY_REG(CSRm, OPAMP_CSR_TRIMOFFSETP,
trimmingvaluep1<<OPAMP_CSR_TRIMOFFSETP_Pos);
OPAMPD1.state = OPAMP_STOP;
#undef CSRm
#endif
#if STM32_OPAMP_USE_OPAMP2
#define CSRm OPAMPD2.opamp->CSR
/* Disable calibration */
CSRm &= ~OPAMP_CSR_CALON;
/* Disable the OPAMPs */
CSRm &= ~OPAMP_CSR_OPAMPxEN;
/* Set normal operating mode back */
CSRm &= ~OPAMP_CSR_FORCEVP;
/* Write calibration result N */
OPAMPD2.trim_n = trimmingvaluen2;
/* Write calibration result P */
OPAMPD2.trim_p = trimmingvaluep2;
MODIFY_REG(CSRm, OPAMP_CSR_TRIMOFFSETN,
trimmingvaluen2<<OPAMP_CSR_TRIMOFFSETN_Pos);
MODIFY_REG(CSRm, OPAMP_CSR_TRIMOFFSETP,
trimmingvaluep2<<OPAMP_CSR_TRIMOFFSETP_Pos);
OPAMPD2.state = OPAMP_STOP;
#undef CSRm
#endif
#if STM32_OPAMP_USE_OPAMP3
#define CSRm OPAMPD3.opamp->CSR
/* Disable calibration */
CSRm &= ~OPAMP_CSR_CALON;
/* Disable the OPAMPs */
CSRm &= ~OPAMP_CSR_OPAMPxEN;
/* Set normal operating mode back */
CSRm &= ~OPAMP_CSR_FORCEVP;
/* Write calibration result N */
OPAMPD3.trim_n = trimmingvaluen3;
/* Write calibration result P */
OPAMPD3.trim_p = trimmingvaluep3;
MODIFY_REG(CSRm, OPAMP_CSR_TRIMOFFSETN,
trimmingvaluen3<<OPAMP_CSR_TRIMOFFSETN_Pos);
MODIFY_REG(CSRm, OPAMP_CSR_TRIMOFFSETP,
trimmingvaluep3<<OPAMP_CSR_TRIMOFFSETP_Pos);
OPAMPD3.state = OPAMP_STOP;
#undef CSRm
#endif
#if STM32_OPAMP_USE_OPAMP4
#define CSRm OPAMPD4.opamp->CSR
/* Disable calibration */
CSRm &= ~OPAMP_CSR_CALON;
/* Disable the OPAMPs */
CSRm &= ~OPAMP_CSR_OPAMPxEN;
/* Set normal operating mode back */
CSRm &= ~OPAMP_CSR_FORCEVP;
/* Write calibration result N */
OPAMPD4.trim_n = trimmingvaluen4;
/* Write calibration result P */
OPAMPD4.trim_p = trimmingvaluep4;
MODIFY_REG(CSRm, OPAMP_CSR_TRIMOFFSETN,
trimmingvaluen4<<OPAMP_CSR_TRIMOFFSETN_Pos);
MODIFY_REG(CSRm, OPAMP_CSR_TRIMOFFSETP,
trimmingvaluep4<<OPAMP_CSR_TRIMOFFSETP_Pos);
OPAMPD4.state = OPAMP_STOP;
#undef CSRm
#endif
}
void opamp_lld_calibrate(void)
{
uint8_t trim_n[4] = {255};
uint8_t trim_p[4] = {255};
bool done;
do {
done = true;
opamp_lld_calibrate_once();
#if STM32_OPAMP_USE_OPAMP1
done = done && (OPAMPD1.trim_n == trim_n[0]) && (OPAMPD1.trim_p == trim_p[0]);
trim_n[0] = OPAMPD1.trim_n;
trim_p[0] = OPAMPD1.trim_p;
#endif
#if STM32_OPAMP_USE_OPAMP2
done = done && (OPAMPD2.trim_n == trim_n[1]) && (OPAMPD2.trim_p == trim_p[1]);
trim_n[1] = OPAMPD2.trim_n;
trim_p[1] = OPAMPD2.trim_p;
#endif
#if STM32_OPAMP_USE_OPAMP3
done = done && (OPAMPD3.trim_n == trim_n[2]) && (OPAMPD3.trim_p == trim_p[2]);
trim_n[2] = OPAMPD3.trim_n;
trim_p[2] = OPAMPD3.trim_p;
#endif
#if STM32_OPAMP_USE_OPAMP4
done = done && (OPAMPD4.trim_n == trim_n[3]) && (OPAMPD4.trim_p == trim_p[3]);
trim_n[3] = OPAMPD4.trim_n;
trim_p[3] = OPAMPD4.trim_p;
#endif
} while (!done);
}
#endif // STM32_OPAMP_USER_TRIM_ENABLED
#endif /* HAL_USE_OPAMP */
/** @} */