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/include/hal_opamp.h | 29 +- os/hal/ports/STM32/LLD/OPAMPv1/hal_opamp_lld.c | 473 +++++++++++++++++++++++-- os/hal/ports/STM32/LLD/OPAMPv1/hal_opamp_lld.h | 153 ++++++-- os/hal/src/hal_opamp.c | 12 +- 4 files changed, 582 insertions(+), 85 deletions(-) (limited to 'os/hal') diff --git a/os/hal/include/hal_opamp.h b/os/hal/include/hal_opamp.h index 383e928..b20c938 100644 --- a/os/hal/include/hal_opamp.h +++ b/os/hal/include/hal_opamp.h @@ -26,6 +26,9 @@ /* Driver constants. */ /*===========================================================================*/ +#define OPAMP_P_BELOW_M (0U) +#define OPAMP_M_BELOW_P (1U) + /*===========================================================================*/ /* Driver pre-compile time settings. */ /*===========================================================================*/ @@ -44,8 +47,8 @@ typedef enum { OPAMP_UNINIT = 0, /**< Not initialized. */ OPAMP_STOP = 1, /**< Stopped. */ - OPAMP_READY = 2, /**< Ready. */ - OPAMP_ACTIVE = 3, /**< Active cycle phase. */ + OPAMP_ACTIVE = 2, /**< Active. */ + OPAMP_CALIBRATING = 3, /**< Calibration in progress. */ } opampstate_t; /** @@ -60,29 +63,13 @@ typedef struct OPAMPDriver OPAMPDriver; /*===========================================================================*/ /** - * @name Macro Functions - * @{ - */ -/** - * @brief Enables the input capture. - * - * @param[in] opamp pointer to the @p OPAMPDriver object - * + * @brief Calibrate opamps + * * * @iclass */ -#define opampEnableI(opamp) opamp_lld_enable(opamp) - -/** - * @brief Disables the input capture. - * - * @param[in] opamp pointer to the @p OPAMPDriver object - * - * @iclass - */ -#define opampDisableI(opamp) opamp_lld_disable(opamp) +#define opampCalibrate() opamp_lld_calibrate() /** @} */ - /** * @name Low Level driver helper macros * @{ 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<state == OPAMP_STOP) || (opampp->state == OPAMP_READY), + osalDbgAssert((opampp->state == OPAMP_STOP) || (opampp->state == OPAMP_ACTIVE), "invalid state"); opampp->config = config; opamp_lld_start(opampp); - opampp->state = OPAMP_READY; + opampp->state = OPAMP_ACTIVE; osalSysUnlock(); } @@ -106,7 +106,7 @@ void opampStop(OPAMPDriver *opampp) { osalDbgCheck(opampp != NULL); osalSysLock(); - osalDbgAssert((opampp->state == OPAMP_STOP) || (opampp->state == OPAMP_READY), + osalDbgAssert((opampp->state == OPAMP_STOP) || (opampp->state == OPAMP_ACTIVE), "invalid state"); opamp_lld_stop(opampp); opampp->state = OPAMP_STOP; @@ -125,7 +125,7 @@ void opampEnable(OPAMPDriver *opampp) { osalDbgCheck(opampp != NULL); osalSysLock(); - osalDbgAssert(opampp->state == OPAMP_READY, "invalid state"); + osalDbgAssert(opampp->state == OPAMP_ACTIVE, "invalid state"); opamp_lld_enable(opampp); opampp->state = OPAMP_ACTIVE; osalSysUnlock(); @@ -143,10 +143,10 @@ void opampDisable(OPAMPDriver *opampp) { osalDbgCheck(opampp != NULL); osalSysLock(); - osalDbgAssert((opampp->state == OPAMP_READY) || (opampp->state == OPAMP_ACTIVE), + osalDbgAssert((opampp->state == OPAMP_ACTIVE), "invalid state"); opamp_lld_disable(opampp); - opampp->state = OPAMP_READY; + opampp->state = OPAMP_ACTIVE; osalSysUnlock(); } -- cgit v1.2.3