From 6076bdf27d3c70675dff3b1866a3bbc82aa1eb00 Mon Sep 17 00:00:00 2001 From: Fabien Poussin Date: Thu, 31 Jan 2019 17:52:13 +0100 Subject: Updating OpAmp code with calibration functions, cleaning. --- os/hal/ports/STM32/LLD/OPAMPv1/hal_opamp_lld.c | 473 +++++++++++++++++++++++-- os/hal/ports/STM32/LLD/OPAMPv1/hal_opamp_lld.h | 153 ++++++-- 2 files changed, 568 insertions(+), 58 deletions(-) (limited to 'os/hal/ports') diff --git a/os/hal/ports/STM32/LLD/OPAMPv1/hal_opamp_lld.c b/os/hal/ports/STM32/LLD/OPAMPv1/hal_opamp_lld.c index 7251002..db988aa 100644 --- a/os/hal/ports/STM32/LLD/OPAMPv1/hal_opamp_lld.c +++ b/os/hal/ports/STM32/LLD/OPAMPv1/hal_opamp_lld.c @@ -1,6 +1,7 @@ /* 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. @@ -98,29 +99,29 @@ void opamp_lld_init(void) { #if STM32_OPAMP_USE_OPAMP1 /* Driver initialization.*/ opampObjectInit(&OPAMPD1); - OPAMPD1.reg = OPAMP; - OPAMPD1.reg->CSR = 0; + OPAMPD1.opamp = OPAMP; + OPAMPD1.opamp->CSR = 0; #endif #if STM32_OPAMP_USE_OPAMP2 /* Driver initialization.*/ opampObjectInit(&OPAMPD2); - OPAMPD2.reg = OPAMP2; - OPAMPD2.reg->CSR = 0; + OPAMPD2.opamp = OPAMP2; + OPAMPD2.opamp->CSR = 0; #endif #if STM32_OPAMP_USE_OPAMP3 /* Driver initialization.*/ opampObjectInit(&OPAMPD3); - OPAMPD3.reg = OPAMP3; - OPAMPD3.reg->CSR = 0; + OPAMPD3.opamp = OPAMP3; + OPAMPD3.opamp->CSR = 0; #endif #if STM32_OPAMP_USE_OPAMP4 /* Driver initialization.*/ opampObjectInit(&OPAMPD4); - OPAMPD4.reg = OPAMP4; - OPAMPD4.reg->CSR = 0; + OPAMPD4.opamp = OPAMP4; + OPAMPD4.opamp->CSR = 0; #endif } @@ -128,29 +129,29 @@ void opamp_lld_init(void) { /** * @brief Configures and activates the OPAMP peripheral. * - * @param[in] compp pointer to the @p OPAMPDriver object + * @param[in] opampp pointer to the @p OPAMPDriver object * * @notapi */ -void opamp_lld_start(OPAMPDriver *compp) { +void opamp_lld_start(OPAMPDriver *opampp) { // Apply CSR Execpt the enable bit. - compp->reg->CSR = compp->config->csr & ~OPAMP_CSR_OPAMPxEN; + opampp->opamp->CSR = opampp->config->csr & ~OPAMP_CSR_OPAMPxEN; } /** * @brief Deactivates the comp peripheral. * - * @param[in] compp pointer to the @p OPAMPDriver object + * @param[in] opampp pointer to the @p OPAMPDriver object * * @notapi */ -void opamp_lld_stop(OPAMPDriver *compp) { +void opamp_lld_stop(OPAMPDriver *opampp) { - if (compp->state == OPAMP_READY) { + if (opampp->state == OPAMP_ACTIVE) { - compp->reg->CSR = 0; + opampp->opamp->CSR = 0; } } @@ -158,27 +159,457 @@ void opamp_lld_stop(OPAMPDriver *compp) { /** * @brief Enables the output. * - * @param[in] compp pointer to the @p OPAMPDriver object + * @param[in] opampp pointer to the @p OPAMPDriver object * * @notapi */ -void opamp_lld_enable(OPAMPDriver *compp) { +void opamp_lld_enable(OPAMPDriver *opampp) { - compp->reg->CSR |= OPAMP_CSR_OPAMPxEN; /* Enable */ + opampp->opamp->CSR |= OPAMP_CSR_OPAMPxEN; /* Enable */ } /** * @brief Disables the output. * - * @param[in] compp pointer to the @p OPAMPDriver object + * @param[in] opampp pointer to the @p OPAMPDriver object * * @notapi */ -void opamp_lld_disable(OPAMPDriver *compp) { +void opamp_lld_disable(OPAMPDriver *opampp) { - compp->reg->CSR &= ~OPAMP_CSR_OPAMPxEN; /* Disable */ + 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<CSR, OPAMP_CSR_TRIMOFFSETN, + trimmingvaluen2<CSR, OPAMP_CSR_TRIMOFFSETN, + trimmingvaluen3<CSR, OPAMP_CSR_TRIMOFFSETN, + trimmingvaluen4<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<CSR, OPAMP_CSR_TRIMOFFSETN, + trimmingvaluen2<CSR, OPAMP_CSR_TRIMOFFSETN, + trimmingvaluen3<CSR, OPAMP_CSR_TRIMOFFSETN, + trimmingvaluen4<CSR & OPAMP_CSR_OUTCAL) { + /* OPAMP_CSR_OUTCAL is HIGH try higher trimming */ + trimmingvaluen1 += (trimmingvaluen1 != 31); + MODIFY_REG(OPAMPD1.opamp->CSR, OPAMP_CSR_TRIMOFFSETN, + trimmingvaluen1<CSR & OPAMP_CSR_OUTCAL) { + trimmingvaluen2 += (trimmingvaluen2 != 31); + MODIFY_REG(OPAMPD2.opamp->CSR, OPAMP_CSR_TRIMOFFSETN, + trimmingvaluen2<CSR & OPAMP_CSR_OUTCAL) { + trimmingvaluen3 += (trimmingvaluen3 != 31); + MODIFY_REG(OPAMPD3.opamp->CSR, OPAMP_CSR_TRIMOFFSETN, + trimmingvaluen3<CSR & OPAMP_CSR_OUTCAL) { + trimmingvaluen4 += (trimmingvaluen4 != 31); + MODIFY_REG(OPAMPD4.opamp->CSR, OPAMP_CSR_TRIMOFFSETN, + trimmingvaluen4<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<CSR, OPAMP_CSR_TRIMOFFSETP, + trimmingvaluep2<CSR, OPAMP_CSR_TRIMOFFSETP, + trimmingvaluep3<CSR, OPAMP_CSR_TRIMOFFSETP, + trimmingvaluep4<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<CSR, OPAMP_CSR_TRIMOFFSETP, + trimmingvaluep2<CSR, OPAMP_CSR_TRIMOFFSETP, + trimmingvaluep3<CSR, OPAMP_CSR_TRIMOFFSETP, + trimmingvaluep4<CSR & OPAMP_CSR_OUTCAL) { + /* OPAMP_CSR_OUTCAL is HIGH try higher trimming */ + trimmingvaluep1 += (trimmingvaluep1 != 31); + MODIFY_REG(OPAMPD1.opamp->CSR, OPAMP_CSR_TRIMOFFSETP, + trimmingvaluep1<CSR & OPAMP_CSR_OUTCAL) { + trimmingvaluep2 += (trimmingvaluep2 != 31); + MODIFY_REG(OPAMPD2.opamp->CSR, OPAMP_CSR_TRIMOFFSETP, + trimmingvaluep2<CSR & OPAMP_CSR_OUTCAL) { + trimmingvaluep3 += (trimmingvaluep3 != 31); + MODIFY_REG(OPAMPD3.opamp->CSR, OPAMP_CSR_TRIMOFFSETP, + trimmingvaluep3<CSR & OPAMP_CSR_OUTCAL) { + trimmingvaluep4 += (trimmingvaluep4 != 31); + MODIFY_REG(OPAMPD4.opamp->CSR, OPAMP_CSR_TRIMOFFSETP, + trimmingvaluep4<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<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<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<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<