/** * @brief Run the self calibration of the 3 OPAMPs in parallel. * @note Trimming values (PMOS & NMOS) are updated and user trimming is * enabled is calibration is succesful. * @note Calibration is performed in the mode specified in OPAMP init * structure (mode normal or low-power). To perform calibration for * both modes, repeat this function twice after OPAMP init structure * accordingly updated. * @note Calibration runs about 10 ms (5 dichotmy steps, repeated for P * and N transistors: 10 steps with 1 ms for each step). * @param hopamp1 handle * @param hopamp2 handle * @param hopamp3 handle * @retval HAL status */ HAL_StatusTypeDef HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef *hopamp1, OPAMP_HandleTypeDef *hopamp2, OPAMP_HandleTypeDef *hopamp3) { HAL_StatusTypeDef status = HAL_OK; uint32_t* opamp1_trimmingvalue = 0; uint32_t opamp1_trimmingvaluen = 0; uint32_t opamp1_trimmingvaluep = 0; uint32_t* opamp2_trimmingvalue = 0; uint32_t opamp2_trimmingvaluen = 0; uint32_t opamp2_trimmingvaluep = 0; uint32_t* opamp3_trimmingvalue = 0; uint32_t opamp3_trimmingvaluen = 0; uint32_t opamp3_trimmingvaluep = 0; uint32_t trimming_diff_pair = 0; /* Selection of differential transistors pair high or low */ __IO uint32_t* tmp_opamp1_reg_trimming; /* Selection of register of trimming depending on power mode: OTR or LPOTR */ __IO uint32_t* tmp_opamp2_reg_trimming; __IO uint32_t* tmp_opamp3_reg_trimming; uint32_t tmp_opamp1_otr_otuser = 0; /* Selection of bit OPAMP_OTR_OT_USER depending on trimming register pointed: OTR or LPOTR */ uint32_t tmp_opamp2_otr_otuser = 0; uint32_t tmp_opamp3_otr_otuser = 0; uint32_t tmp_Opa1calout_DefaultSate = 0; /* Bit OPAMP_CSR_OPA1CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */ uint32_t tmp_Opa2calout_DefaultSate = 0; /* Bit OPAMP_CSR_OPA2CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */ uint32_t tmp_Opa3calout_DefaultSate = 0; /* Bit OPAMP_CSR_OPA3CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */ uint32_t tmp_OpaxSwitchesContextBackup = 0; uint8_t trimming_diff_pair_iteration_count = 0; /* For calibration loop algorithm: to repeat the calibration loop for both differential transistors pair high and low */ uint8_t delta = 0; /* For calibration loop algorithm: Variable for dichotomy steps value */ uint8_t final_step_check = 0; /* For calibration loop algorithm: Flag for additional check of last trimming step */ /* Check the OPAMP handle allocation */ /* Check if OPAMP locked */ if((hopamp1 == NULL) || (hopamp1->State == HAL_OPAMP_STATE_BUSYLOCKED) || (hopamp2 == NULL) || (hopamp2->State == HAL_OPAMP_STATE_BUSYLOCKED) || (hopamp3 == NULL) || (hopamp3->State == HAL_OPAMP_STATE_BUSYLOCKED) ) { status = HAL_ERROR; } else { /* Check if OPAMP in calibration mode and calibration not yet enable */ if((hopamp1->State == HAL_OPAMP_STATE_READY) && (hopamp2->State == HAL_OPAMP_STATE_READY) && (hopamp3->State == HAL_OPAMP_STATE_READY) ) { /* Check the parameter */ assert_param(IS_OPAMP_ALL_INSTANCE(hopamp1->Instance)); assert_param(IS_OPAMP_ALL_INSTANCE(hopamp2->Instance)); assert_param(IS_OPAMP_ALL_INSTANCE(hopamp3->Instance)); assert_param(IS_OPAMP_POWERMODE(hopamp1->Init.PowerMode)); assert_param(IS_OPAMP_POWERMODE(hopamp2->Init.PowerMode)); assert_param(IS_OPAMP_POWERMODE(hopamp3->Init.PowerMode)); /* Update OPAMP state */ hopamp1->State = HAL_OPAMP_STATE_CALIBBUSY; hopamp2->State = HAL_OPAMP_STATE_CALIBBUSY; hopamp3->State = HAL_OPAMP_STATE_CALIBBUSY; /* Backup of switches configuration to restore it at the end of the */ /* calibration. */ tmp_OpaxSwitchesContextBackup = READ_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES_ALL_OPAMPS); /* Open all switches on non-inverting input, inverting input and output */ /* feedback. */ CLEAR_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES_ALL_OPAMPS); /* Set calibration mode to user programmed trimming values */ SET_BIT(OPAMP->OTR, OPAMP_OTR_OT_USER); /* Select trimming settings depending on power mode */ if (hopamp1->Init.PowerMode == OPAMP_POWERMODE_NORMAL) { tmp_opamp1_otr_otuser = OPAMP_OTR_OT_USER; tmp_opamp1_reg_trimming = &OPAMP->OTR; } else { tmp_opamp1_otr_otuser = 0x00000000; tmp_opamp1_reg_trimming = &OPAMP->LPOTR; } if (hopamp2->Init.PowerMode == OPAMP_POWERMODE_NORMAL) { tmp_opamp2_otr_otuser = OPAMP_OTR_OT_USER; tmp_opamp2_reg_trimming = &OPAMP->OTR; } else { tmp_opamp2_otr_otuser = 0x00000000; tmp_opamp2_reg_trimming = &OPAMP->LPOTR; } if (hopamp3->Init.PowerMode == OPAMP_POWERMODE_NORMAL) { tmp_opamp3_otr_otuser = OPAMP_OTR_OT_USER; tmp_opamp3_reg_trimming = &OPAMP->OTR; } else { tmp_opamp3_otr_otuser = 0x00000000; tmp_opamp3_reg_trimming = &OPAMP->LPOTR; } /* Enable the selected opamp */ CLEAR_BIT (OPAMP->CSR, OPAMP_CSR_OPAXPD_ALL); /* Perform trimming for both differential transistors pair high and low */ for (trimming_diff_pair_iteration_count = 0; trimming_diff_pair_iteration_count <=1; trimming_diff_pair_iteration_count++) { if (trimming_diff_pair_iteration_count == 0) { /* Calibration of transistors differential pair high (NMOS) */ trimming_diff_pair = OPAMP_FACTORYTRIMMING_N; opamp1_trimmingvalue = &opamp1_trimmingvaluen; opamp2_trimmingvalue = &opamp2_trimmingvaluen; opamp3_trimmingvalue = &opamp3_trimmingvaluen; /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value */ /* is 00000b. Used to detect the bit toggling during trimming. */ tmp_Opa1calout_DefaultSate = RESET; tmp_Opa2calout_DefaultSate = RESET; tmp_Opa3calout_DefaultSate = RESET; /* Enable calibration for N differential pair */ MODIFY_REG(OPAMP->CSR, OPAMP_CSR_OPAXCAL_L_ALL, OPAMP_CSR_OPAXCAL_H_ALL); } else /* (trimming_diff_pair_iteration_count == 1) */ { /* Calibration of transistors differential pair low (PMOS) */ trimming_diff_pair = OPAMP_FACTORYTRIMMING_P; opamp1_trimmingvalue = &opamp1_trimmingvaluep; opamp2_trimmingvalue = &opamp2_trimmingvaluep; opamp3_trimmingvalue = &opamp3_trimmingvaluep; /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value */ /* is 00000b. Used to detect the bit toggling during trimming. */ tmp_Opa1calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp1); tmp_Opa2calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp2); tmp_Opa3calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp3); /* Enable calibration for P differential pair */ MODIFY_REG(OPAMP->CSR, OPAMP_CSR_OPAXCAL_H_ALL, OPAMP_CSR_OPAXCAL_L_ALL); } /* Perform calibration parameter search by dichotomy sweep */ /* - Delta initial value 16: for 5 dichotomy steps: 16 for the */ /* initial range, then successive delta sweeps (8, 4, 2, 1). */ /* can extend the search range to +/- 15 units. */ /* - Trimming initial value 15: search range will go from 0 to 30 */ /* (Trimming value 31 is forbidden). */ /* Note: After dichotomy sweep, the trimming result is determined. */ /* However, the final trimming step is deduced from previous */ /* trimming steps tested but is not effectively tested. */ /* An additional test step (using variable "final_step_check") */ /* allow to Test the final trimming step. */ *opamp1_trimmingvalue = 15; *opamp2_trimmingvalue = 15; *opamp3_trimmingvalue = 15; delta = 16; while ((delta != 0) || (final_step_check == 1)) { /* Set candidate trimming */ MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) , OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, *opamp1_trimmingvalue) | tmp_opamp1_otr_otuser); MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) , OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, *opamp2_trimmingvalue) | tmp_opamp2_otr_otuser); MODIFY_REG(*tmp_opamp3_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) , OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, *opamp3_trimmingvalue) | tmp_opamp3_otr_otuser); /* Offset trimming time: during calibration, minimum time needed */ /* between two steps to have 1 mV accuracy. */ HAL_Delay(OPAMP_TRIMMING_DELAY); /* Set flag for additional check of last trimming step equal to */ /* dichotomy step before its division by 2 (equivalent to previous */ /* value of dichotomy step). */ final_step_check = delta; /* Divide range by 2 to continue dichotomy sweep */ delta >>= 1; /* Set trimming values for next iteration in function of trimming */ /* result toggle (versus initial state). */ /* Trimming values update with dichotomy delta of previous */ /* iteration. */ /* Note: on the last trimming loop, delta is equal to 0 and */ /* therefore has no effect. */ if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp1)) != tmp_Opa1calout_DefaultSate) { /* If calibration output is has toggled, try lower trimming */ *opamp1_trimmingvalue -= delta; } else { /* If calibration output is has not toggled, try higher trimming */ *opamp1_trimmingvalue += delta; } if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp2)) != tmp_Opa2calout_DefaultSate) { /* If calibration output is has toggled, try lower trimming */ *opamp2_trimmingvalue -= delta; } else { /* If calibration output is has not toggled, try higher trimming */ *opamp2_trimmingvalue += delta; } if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp3)) != tmp_Opa3calout_DefaultSate) { /* If calibration output is has toggled, try lower trimming */ *opamp3_trimmingvalue -= delta; } else { /* If calibration output is has not toggled, try higher trimming */ *opamp3_trimmingvalue += delta; } } /* Check trimming result of the selected step and perform final fine */ /* trimming. */ /* - If calibration output is has toggled: the current step is */ /* already optimized. */ /* - If calibration output is has not toggled: the current step can */ /* be optimized by incrementing it of one step. */ if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp1)) == tmp_Opa1calout_DefaultSate) { *opamp1_trimmingvalue += 1; /* Set final fine trimming */ MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) , OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, *opamp1_trimmingvalue) | tmp_opamp1_otr_otuser); } if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp2)) == tmp_Opa2calout_DefaultSate) { *opamp2_trimmingvalue += 1; /* Set final fine trimming */ MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) , OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, *opamp2_trimmingvalue) | tmp_opamp2_otr_otuser); } if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp3)) == tmp_Opa3calout_DefaultSate) { *opamp3_trimmingvalue += 1; /* Set final fine trimming */ MODIFY_REG(*tmp_opamp3_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) , OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, *opamp3_trimmingvalue) | tmp_opamp3_otr_otuser); } } /* Disable calibration for P and N differential pairs */ /* Disable the selected opamp */ CLEAR_BIT (OPAMP->CSR, (OPAMP_CSR_OPAXCAL_H_ALL | OPAMP_CSR_OPAXCAL_L_ALL | OPAMP_CSR_OPAXPD_ALL )); /* Backup of switches configuration to restore it at the end of the */ /* calibration. */ SET_BIT(OPAMP->CSR, tmp_OpaxSwitchesContextBackup); /* Self calibration is successful */ /* Store calibration (user trimming) results in init structure. */ /* Set user trimming mode */ hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER; hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER; hopamp3->Init.UserTrimming = OPAMP_TRIMMING_USER; /* Affect calibration parameters depending on mode normal/low power */ if (hopamp1->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER) { /* Write calibration result N */ hopamp1->Init.TrimmingValueN = opamp1_trimmingvaluen; /* Write calibration result P */ hopamp1->Init.TrimmingValueP = opamp1_trimmingvaluep; } else { /* Write calibration result N */ hopamp1->Init.TrimmingValueNLowPower = opamp1_trimmingvaluen; /* Write calibration result P */ hopamp1->Init.TrimmingValuePLowPower = opamp1_trimmingvaluep; } if (hopamp2->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER) { /* Write calibration result N */ hopamp2->Init.TrimmingValueN = opamp2_trimmingvaluen; /* Write calibration result P */ hopamp2->Init.TrimmingValueP = opamp2_trimmingvaluep; } else { /* Write calibration result N */ hopamp2->Init.TrimmingValueNLowPower = opamp2_trimmingvaluen; /* Write calibration result P */ hopamp2->Init.TrimmingValuePLowPower = opamp2_trimmingvaluep; } if (hopamp3->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER) { /* Write calibration result N */ hopamp3->Init.TrimmingValueN = opamp3_trimmingvaluen; /* Write calibration result P */ hopamp3->Init.TrimmingValueP = opamp3_trimmingvaluep; } else { /* Write calibration result N */ hopamp3->Init.TrimmingValueNLowPower = opamp3_trimmingvaluen; /* Write calibration result P */ hopamp3->Init.TrimmingValuePLowPower = opamp3_trimmingvaluep; } /* Update OPAMP state */ hopamp1->State = HAL_OPAMP_STATE_READY; hopamp2->State = HAL_OPAMP_STATE_READY; hopamp3->State = HAL_OPAMP_STATE_READY; } else {
/** * @brief Initializes the OPAMP according to the specified * parameters in the OPAMP_InitTypeDef and create the associated handle. * @note If the selected opamp is locked, initialization can't be performed. * To unlock the configuration, perform a system reset. * @param hopamp: OPAMP handle * @retval HAL status */ HAL_StatusTypeDef HAL_OPAMP_Init(OPAMP_HandleTypeDef* hopamp) { HAL_StatusTypeDef status = HAL_OK; uint32_t tmp_csr = 0; /* Temporary variable to update register CSR, except bits ANAWSSELx, S7SEL2, OPA_RANGE, OPAxCALOUT */ /* Check the OPAMP handle allocation and lock status */ /* Init not allowed if calibration is ongoing */ if((hopamp == NULL) || (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED) || (hopamp->State == HAL_OPAMP_STATE_CALIBBUSY) ) { status = HAL_ERROR; } else { /* Check the parameter */ assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance)); /* Set OPAMP parameters */ assert_param(IS_OPAMP_POWER_SUPPLY_RANGE(hopamp->Init.PowerSupplyRange)); assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode)); assert_param(IS_OPAMP_FUNCTIONAL_NORMALMODE(hopamp->Init.Mode)); assert_param(IS_OPAMP_NONINVERTING_INPUT_CHECK_INSTANCE(hopamp, hopamp->Init.NonInvertingInput)); assert_param(IS_OPAMP_TRIMMING(hopamp->Init.UserTrimming)); if (hopamp->Init.Mode != OPAMP_FOLLOWER_MODE) { assert_param(IS_OPAMP_INVERTING_INPUT(hopamp->Init.InvertingInput)); } if (hopamp->Init.UserTrimming == OPAMP_TRIMMING_USER) { if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMAL) { assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueP)); assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueN)); } else { assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValuePLowPower)); assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueNLowPower)); } } if(hopamp->State == HAL_OPAMP_STATE_RESET) { /* Allocate lock resource and initialize it */ hopamp->Lock = HAL_UNLOCKED; } /* Call MSP init function */ HAL_OPAMP_MspInit(hopamp); /* Set OPAMP parameters */ /* - Set internal switches in function of: */ /* - OPAMP selected mode: standalone or follower. */ /* - Non-inverting input connection */ /* - Inverting input connection */ /* - Set power supply range */ /* - Set power mode and associated calibration parameters */ /* Get OPAMP CSR register into temporary variable */ /* Note: OPAMP register CSR is written directly, independently of OPAMP */ /* instance, because all OPAMP settings are dispatched in the same */ /* register. */ /* Settings of bits for each OPAMP instances are managed case by */ /* case using macro (OPAMP_CSR_S3SELX(), OPAMP_CSR_ANAWSELX(), ...) */ tmp_csr = OPAMP->CSR; /* Open all switches on non-inverting input, inverting input and output */ /* feedback. */ CLEAR_BIT(tmp_csr, OPAMP_CSR_ALL_SWITCHES(hopamp)); /* Set internal switches in function of OPAMP mode selected: standalone */ /* or follower. */ /* If follower mode is selected, feedback switch S3 is closed and */ /* inverting inputs switches are let opened. */ /* If standalone mode is selected, feedback switch S3 is let opened and */ /* the selected inverting inputs switch is closed. */ if (hopamp->Init.Mode == OPAMP_FOLLOWER_MODE) { /* Follower mode: Close switches S3 and SanB */ SET_BIT(tmp_csr, OPAMP_CSR_S3SELX(hopamp)); } else { /* Set internal switches in function of inverting input selected: */ /* Close switch to connect OPAMP inverting input to the selected */ /* input: dedicated IO pin or alternative IO pin available on some */ /* device packages. */ if (hopamp->Init.InvertingInput == OPAMP_INVERTINGINPUT_IO0) { /* Close switch to connect OPAMP non-inverting input to */ /* dedicated IO pin low-leakage. */ SET_BIT(tmp_csr, OPAMP_CSR_S4SELX(hopamp)); } else { /* Close switch to connect OPAMP inverting input to alternative */ /* IO pin available on some device packages. */ SET_BIT(tmp_csr, OPAMP_CSR_ANAWSELX(hopamp)); } } /* Set internal switches in function of non-inverting input selected: */ /* Close switch to connect OPAMP non-inverting input to the selected */ /* input: dedicated IO pin or DAC channel. */ if (hopamp->Init.NonInvertingInput == OPAMP_NONINVERTINGINPUT_IO0) { /* Close switch to connect OPAMP non-inverting input to */ /* dedicated IO pin low-leakage. */ SET_BIT(tmp_csr, OPAMP_CSR_S5SELX(hopamp)); } else if (hopamp->Init.NonInvertingInput == OPAMP_NONINVERTINGINPUT_DAC_CH1) { /* Particular case for connection to DAC channel 1: */ /* OPAMP_NONINVERTINGINPUT_DAC_CH1 available on OPAMP1 and OPAMP2 only */ /* (OPAMP3 availability depends on device category). */ if ((hopamp->Instance == OPAMP1) || (hopamp->Instance == OPAMP2)) { /* Close switch to connect OPAMP non-inverting input to */ /* DAC channel 1. */ SET_BIT(tmp_csr, OPAMP_CSR_S6SELX(hopamp)); } else { /* Set HAL status to error if another OPAMP instance as OPAMP1 or */ /* OPAMP2 is intended to be connected to DAC channel 2. */ status = HAL_ERROR; } } else /* if (hopamp->Init.NonInvertingInput == */ /* OPAMP_NONINVERTINGINPUT_DAC_CH2 ) */ { /* Particular case for connection to DAC channel 2: */ /* OPAMP_NONINVERTINGINPUT_DAC_CH2 available on OPAMP2 and OPAMP3 only */ /* (OPAMP3 availability depends on device category). */ if (hopamp->Instance == OPAMP2) { /* Close switch to connect OPAMP non-inverting input to */ /* DAC channel 2. */ SET_BIT(tmp_csr, OPAMP_CSR_S7SEL2); } /* If OPAMP3 is selected (if available) */ else if (hopamp->Instance != OPAMP1) { /* Close switch to connect OPAMP non-inverting input to */ /* DAC channel 2. */ SET_BIT(tmp_csr, OPAMP_CSR_S6SELX(hopamp)); } else { /* Set HAL status to error if another OPAMP instance as OPAMP2 or */ /* OPAMP3 (if available) is intended to be connected to DAC channel 2.*/ status = HAL_ERROR; } } /* Continue OPAMP configuration if settings of switches are correct */ if (status != HAL_ERROR) { /* Set power mode and associated calibration parameters */ if (hopamp->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER) { /* Set normal mode */ CLEAR_BIT(tmp_csr, OPAMP_CSR_OPAXLPM(hopamp)); if (hopamp->Init.UserTrimming == OPAMP_TRIMMING_USER) { /* Set calibration mode (factory or user) and values for */ /* transistors differential pair high (PMOS) and low (NMOS) for */ /* normal mode. */ MODIFY_REG(OPAMP->OTR, OPAMP_OTR_OT_USER | OPAMP_OFFSET_TRIM_SET(hopamp, OPAMP_FACTORYTRIMMING_N, OPAMP_TRIM_VALUE_MASK) | OPAMP_OFFSET_TRIM_SET(hopamp, OPAMP_FACTORYTRIMMING_P, OPAMP_TRIM_VALUE_MASK) , hopamp->Init.UserTrimming | OPAMP_OFFSET_TRIM_SET(hopamp, OPAMP_FACTORYTRIMMING_N, hopamp->Init.TrimmingValueN) | OPAMP_OFFSET_TRIM_SET(hopamp, OPAMP_FACTORYTRIMMING_P, hopamp->Init.TrimmingValueP) ); } else { /* Set calibration mode to factory */ CLEAR_BIT(OPAMP->OTR, OPAMP_OTR_OT_USER); } } else { /* Set low power mode */ SET_BIT(tmp_csr, OPAMP_CSR_OPAXLPM(hopamp)); if (hopamp->Init.UserTrimming == OPAMP_TRIMMING_USER) { /* Set calibration mode to user trimming */ SET_BIT(OPAMP->OTR, OPAMP_OTR_OT_USER); /* Set values for transistors differential pair high (PMOS) and low */ /* (NMOS) for low power mode. */ MODIFY_REG(OPAMP->LPOTR, OPAMP_OFFSET_TRIM_SET(hopamp, OPAMP_FACTORYTRIMMING_N, OPAMP_TRIM_VALUE_MASK) | OPAMP_OFFSET_TRIM_SET(hopamp, OPAMP_FACTORYTRIMMING_P, OPAMP_TRIM_VALUE_MASK) , OPAMP_OFFSET_TRIM_SET(hopamp, OPAMP_FACTORYTRIMMING_N, hopamp->Init.TrimmingValueNLowPower) | OPAMP_OFFSET_TRIM_SET(hopamp, OPAMP_FACTORYTRIMMING_P, hopamp->Init.TrimmingValuePLowPower) ); } else { /* Set calibration mode to factory trimming */ CLEAR_BIT(OPAMP->OTR, OPAMP_OTR_OT_USER); } } /* Configure the power supply range */ MODIFY_REG(tmp_csr, OPAMP_CSR_AOP_RANGE, hopamp->Init.PowerSupplyRange); /* Set OPAMP CSR register from temporary variable */ /* This allows to apply all changes on one time, in case of update on */ /* the fly with OPAMP previously set and running: */ /* - to avoid hazardous transient switches settings (risk of short */ /* circuit) */ /* - to avoid interruption of input signal */ OPAMP->CSR = tmp_csr; /* Update the OPAMP state */ /* If coming from state reset: Update from state RESET to state READY */ if (hopamp->State == HAL_OPAMP_STATE_RESET) { hopamp->State = HAL_OPAMP_STATE_READY; } /* else: OPAMP state remains READY or BUSY state (no update) */ } } return status; }