From e4d47d61cc7a5500a83b177ca32e139aaaa7a1de Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sun, 30 Apr 2017 11:05:34 +0200 Subject: [PATCH 1/3] STM32F33: Add OPAMP support --- arch/arm/src/stm32/Make.defs | 4 + arch/arm/src/stm32/chip/stm32f33xxx_opamp.h | 6 +- arch/arm/src/stm32/chip/stm32f33xxx_pinmap.h | 7 +- arch/arm/src/stm32/stm32.h | 1 + arch/arm/src/stm32/stm32_opamp.c | 1418 ++++++++++++++++++ arch/arm/src/stm32/stm32_opamp.h | 231 +++ 6 files changed, 1661 insertions(+), 6 deletions(-) create mode 100644 arch/arm/src/stm32/stm32_opamp.c create mode 100644 arch/arm/src/stm32/stm32_opamp.h diff --git a/arch/arm/src/stm32/Make.defs b/arch/arm/src/stm32/Make.defs index 970ce3ba0c0..3429ba88a4f 100644 --- a/arch/arm/src/stm32/Make.defs +++ b/arch/arm/src/stm32/Make.defs @@ -221,6 +221,10 @@ ifeq ($(CONFIG_COMP),y) CHIP_CSRCS += stm32_comp.c endif +ifeq ($(CONFIG_OPAMP),y) +CHIP_CSRCS += stm32_opamp.c +endif + ifeq ($(CONFIG_STM32_1WIREDRIVER),y) CHIP_CSRCS += stm32_1wire.c endif diff --git a/arch/arm/src/stm32/chip/stm32f33xxx_opamp.h b/arch/arm/src/stm32/chip/stm32f33xxx_opamp.h index a6940bb0550..3a254af3a80 100644 --- a/arch/arm/src/stm32/chip/stm32f33xxx_opamp.h +++ b/arch/arm/src/stm32/chip/stm32f33xxx_opamp.h @@ -54,7 +54,7 @@ /* Register Addresses *******************************************************************************/ -#define STM32_OPAMP2_CSR (STM32_OPAMP2_BASE+STM32_OPAMP2_CSR_OFFSET) +#define STM32_OPAMP2_CSR (STM32_OPAMP_BASE+STM32_OPAMP2_CSR_OFFSET) /* Register Bitfield Definitions ****************************************************/ @@ -66,7 +66,7 @@ #define OPAMP_CSR_VPSEL_SHIFT (3) /* Bits 2-3: OPAMP non inverting input selection */ #define OPAMP_CSR_VPSEL_MASK (3 << OPAMP_CSR_VPSEL_SHIFT) /* 00: Reserved */ -# define OPAMP_CSR_VPSEL_PB13 (1 << OPAMP_CSR_VPSEL_SHIFT) /* 01: PB14 */ +# define OPAMP_CSR_VPSEL_PB14 (1 << OPAMP_CSR_VPSEL_SHIFT) /* 01: PB14 */ # define OPAMP_CSR_VPSEL_PB0 (2 << OPAMP_CSR_VPSEL_SHIFT) /* 10: PB0 */ # define OPAMP_CSR_VPSEL_PA7 (3 << OPAMP_CSR_VPSEL_SHIFT) /* 11: PA7 */ /* Bit 4: Reserved */ @@ -74,7 +74,7 @@ #define OPAMP_CSR_VMSEL_MASK (3 << OPAMP_CSR_VMSEL_SHIFT) # define OPAMP_CSR_VMSEL_PC5 (0 << OPAMP_CSR_VMSEL_SHIFT) /* 00: PC5 */ # define OPAMP_CSR_VMSEL_PA5 (1 << OPAMP_CSR_VMSEL_SHIFT) /* 01: PA5 */ -# define OPAMP_CSR_VMSEL_RESISTOR (2 << OPAMP_CSR_VMSEL_SHIFT) /* 10: Resistor feedback output */ +# define OPAMP_CSR_VMSEL_PGA (2 << OPAMP_CSR_VMSEL_SHIFT) /* 10: Resistor feedback output (PGA mode)*/ # define OPAMP_CSR_VMSEL_FOLLOWER (3 << OPAMP_CSR_VMSEL_SHIFT) /* 11: Follower mode */ #define OPAMP_CSR_TCMEN (1 << 7) /* Bit 7: Timer controlled Mux mode enable */ #define OPAMP_CSR_VMSSEL (1 << 8) /* Bit 8: OPAMP inverting input secondary selection */ diff --git a/arch/arm/src/stm32/chip/stm32f33xxx_pinmap.h b/arch/arm/src/stm32/chip/stm32f33xxx_pinmap.h index b5b97c88da0..e0ad65fc1af 100644 --- a/arch/arm/src/stm32/chip/stm32f33xxx_pinmap.h +++ b/arch/arm/src/stm32/chip/stm32f33xxx_pinmap.h @@ -337,9 +337,10 @@ #define GPIO_OPAMP2_VINM_1 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN5) #define GPIO_OPAMP2_VINM_2 (GPIO_ANALOG|GPIO_PORTC|GPIO_PIN5) #define GPIO_OPAMP2_VOUT (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN6) -#define GPIO_OPAMP2_VINP_1 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN7) -#define GPIO_OPAMP2_VINP_2 (GPIO_ANALOG|GPIO_PORTB|GPIO_PIN0) -#define GPIO_OPAMP2_VINP_3 (GPIO_ANALOG|GPIO_PORTB|GPIO_PIN14) +#undef GPIO_OPAMP2_VINP_1 /* not supported in F33XX */ +#define GPIO_OPAMP2_VINP_2 (GPIO_ANALOG|GPIO_PORTA|GPIO_PIN7) +#define GPIO_OPAMP2_VINP_3 (GPIO_ANALOG|GPIO_PORTB|GPIO_PIN0) +#define GPIO_OPAMP2_VINP_4 (GPIO_ANALOG|GPIO_PORTB|GPIO_PIN14) /* TSC */ diff --git a/arch/arm/src/stm32/stm32.h b/arch/arm/src/stm32/stm32.h index 534d30246c0..56225ee211d 100644 --- a/arch/arm/src/stm32/stm32.h +++ b/arch/arm/src/stm32/stm32.h @@ -69,6 +69,7 @@ #include "stm32_gpio.h" #include "stm32_i2c.h" #include "stm32_ltdc.h" +#include "stm32_opamp.h" #include "stm32_pwr.h" #include "stm32_rcc.h" #include "stm32_rtc.h" diff --git a/arch/arm/src/stm32/stm32_opamp.c b/arch/arm/src/stm32/stm32_opamp.c new file mode 100644 index 00000000000..e79e8ed8068 --- /dev/null +++ b/arch/arm/src/stm32/stm32_opamp.c @@ -0,0 +1,1418 @@ +/**************************************************************************** + * arch/arm/src/stm32/stm32_opamp.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Mateusz Szafoni + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "chip.h" +#include "stm32_gpio.h" +#include "stm32_opamp.h" + +/* OPAMP "upper half" support must be enabled */ + +#ifdef CONFIG_STM32_OPAMP + +/* Some OPAMP peripheral must be enabled */ +/* Up to 4 OPAMPs in STM32F3 Series */ + +#if defined(CONFIG_STM32_OPAMP1) || defined(CONFIG_STM32_OPAMP2) || \ + defined(CONFIG_STM32_OPAMP3) || defined(CONFIG_STM32_OPAMP4) + +#ifndef CONFIG_STM32_SYSCFG +# error "SYSCFG clock enable must be set" +#endif + +/* @TODO: support for STM32F30XX opamps */ + +#if defined(CONFIG_STM32_STM32F30XX) || defined(CONFIG_STM32_STM32F33XX) + +/* Currently only STM32F33XX supported */ + +#if defined(CONFIG_STM32_STM32F30XX) +# error "Not supported yet" +#endif + +#if defined(CONFIG_STM32_STM32F33XX) +# if defined(CONFIG_STM32_OPAMP1) || defined(CONFIG_STM32_OPAMP3) || \ + defined(CONFIG_STM32_OPAMP4) +# error "STM32F33 supports only OPAMP2" +# endif +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* OPAMPs default configuration *********************************************/ + +#ifdef CONFIG_STM32_OPAMP1 +# ifndef OPAMP1_MODE +# define OPAMP1_MODE OPAMP_MODE_DEFAULT +# endif +# ifndef OPAMP1_MUX +# define OPAMP1_MUX OPAMP_MUX_DEFAULT +# endif +# ifndef OPAMP1_USERCAL +# define OPAMP1_USERCAL OPAMP_USERCAL_DEFAULT +# endif +# ifndef OPAMP1_LOCK +# define OPAMP1_LOCK OPAMP_LOCK_DEFAULT +# endif +# ifndef OPAMP1_GAIN +# define OPAMP1_GAIN OPAMP_GAIN_DEFAULT +# endif +#endif +#ifdef CONFIG_STM32_OPAMP2 +# ifndef OPAMP2_MODE +# define OPAMP2_MODE OPAMP_MODE_DEFAULT +# endif +# ifndef OPAMP2_MUX +# define OPAMP2_MUX OPAMP_MUX_DEFAULT +# endif +# ifndef OPAMP2_USERCAL +# define OPAMP2_USERCAL OPAMP_USERCAL_DEFAULT +# endif +# ifndef OPAMP2_LOCK +# define OPAMP2_LOCK OPAMP_LOCK_DEFAULT +# endif +# ifndef OPAMP2_GAIN +# define OPAMP2_GAIN OPAMP_GAIN_DEFAULT +# endif +#endif +#ifdef CONFIG_STM32_OPAMP3 +# ifndef OPAMP3_MODE +# define OPAMP3_MODE OPAMP_MODE_DEFAULT +# endif +# ifndef OPAMP3_MUX +# define OPAMP3_MUX OPAMP_MUX_DEFAULT +# endif +# ifndef OPAMP3_USERCAL +# define OPAMP3_USERCAL OPAMP_USERCAL_DEFAULT +# endif +# ifndef OPAMP3_LOCK +# define OPAMP3_LOCK OPAMP_LOCK_DEFAULT +# endif +# ifndef OPAMP3_GAIN +# define OPAMP3_GAIN OPAMP_GAIN_DEFAULT +# endif +#endif +#ifdef CONFIG_STM32_OPAMP4 +# ifndef OPAMP4_MODE +# define OPAMP4_MODE OPAMP_MODE_DEFAULT +# endif +# ifndef OPAMP4_MUX +# define OPAMP4_MUX OPAMP_MUX_DEFAULT +# endif +# ifndef OPAMP4_USERCAL +# define OPAMP4_USERCAL OPAMP_USERCAL_DEFAULT +# endif +# ifndef OPAMP4_LOCK +# define OPAMP4_LOCK OPAMP_LOCK_DEFAULT +# endif +# ifndef OPAMP4_GAIN +# define OPAMP4_GAIN OPAMP_GAIN_DEFAULT +# endif +#endif + +/* Some assertions *******************************************************/ + +/* Check OPAMPs inputs selection */ + +#ifdef CONFIG_STM32_OPAMP1 +# if (OPAMP1_MODE == OPAMP_MODE_FOLLOWER) +# define OPAMP1_VMSEL OPAMP1_VMSEL_FOLLOWER +# endif +# if (OPAMP1_MODE == OPAMP_MODE_PGA) +# define OPAMP1_VMSEL OPAMP1_VMSEL_PGA +# endif +# if (OPAMP1_MODE == OPAMP_MODE_STANDALONE) +# ifndef OPAMP1_VMSEL +# error "OPAMP1_VMSEL must be selected in standalone mode!" +# endif +# endif +# ifndef OPAMP1_VPSEL +# error "OPAMP1_VPSEL must be slected in standalone mode!" +# endif +#endif +#ifdef CONFIG_STM32_OPAMP2 +# if (OPAMP2_MODE == OPAMP_MODE_FOLLOWER) +# define OPAMP2_VMSEL OPAMP2_VMSEL_FOLLOWER +# endif +# if (OPAMP2_MODE == OPAMP_MODE_PGA) +# define OPAMP2_VMSEL OPAMP2_VMSEL_PGA +# endif +# if (OPAMP2_MODE == OPAMP_MODE_STANDALONE) +# ifndef OPAMP2_VMSEL +# error "OPAMP2_VMSEL must be selected in standalone mode!" +# endif +# endif +# ifndef OPAMP2_VPSEL +# error "OPAMP2_VPSEL must be slected in standalone mode!" +# endif +#endif +#ifdef CONFIG_STM32_OPAMP3 +# if (OPAMP3_MODE == OPAMP_MODE_FOLLOWER) +# define OPAMP3_VMSEL OPAMP3_VMSEL_FOLLOWER +# endif +# if (OPAMP3_MODE == OPAMP_MODE_PGA) +# define OPAMP3_VMSEL OPAMP3_VMSEL_PGA +# endif +# if (OPAMP3_MODE == OPAMP_MODE_STANDALONE) +# ifndef OPAMP3_VMSEL +# error "OPAMP3_VMSEL must be selected in standalone mode!" +# endif +# endif +# ifndef OPAMP3_VPSEL +# error "OPAMP3_VPSEL must be slected in standalone mode!" +# endif +#endif +#ifdef CONFIG_STM32_OPAMP4 +# if (OPAMP4_MODE == OPAMP_MODE_FOLLOWER) +# define OPAMP4_VMSEL OPAMP4_VMSEL_FOLLOWER +# endif +# if (OPAMP4_MODE == OPAMP_MODE_PGA) +# define OPAMP4_VMSEL OPAMP4_VMSEL_PGA +# endif +# if (OPAMP4_MODE == OPAMP_MODE_STANDALONE) +# ifndef OPAMP4_VMSEL +# error "OPAMP4_VMSEL must be selected in standalone mode!" +# endif +# endif +# ifndef OPAMP4_VPSEL +# error "OPAMP4_VPSEL must be slected in standalone mode!" +# endif +#endif + +/* When OPAMP MUX enabled, make sure that secondary selection inputs are configured */ + +#ifdef CONFIG_STM32_OPAMP1 +# if (OPAMP1_MUX == OPAMP_MUX_ENABLE) +# if !defined(OPAMP1_VMSSEL) || !defined(OPAMP1_VPSSEL) +# error "OPAMP1_VMSSEL and OPAMP1_VPSSEL must be selected when OPAMP1 MUX enabled!" +# endif +# endif +#endif +#ifdef CONFIG_STM32_OPAMP2 +# if (OPAMP2_MUX == OPAMP_MUX_ENABLE) +# if !defined(OPAMP2_VMSSEL) || !defined(OPAMP2_VPSSEL) +# error "OPAMP2_VMSSEL and OPAMP2_VPSSEL must be selected when OPAMP2 MUX enabled!" +# endif +# endif +#endif +#ifdef CONFIG_STM32_OPAMP3 +# if (OPAMP3_MUX == OPAMP_MUX_ENABLE) +# if !defined(OPAMP3_VMSSEL) || !defined(OPAMP3_VPSSEL) +# error "OPAMP3_VMSSEL and OPAMP3_VPSSEL must be selected when OPAMP3 MUX enabled!" +# endif +# endif +#endif +#ifdef CONFIG_STM32_OPAMP4 +# if (OPAMP4_MUX == OPAMP_MUX_ENABLE) +# if !defined(OPAMP4_VMSSEL) || !defined(OPAMP4_VPSSEL) +# error "OPAMP4_VMSSEL and OPAMP4_VPSSEL must be selected when OPAMP4 MUX enabled!" +# endif +# endif +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes the configuration of one OPAMP device */ + +struct stm32_opamp_s +{ + uint32_t csr; /* Control and status register */ + + uint8_t lock:1; /* OPAMP lock */ + uint8_t mux:1; /* Timer controlled MUX mode */ + uint8_t mode:2; /* OPAMP mode */ + uint8_t gain:4; /* OPAMP gain in PGA mode */ + + uint8_t vm_sel:2; /* Inverting input selection */ + uint8_t vp_sel:2; /* Non inverting input selection */ + uint8_t vms_sel:2; /* Inverting input secondary selection (MUX mode) */ + uint8_t vps_sel:2; /* Non inverting input secondary selection (Mux mode) */ + + uint16_t trim_n:5; /* Offset trimming value (NMOS) */ + uint16_t trim_p:5; /* Offset trimming value (PMOS) */ + uint16_t _reserved:6; /* reserved for calibration */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* OPAMP Register access */ + +static inline void opamp_modify_csr(FAR struct stm32_opamp_s *priv, + uint32_t clearbits, uint32_t setbits); +static inline uint32_t opamp_getreg_csr(FAR struct stm32_opamp_s* priv); +static inline void opamp_putreg_csr(FAR struct stm32_opamp_s* priv, + uint32_t value); +static bool stm32_opamplock_get(FAR struct stm32_opamp_s *priv); +static int stm32_opamplock(FAR struct stm32_opamp_s *priv, bool lock); + +/* Initialization */ + +static int stm32_opampconfig(FAR struct stm32_opamp_s *priv); +static int stm32_opampenable(FAR struct stm32_opamp_s *priv, bool enable); +static int stm32_opampgain_set(FAR struct stm32_opamp_s *priv, uint8_t gain); +#if 0 +static int stm32_opampcalibrate(FAR struct stm32_opamp_s *priv); +#endif + +/* OPAMP Driver Methods */ + +static void opamp_shutdown(FAR struct opamp_dev_s *dev); +static int opamp_setup(FAR struct opamp_dev_s *dev); +static int opamp_ioctl(FAR struct opamp_dev_s *dev, int cmd, unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct opamp_ops_s g_opampops = +{ + .ao_shutdown = opamp_shutdown, + .ao_setup = opamp_setup, + .ao_ioctl = opamp_ioctl +}; + +#ifdef CONFIG_STM32_OPAMP1 +static struct stm32_opamp_s g_opamp1priv = +{ + .csr = STM32_OPAMP1_CSR, + .lock = OPAMP1_LOCK, + .mux = OPAMP1_MUX, + .mode = OPAMP1_MODE, + .vm_sel = OPAMP1_VMSEL, + .vp_sel = OPAMP1_VPSEL, +#if OPAMP1_MUX == OPAMP_MUX_ENABLE + .vms_sel = OPAMP1_VMSSEL, + .vps_sel = OPAMP1_VPSSEL, +#endif + .gain = OPAMP1_GAIN +}; + +static struct opamp_dev_s g_opamp1dev = +{ + .ad_ops = &g_opampops, + .ad_priv = &g_opamp1priv +}; +#endif + +#ifdef CONFIG_STM32_OPAMP2 +static struct stm32_opamp_s g_opamp2priv = +{ + .csr = STM32_OPAMP2_CSR, + .lock = OPAMP2_LOCK, + .mux = OPAMP2_MUX, + .mode = OPAMP2_MODE, + .vm_sel = OPAMP2_VMSEL, + .vp_sel = OPAMP2_VPSEL, +#if OPAMP2_MUX == OPAMP_MUX_ENABLE + .vms_sel = OPAMP2_VMSSEL, + .vps_sel = OPAMP2_VPSSEL, +#endif + .gain = OPAMP2_GAIN +}; + +static struct opamp_dev_s g_opamp2dev = + { + .ad_ops = &g_opampops, + .ad_priv = &g_opamp2priv + }; +#endif + +#ifdef CONFIG_STM32_OPAMP3 +static struct stm32_opamp_s g_opamp3priv = +{ + .csr = STM32_OPAMP3_CSR, + .lock = OPAMP3_LOCK, + .mux = OPAMP3_MUX, + .mode = OPAMP3_MODE, + .vm_sel = OPAMP3_VMSEL, + .vp_sel = OPAMP3_VPSEL, +#if OPAMP3_MUX == OPAMP_MUX_ENABLE + .vms_sel = OPAMP3_VMSSEL, + .vps_sel = OPAMP3_VPSSEL, +#endif + .gain = OPAMP3_GAIN +}; + +static struct opamp_dev_s g_opamp3dev = +{ + .ad_ops = &g_opampops, + .ad_priv = &g_opamp3priv +}; +#endif + +#ifdef CONFIG_STM32_OPAMP4 +static struct stm32_opamp_s g_opamp4priv = +{ + .csr = STM32_OPAMP4_CSR, + .lock = OPAMP4_LOCK, + .mux = OPAMP4_MUX, + .mode = OPAMP4_MODE, + .vm_sel = OPAMP4_VMSEL, + .vp_sel = OPAMP4_VPSEL, +#if OPAMP4_MUX == OPAMP_MUX_ENABLE + .vms_sel = OPAMP4_VMSSEL, + .vps_sel = OPAMP4_VPSSEL, +#endif + .gain = OPAMP4_GAIN +}; + +static struct opamp_dev_s g_opamp4dev = +{ + .ad_ops = &g_opampops, + .ad_priv = &g_opamp4priv +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: opamp_modify_csr + * + * Description: + * Modify the value of a 32-bit OPAMP CSR register (not atomic). + * + * Input Parameters: + * priv - A reference to the OPAMP structure + * clrbits - The bits to clear + * setbits - The bits to set + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void opamp_modify_csr(FAR struct stm32_opamp_s *priv, + uint32_t clearbits, uint32_t setbits) +{ + uint32_t csr = priv->csr; + + modifyreg32(csr, clearbits, setbits); +} + +/**************************************************************************** + * Name: opamp_getreg_csr + * + * Description: + * Read the value of an OPAMP CSR register + * + * Input Parameters: + * priv - A reference to the OPAMP structure + * + * Returned Value: + * The current contents of the OPAMP CSR register + * + ****************************************************************************/ + +static inline uint32_t opamp_getreg_csr(FAR struct stm32_opamp_s *priv) +{ + uint32_t csr = priv->csr; + + return getreg32(csr); +} + +/**************************************************************************** + * Name: opamp_putreg_csr + * + * Description: + * Write a value to an OPAMP register. + * + * Input Parameters: + * priv - A reference to the OPAMP structure + * value - The value to write to the OPAMP CSR register + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void opamp_putreg_csr(FAR struct stm32_opamp_s *priv, + uint32_t value) +{ + uint32_t csr = priv->csr; + + putreg32(value, csr); +} + +/**************************************************************************** + * Name: stm32_opamp_opamplock_get + * + * Description: + * Get OPAMP lock bit state + * + * Input Parameters: + * priv - A reference to the OPAMP structure + * + * Returned Value: + * True if OPAMP locked, false if not locked + * + ****************************************************************************/ + +static bool stm32_opamplock_get(FAR struct stm32_opamp_s *priv) +{ + uint32_t regval; + + regval = opamp_getreg_csr(priv); + + return (((regval & OPAMP_CSR_LOCK) == 0) ? false : true); +} + +/**************************************************************************** + * Name: stm32_opamplock + * + * Description: + * Lock OPAMP CSR register + * + * Input Parameters: + * priv - A reference to the OPAMP structure + * enable - lock flag + * + * Returned Value: + * 0 on success, a negated errno value on failure + * + ****************************************************************************/ + +static int stm32_opamplock(FAR struct stm32_opamp_s *priv, bool lock) +{ + bool current; + + current = stm32_opamplock_get(priv); + + if (current) + { + if (lock == false) + { + aerr("ERROR: OPAMP LOCK can be cleared only by a system reset\n"); + + return -EPERM; + } + } + else + { + if (lock == true) + { + opamp_modify_csr(priv, 0, OPAMP_CSR_LOCK); + + priv->lock = OPAMP_LOCK_RO; + } + } + + return OK; +} + +/**************************************************************************** + * Name: stm32_opampconfig + * + * Description: + * Configure OPAMP and used I/Os + * + * Input Parameters: + * priv - A reference to the OPAMP structure + * + * Returned Value: + * 0 on success, a negated errno value on failure + * + ****************************************************************************/ + +static int stm32_opampconfig(FAR struct stm32_opamp_s *priv) +{ + uint32_t regval = 0; + int index; + + /* Get OPAMP index */ + + switch (priv->csr) + { +#ifdef CONFIG_STM32_OPAMP1 + case STM32_OPAMP1_CSR: + index = 1; + break; +#endif + +#ifdef CONFIG_STM32_OPAMP2 + case STM32_OPAMP2_CSR: + index = 2; + break; +#endif + +#ifdef CONFIG_STM32_OPAMP3 + case STM32_OPAMP3_CSR: + index = 3; + break; +#endif + +#ifdef CONFIG_STM32_OPAMP4 + case STM32_OPAMP4_CSR: + index = 4; + break; +#endif + + default: + return -EINVAL; + } + + /* Configure non inverting input */ + + switch (index) + { +#ifdef CONFIG_STM32_OPAMP1 + case 1: + { + switch (priv->vp_sel) + { + case OPAMP1_VPSEL_PA7: + stm32_configgpio(GPIO_OPAMP1_VINP_1); + regval |= OPAMP_CSR_VPSEL_PA7; + break; + + case OPAMP1_VPSEL_PA5: + stm32_configgpio(GPIO_OPAMP1_VINP_2); + regval |= OPAMP_CSR_VPSEL_PA5; + break; + + case OPAMP1_VPSEL_PA3: + stm32_configgpio(GPIO_OPAMP1_VINP_3); + regval |= OPAMP_CSR_VPSEL_PA3; + break; + + case OPAMP1_VPSEL_PA1: + stm32_configgpio(GPIO_OPAMP1_VINP_4); + regval |= OPAMP_CSR_VPSEL_PA1; + break; + + default: + return -EINVAL; + } + break; + } +#endif + +#ifdef CONFIG_STM32_OPAMP2 + case 2: + { + switch (priv->vp_sel) + { +#ifndef CONFIG_STM32_STM32F33XX + case OPAMP2_VPSEL_PD14: + stm32_configgpio(GPIO_OPAMP2_VINP_1); + regval |= OPAMP_CSR_VPSEL_PD14; + break; +#endif + case OPAMP2_VPSEL_PB14: + stm32_configgpio(GPIO_OPAMP2_VINP_2); + regval |= OPAMP_CSR_VPSEL_PB14; + break; + + case OPAMP2_VPSEL_PB0: + stm32_configgpio(GPIO_OPAMP2_VINP_3); + regval |= OPAMP_CSR_VPSEL_PB0; + break; + + case OPAMP2_VPSEL_PA7: + stm32_configgpio(GPIO_OPAMP2_VINP_4); + regval |= OPAMP_CSR_VPSEL_PA7; + break; + + default: + return -EINVAL; + } + break; + } +#endif + +#ifdef CONFIG_STM32_OPAMP3 + case 3: + { + switch (priv->vp_sel) + { + case OPAMP3_VPSEL_PB13: + stm32_configgpio(GPIO_OPAMP3_VINP_1); + regval |= OPAMP_CSR_VPSEL_PB13; + break; + + case OPAMP3_VPSEL_PA5: + stm32_configgpio(GPIO_OPAMP3_VINP_2); + regval |= OPAMP_CSR_VPSEL_PA5; + break; + + case OPAMP3_VPSEL_PA1: + stm32_configgpio(GPIO_OPAMP3_VINP_3); + regval |= OPAMP_CSR_VPSEL_PA1; + break; + + case OPAMP3_VPSEL_PB0: + stm32_configgpio(GPIO_OPAMP3_VINP_4); + regval |= OPAMP_CSR_VPSEL_PB0; + break; + + default: + return -EINVAL; + } + break; + } +#endif + +#ifdef CONFIG_STM32_OPAMP4 + case 4: + { + switch (priv->vp_sel) + { + case OPAMP4_VPSEL_PD11: + stm32_configgpio(GPIO_OPAMP4_VINP_1); + regval |= OPAMP_CSR_VPSEL_PD11; + break; + + case OPAMP4_VPSEL_PB11: + stm32_configgpio(GPIO_OPAMP4_VINP_2); + regval |= OPAMP_CSR_VPSEL_PB11; + break; + + case OPAMP4_VPSEL_PA4: + stm32_configgpio(GPIO_OPAMP4_VINP_3); + regval |= OPAMP_CSR_VPSEL_PA4; + break; + + case OPAMP4_VPSEL_PB13: + stm32_configgpio(GPIO_OPAMP4_VINP_4; + regval |= OPAMP_CSR_VPSEL_PB13; + break; + + default: + return -EINVAL; + } + break; + } +#endif + + default: + return -EINVAL; + } + + /* Configure inverting input */ + + switch (index) + { +#ifdef CONFIG_STM32_OPAMP1 + case 1: + { + switch (priv->vm_sel) + { + case OPAMP1_VSEL_PC5: + stm32_configgpio(GPIO_OPAMP1_VINM_1); + regval |= OPAMP_CSR_VMSEL_PC5; + break; + + case OPAMP1_VMSEL_PA3: + stm32_configgpio(GPIO_OPAMP1_VINM_2); + regval |= OPAMP_CSR_VMSEL_PA3; + break; + + case OPAMP1_VMSEL_PGAMODE: + regval |= OPAMP_CSR_VMSEL_PGA; + break; + + case OPAMP1_VMSEL_FOLLOWER: + regval |= OPAMP_CSR_VMSEL_FOLLOWER; + break; + + default: + return -EINVAL; + } + break; + } +#endif + +#ifdef CONFIG_STM32_OPAMP2 + case 2: + { + switch (priv->vm_sel) + { + case OPAMP2_VMSEL_PC5: + stm32_configgpio(GPIO_OPAMP2_VINM_1); + regval |= OPAMP_CSR_VMSEL_PC5; + break; + + case OPAMP2_VMSEL_PA5: + stm32_configgpio(GPIO_OPAMP2_VINM_2); + regval |= OPAMP_CSR_VMSEL_PA5; + break; + + case OPAMP2_VMSEL_PGAMODE: + regval |= OPAMP_CSR_VMSEL_PGA; + break; + + case OPAMP2_VMSEL_FOLLOWER: + regval |= OPAMP_CSR_VMSEL_FOLLOWER; + break; + + default: + return -EINVAL; + } + break; + } +#endif + +#ifdef CONFIG_STM32_OPAMP3 + case 3: + { + switch (priv->vm_sel) + { + case OPAMP3_VMSEL_PB10: + stm32_configgpio(GPIO_OPAMP3_VINM_1); + regval |= OPAMP_CSR_VMSEL_PB10; + break; + + case OPAMP3_VMSEL_PB2: + stm32_configgpio(GPIO_OPAMP3_VINM_2); + regval |= OPAMP_CSR_VMSEL_PB2; + break; + + case OPAMP3_VMSEL_PGAMODE: + regval |= OPAMP_CSR_VMSEL_PGA; + break; + + case OPAMP3_VMSEL_FOLLOWER: + regval |= OPAMP_CSR_VMSEL_FOLLOWER; + break; + + default: + return -EINVAL; + } + break; + } +#endif + +#ifdef CONFIG_STM32_OPAMP4 + case 4: + { + switch (priv->vm_sel) + { + case OPAMP4_VMSEL_PB10: + stm32_configgpio(GPIO_OPAMP4_VINM_1); + regval |= OPAMP_CSR_VMSEL_PB10; + break; + + case OPAMP4_VMSEL_PD8: + stm32_configgpio(GPIO_OPAMP4_VINM_2); + regval |= OPAMP_CSR_VMSEL_PD8; + break; + + case OPAMP4_VMSEL_PGAMODE: + regval |= OPAMP_CSR_VMSEL_PGA; + break; + + case OPAMP4_VMSEL_FOLLOWER: + regval |= OPAMP_CSR_VMSEL_FOLLOWER; + break; + + default: + return -EINVAL; + } + break; + } +#endif + + default: + return -EINVAL; + } + + if (priv->mux == 1) + { + /* Enable Timer controled Mux mode */ + + regval |= OPAMP_CSR_TCMEN; + + /* Configure non inverting secondary input */ + + switch (index) + { +#ifdef CONFIG_STM32_OPAMP1 + case 1: + { + switch (priv->vps_sel) + { + case OPAMP1_VPSEL_PA7: + stm32_configgpio(GPIO_OPAMP1_VINP_1); + regval |= OPAMP_CSR_VPSSEL_PA7; + break; + + case OPAMP1_VPSEL_PA5: + stm32_configgpio(GPIO_OPAMP1_VINP_2); + regval |= OPAMP_CSR_VPSSEL_PA5; + break; + + case OPAMP1_VPSEL_PA3: + stm32_configgpio(GPIO_OPAMP1_VINP_3); + regval |= OPAMP_CSR_VPSSEL_PA3; + break; + + case OPAMP1_VPSEL_PA1: + stm32_configgpio(GPIO_OPAMP1_VINP_4); + regval |= OPAMP_CSR_VPSSEL_PA1; + break; + + default: + return -EINVAL; + } + break; + } +#endif + +#ifdef CONFIG_STM32_OPAMP2 + case 2: + { + switch (priv->vps_sel) + { +#ifndef CONFIG_STM32_STM32F33XX + case OPAMP2_VPSEL_PD14: + stm32_configgpio(GPIO_OPAMP2_VINP_1); + regval |= OPAMP_CSR_VPSSEL_PD14; + break; +#endif + case OPAMP2_VPSEL_PB14: + stm32_configgpio(GPIO_OPAMP2_VINP_2); + regval |= OPAMP_CSR_VPSSEL_PB14; + break; + + case OPAMP2_VPSEL_PB0: + stm32_configgpio(GPIO_OPAMP2_VINP_3); + regval |= OPAMP_CSR_VPSSEL_PB0; + break; + + case OPAMP2_VPSEL_PA7: + stm32_configgpio(GPIO_OPAMP2_VINP_4); + regval |= OPAMP_CSR_VPSSEL_PA7; + break; + + default: + return -EINVAL; + } + break; + } +#endif + +#ifdef CONFIG_STM32_OPAMP3 + case 3: + { + switch (priv->vps_sel) + { + case OPAMP3_VPSEL_PB13: + stm32_configgpio(GPIO_OPAMP3_VINP_1); + regval |= OPAMP_CSR_VPSSEL_PB13; + break; + + case OPAMP3_VPSEL_PA5: + stm32_configgpio(GPIO_OPAMP3_VINP_2); + regval |= OPAMP_CSR_VPSSEL_PA5; + break; + + case OPAMP3_VPSEL_PA1: + stm32_configgpio(GPIO_OPAMP3_VINP_3); + regval |= OPAMP_CSR_VPSSEL_PA1; + break; + + case OPAMP3_VPSEL_PB0: + stm32_configgpio(GPIO_OPAMP3_VINP_4); + regval |= OPAMP_CSR_VPSSEL_PB0; + break; + + default: + return -EINVAL; + } + break; + } +#endif + +#ifdef CONFIG_STM32_OPAMP4 + case 4: + { + switch (priv->vps_sel) + { + case OPAMP4_VPSEL_PD11: + stm32_configgpio(GPIO_OPAMP4_VINP_1); + regval |= OPAMP_CSR_VPSSEL_PD11; + break; + + case OPAMP4_VPSEL_PB11: + stm32_configgpio(GPIO_OPAMP4_VINP_2); + regval |= OPAMP_CSR_VPSSEL_PB11; + break; + + case OPAMP4_VPSEL_PA4: + stm32_configgpio(GPIO_OPAMP4_VINP_3); + regval |= OPAMP_CSR_VPSSEL_PA4; + break; + + case OPAMP4_VPSEL_PB13: + stm32_configgpio(GPIO_OPAMP4_VINP_4); + regval |= OPAMP_CSR_VPSSEL_PB13; + break; + + default: + return -EINVAL; + } + break; + } +#endif + + default: + return -EINVAL; + } + + /* Configure inverting secondary input */ + + switch (index) + { +#ifdef CONFIG_STM32_OPAMP1 + case 1: + { + switch (priv->vms_sel) + { + case OPAMP1_VSEL_PC5: + stm32_configgpio(GPIO_OPAMP1_VINM_1); + regval &= ~OPAMP_CSR_VMSSEL; + break; + + case OPAMP1_VMSEL_PA3: + stm32_configgpio(GPIO_OPAMP1_VINM_2); + regval |= OPAMP_CSR_VMSSEL; + break; + + default: + return -EINVAL; + } + break; + } +#endif + +#ifdef CONFIG_STM32_OPAMP2 + case 2: + { + switch (priv->vms_sel) + { + case OPAMP2_VMSEL_PC5: + stm32_configgpio(GPIO_OPAMP2_VINM_1); + regval &= ~OPAMP_CSR_VMSSEL; + break; + + case OPAMP2_VMSEL_PA5: + stm32_configgpio(GPIO_OPAMP2_VINM_2); + regval |= OPAMP_CSR_VMSSEL; + break; + + default: + return -EINVAL; + } + break; + } +#endif + +#ifdef CONFIG_STM32_OPAMP3 + case 3: + { + switch (priv->vms_sel) + { + case OPAMP3_VMSEL_PB10: + stm32_configgpio(GPIO_OPAMP3_VINM_1); + regval &= ~OPAMP_CSR_VMSSEL; + break; + + case OPAMP3_VMSEL_PB2: + stm32_configgpio(GPIO_OPAMP3_VINM_2); + regval |= OPAMP_CSR_VMSSEL; + break; + + default: + return -EINVAL; + } + break; + } +#endif + +#ifdef CONFIG_STM32_OPAMP4 + case 4: + { + switch (priv->vms_sel) + { + case OPAMP4_VMSEL_PB10: + stm32_configgpio(GPIO_OPAMP4_VINM_1); + regval &= ~OPAMP_CSR_VMSSEL; + break; + + case OPAMP4_VMSEL_PD8: + stm32_configgpio(GPIO_OPAMP4_VINM_2); + regval |= OPAMP_CSR_VMSSEL; + break; + + default: + return -EINVAL; + } + break; + } +#endif + + default: + return -EINVAL; + } + } + + /* Save CSR register */ + + opamp_putreg_csr(priv, regval); + + /* Configure defaul gain in PGA mode */ + + stm32_opampgain_set(priv, priv->gain); + + /* Enable OPAMP */ + + stm32_opampenable(priv, true); + + /* TODO: OPAMP user calibration */ + /* stm32_opampcalibrate(priv); */ + + + /* Lock OPAMP if needed */ + + if (priv->lock == OPAMP_LOCK_RO) + { + stm32_opamplock(priv, true); + } + + return OK; +} + +/**************************************************************************** + * Name: stm32_opampenable + * + * Description: + * Enable/disable OPAMP + * + * Input Parameters: + * priv - A reference to the OPAMP structure + * enable - enable/disable flag + * + * Returned Value: + * 0 on success, a negated errno value on failure + * + ****************************************************************************/ + +static int stm32_opampenable(FAR struct stm32_opamp_s *priv, bool enable) +{ + bool lock; + + ainfo("enable: %d\n", enable ? 1 : 0); + + lock = stm32_opamplock_get(priv); + + if (lock) + { + aerr("ERROR: OPAMP locked!\n"); + + return -EPERM; + } + else + { + if (enable) + { + /* Enable the OPAMP */ + + opamp_modify_csr(priv, 0, OPAMP_CSR_OPAMPEN); + } + else + { + /* Disable the OPAMP */ + + opamp_modify_csr(priv, OPAMP_CSR_OPAMPEN, 0); + } + } + + return OK; +} + +/**************************************************************************** + * Name: stm32_opampgain_set + * + * Description: + * Set OPAMP gain + * + * Input Parameters: + * priv - A reference to the OPAMP structure + * gain - OPAMP gain + * + * Returned Value: + * 0 on success, a negated errno value on failure + * + ****************************************************************************/ + +static int stm32_opampgain_set(FAR struct stm32_opamp_s *priv, uint8_t gain) +{ + bool lock; + uint32_t regval = 0; + + lock = stm32_opamplock_get(priv); + + if (lock) + { + aerr("ERROR: OPAMP locked!\n"); + return -EPERM; + } + + regval = opamp_getreg_csr(priv); + + switch (gain) + { + case OPAMP_GAIN_2: + regval |= OPAMP_CSR_PGAGAIN_2; + break; + case OPAMP_GAIN_4: + regval |= OPAMP_CSR_PGAGAIN_4; + break; + case OPAMP_GAIN_8: + regval |= OPAMP_CSR_PGAGAIN_8; + break; + case OPAMP_GAIN_2_VM0: + regval |= OPAMP_CSR_PGAGAIN_2VM0; + break; + case OPAMP_GAIN_4_VM0: + regval |= OPAMP_CSR_PGAGAIN_4VM0; + break; + case OPAMP_GAIN_8_VM0: + regval |= OPAMP_CSR_PGAGAIN_8VM0; + break; + case OPAMP_GAIN_16_VM0: + regval |= OPAMP_CSR_PGAGAIN_16VM0; + break; + case OPAMP_GAIN_2_VM1: + regval |= OPAMP_CSR_PGAGAIN_2VM1; + break; + case OPAMP_GAIN_4_VM1: + regval |= OPAMP_CSR_PGAGAIN_4VM1; + break; + case OPAMP_GAIN_8_VM1: + regval |= OPAMP_CSR_PGAGAIN_8VM1; + break; + case OPAMP_GAIN_16_VM1: + regval |= OPAMP_CSR_PGAGAIN_16VM1; + break; + default: + aerr("ERROR: Unsupported OPAMP gain\n"); + return -EINVAL; + } + + /* Update gain in OPAMP device structure */ + + priv->gain = gain; + + return OK; + +} + +#if 0 +static int stm32_opampcalibrate(FAR struct stm32_opamp_s *priv) +{ +#warning "Missing logic" + return OK; +} +#endif + +/**************************************************************************** + * Name: opamp_shutdown + * + * Description: + * Disable the OPAMP. This method is called when the OPAMP device is closed. + * This method reverses the operation the setup method. + * Works only if OPAMP device is not locked. + * + * Input Parameters: + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void opamp_shutdown(FAR struct opamp_dev_s *dev) +{ +#warning "Missing logic" +} + +/**************************************************************************** + * Name: opamp_setup + * + * Description: + * Configure the OPAMP. This method is called the first time that the OPAMP + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching OPAMP interrupts. + * Interrupts are all disabled upon return. + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +static int opamp_setup(FAR struct opamp_dev_s *dev) +{ +#warning "Missing logic" + return OK; +} + +/**************************************************************************** + * Name: opamp_ioctl + * + * Description: + * All ioctl calls will be routed through this method. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * cmd - command + * arg - arguments passed with command + * + * Returned Value: + * + ****************************************************************************/ + +static int opamp_ioctl(FAR struct opamp_dev_s* dev, int cmd, unsigned long arg) +{ +#warning "Missing logic" + return -ENOTTY; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_opampinitialize + * + * Description: + * Initialize the OPAMP. + * + * Input Parameters: + * intf - The OPAMP interface number. + * + * Returned Value: + * Valid OPAMP device structure reference on succcess; a NULL on failure. + * + * Assumptions: + * 1. Clock to the OPAMP block has enabled, + * 2. Board-specific logic has already configured + * + ****************************************************************************/ + +FAR struct opamp_dev_s* stm32_opampinitialize(int intf) +{ + FAR struct opamp_dev_s *dev; + FAR struct stm32_opamp_s *opamp; + int ret; + + switch (intf) + { +#ifdef CONFIG_STM32_OPAMP1 + case 1: + ainfo("OPAMP1 selected\n"); + dev = &g_opamp1dev; + break; +#endif + +#ifdef CONFIG_STM32_OPAMP2 + case 2: + ainfo("OPAMP2 selected\n"); + dev = &g_opamp2dev; + break; +#endif + +#ifdef CONFIG_STM32_OPAMP3 + case 3: + ainfo("OPAMP3 selected\n"); + dev = &g_opamp3dev; + break; +#endif + +#ifdef CONFIG_STM32_OPAMP4 + case 4: + ainfo("OPAMP4 selected\n"); + dev = &g_opamp4dev; + break; +#endif + + default: + aerr("ERROR: No OPAMP interface defined\n"); + return NULL; + } + + /* Configure selected OPAMP */ + + opamp = dev->ad_priv; + + ret = stm32_opampconfig(opamp); + if (ret < 0) + { + aerr("ERROR: Failed to initialize OPAMP%d: %d\n", intf, ret); + errno = -ret; + return NULL; + } + + return dev; +} + +#endif /* CONFIG_STM32_STM32F30XX || CONFIG_STM32_STM32F33XX*/ + +#endif /* CONFIG_STM32_OPAMP1 || CONFIG_STM32_OPAMP2 || + * CONFIG_STM32_OPAMP3 || CONFIG_STM32_OPAMP4 + */ + +#endif /* CONFIG_STM32_OPAMP */ diff --git a/arch/arm/src/stm32/stm32_opamp.h b/arch/arm/src/stm32/stm32_opamp.h new file mode 100644 index 00000000000..94af6990f9c --- /dev/null +++ b/arch/arm/src/stm32/stm32_opamp.h @@ -0,0 +1,231 @@ +/************************************************************************************ + * arch/arm/src/stm32/stm32_opamp.h + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Mateusz Szafoni + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32_STM32_OPAMP_H +#define __ARCH_ARM_SRC_STM32_STM32_OPAMP_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include + +#include "chip.h" + +#ifdef CONFIG_STM32_OPAMP + +#if defined(CONFIG_STM32_STM32F30XX) +# error "OPAMP support for STM32F30XX not implemented yet" +#elif defined(CONFIG_STM32_STM32F33XX) +# include "chip/stm32f33xxx_opamp.h" +#endif + +#include + +/************************************************************************************ + * Pre-processor definitions + ************************************************************************************/ + +/* OPAMP operation mode */ + +#define OPAMP_MODE_STANDALONE 0 +#define OPAMP_MODE_FOLLOWER 1 +#define OPAMP_MODE_PGA 2 + +/* Timer controlled Mux mode */ + +#define OPAMP_MUX_DISABLE 0 +#define OPAMP_MUX_ENABLE 1 + +/* User callibration */ + +#define OPAMP_USERCAL_DISABLE 0 +#define OPAMP_USERCAL_ENABLE 1 + +/* Default configuration */ + +#define OPAMP_MODE_DEFAULT OPAMP_MODE_STANDALONE /* Standalone mode */ +#define OPAMP_MUX_DEFAULT OPAMP_MUX_DISABLE /* MUX disabled */ +#define OPAMP_USERCAL_DEFAULT OPAMP_USERCAL_DISABLE /* User calibration disabled */ +#define OPAMP_GAIN_DEFAULT OPAMP_GAIN_2 /* Gain in PGA mode = 2 */ +#define OPAMP_LOCK_DEFAULT OPAMP_LOCK_RW /* Do not lock CSR register */ + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +/* CSR register lock state */ + +enum stm32_opamp_lock_e +{ + OPAMP_LOCK_RW, + OPAMP_LOCK_RO +}; + +/* Gain in PGA mode */ + +enum stm32_opamp_gain_e +{ + OPAMP_GAIN_2, + OPAMP_GAIN_4, + OPAMP_GAIN_8, + OPAMP_GAIN_2_VM0, + OPAMP_GAIN_4_VM0, + OPAMP_GAIN_8_VM0, + OPAMP_GAIN_16_VM0, + OPAMP_GAIN_2_VM1, + OPAMP_GAIN_4_VM1, + OPAMP_GAIN_8_VM1, + OPAMP_GAIN_16_VM1 +}; + +/* Input selection and secondary input selection use the same GPIOs */ + +#ifdef CONFIG_STM32_OPAMP1 +enum stm32_opamp1_vpsel_e +{ + OPAMP1_VPSEL_PA7, + OPAMP1_VPSEL_PA5, + OPAMP1_VPSEL_PA3, + OPAMP1_VPSEL_PA1 +}; + +enum stm32_opamp1_vmsel_e +{ + OPAMP1_VMSEL_PC5, + OPAMP1_VMSEL_PA3, + OPAMP1_VMSEL_PGAMODE, + OPAMP1_VMSEL_FOLLOWER, +}; +#endif + +#ifdef CONFIG_STM32_OPAMP2 +enum stm32_opamp2_vpsel_e +{ +#ifndef CONFIG_STM32_STM32F33XX + /* TODO: STM32F303xB/C and STM32F358C devices only */ + OPAMP2_VPSEL_PD14, +#endif + OPAMP2_VPSEL_PB14, + OPAMP2_VPSEL_PB0, + OPAMP2_VPSEL_PA7 +}; + +enum stm32_opamp2_vmsel_e +{ + OPAMP2_VMSEL_PC5, + OPAMP2_VMSEL_PA5, + OPAMP2_VMSEL_PGAMODE, + OPAMP2_VMSEL_FOLLOWER +}; +#endif + +#ifdef CONFIG_STM32_OPAMP3 +enum stm32_opamp3_vpsel_e +{ + OPAMP3_VPSEL_PB13, + OPAMP3_VPSEL_PA5, + OPAMP3_VPSEL_PA1, + OPAMP3_VPSEL_PB0 +}; + +enum stm32_opamp3_vmsel_e +{ + OPAMP3_VMSEL_PB10, + OPAMP3_VMSEL_PB2, + OPAMP3_VMSEL_PGAMODE, + OPAMP3_VMSEL_FOLLOWER +}; +#endif + +#ifdef CONFIG_STM32_OPAMP4 +enum stm32_opamp4_vpsel_e +{ + OPAMP4_VPSEL_PD11, + OPAMP4_VPSEL_PB11, + OPAMP4_VPSEL_PA4, + OPAMP4_VPSEL_PB13 +}; + +enum stm32_opamp4_vmsel_e +{ + OPAMP4_VMSEL_PB10, + OPAMP4_VMSEL_PD8, + OPAMP4_VMSEL_PGAMODE, + OPAMP4_VMSEL_FOLLOWER +}; +#endif + +/************************************************************************************ + * Public Function Prototypes + ************************************************************************************/ + +#ifndef __ASSEMBLY__ +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** +* Name: stm32_opampinitialize +* +* Description: +* Initialize the OPAMP. +* +* Input Parameters: +* intf - The OPAMP interface number. +* +* Returned Value: +* Valid OPAMP device structure reference on succcess; a NULL on failure. +* +* Assumptions: +* 1. Clock to the OPAMP block has enabled, +* 2. Board-specific logic has already configured +* +****************************************************************************/ + +FAR struct opamp_dev_s* stm32_opampinitialize(int intf); + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif /* __ASSEMBLY__ */ + +#endif /* CONFIG_STM32_OPAMP */ +#endif /* __ARCH_ARM_SRC_STM32_STM32_OPAMP_H */ From 0b6190c1c48c0c9f48753ce2390b9cd91bff3a15 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sun, 30 Apr 2017 11:11:17 +0200 Subject: [PATCH 2/3] drivers/analog: Add basic OPAMP driver --- drivers/analog/Kconfig | 6 + drivers/analog/Make.defs | 17 +++ drivers/analog/opamp.c | 243 +++++++++++++++++++++++++++++++++++ include/nuttx/analog/opamp.h | 109 ++++++++++++++++ 4 files changed, 375 insertions(+) create mode 100644 drivers/analog/opamp.c create mode 100644 include/nuttx/analog/opamp.h diff --git a/drivers/analog/Kconfig b/drivers/analog/Kconfig index 6727f67c47c..64fa435f4d6 100644 --- a/drivers/analog/Kconfig +++ b/drivers/analog/Kconfig @@ -141,3 +141,9 @@ config DAC_AD5410 select SPI endif # DAC + +config OPAMP + bool "Operational Amplifier" + default n + ---help--- + Select to enable support for Operational Amplifiers (OPAMPs). diff --git a/drivers/analog/Make.defs b/drivers/analog/Make.defs index 01d5a2fe8e2..69d10a638de 100644 --- a/drivers/analog/Make.defs +++ b/drivers/analog/Make.defs @@ -60,6 +60,16 @@ CSRCS += comp.c endif +# Check for OPAMP devices + +ifeq ($(CONFIG_OPAMP),y) + +# Include the common OPAMP character driver + +CSRCS += opamp.c + +endif + # Check for ADC devices ifeq ($(CONFIG_ADC),y) @@ -105,6 +115,13 @@ ifeq ($(CONFIG_COMP),y) DEPPATH += --dep-path analog VPATH += :analog CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)analog} +else +ifeq ($(CONFIG_OPAMP),y) + DEPPATH += --dep-path analog + VPATH += :analog + CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)analog} endif endif endif +endif + diff --git a/drivers/analog/opamp.c b/drivers/analog/opamp.c new file mode 100644 index 00000000000..666b19a8ceb --- /dev/null +++ b/drivers/analog/opamp.c @@ -0,0 +1,243 @@ +/**************************************************************************** + * drivers/analog/opamp.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Mateusz Szafoni + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int opamp_open(FAR struct file *filep); +static int opamp_close(FAR struct file *filep); +static int opamp_ioctl(FAR struct file *filep, int cmd, unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations opamp_fops = +{ + opamp_open, /* open */ + opamp_close, /* close */ + NULL, /* read */ + NULL, /* write */ + NULL, /* seek */ + opamp_ioctl /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , NULL /* poll */ +#endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + , NULL /* unlink */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ +/**************************************************************************** + * Name: opamp_open + * + * Description: + * This function is called whenever the OPAMP device is opened. + * + ****************************************************************************/ + +static int opamp_open(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct opamp_dev_s *dev = inode->i_private; + uint8_t tmp; + int ret = OK; + + /* If the port is the middle of closing, wait until the close is finished */ + + if (sem_wait(&dev->ad_closesem) != OK) + { + ret = -errno; + } + else + { + /* Increment the count of references to the device. If this the first + * time that the driver has been opened for this device, then initialize + * the device. + */ + + tmp = dev->ad_ocount + 1; + if (tmp == 0) + { + /* More than 255 opens; uint8_t overflows to zero */ + + ret = -EMFILE; + } + else + { + /* Check if this is the first time that the driver has been opened. */ + + if (tmp == 1) + { + /* Yes.. perform one time hardware initialization. */ + + irqstate_t flags = enter_critical_section(); + ret = dev->ad_ops->ao_setup(dev); + if (ret == OK) + { + /* Save the new open count on success */ + + dev->ad_ocount = tmp; + } + + leave_critical_section(flags); + } + } + + sem_post(&dev->ad_closesem); + } + + return ret; +} + +/**************************************************************************** + * Name: opamp_close + * + * Description: + * This routine is called when the OPAMP device is closed. + * It waits for the last remaining data to be sent. + * + ****************************************************************************/ + +static int opamp_close(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct opamp_dev_s *dev = inode->i_private; + irqstate_t flags; + int ret = OK; + + if (sem_wait(&dev->ad_closesem) != OK) + { + ret = -errno; + } + else + { + /* Decrement the references to the driver. If the reference count will + * decrement to 0, then uninitialize the driver. + */ + + if (dev->ad_ocount > 1) + { + dev->ad_ocount--; + sem_post(&dev->ad_closesem); + } + else + { + /* There are no more references to the port */ + + dev->ad_ocount = 0; + + /* Free the IRQ and disable the OPAMP device */ + + flags = enter_critical_section(); /* Disable interrupts */ + dev->ad_ops->ao_shutdown(dev); /* Disable the OPAMP */ + leave_critical_section(flags); + + sem_post(&dev->ad_closesem); + } + } + + return ret; +} + +/**************************************************************************** + * Name: opamp_ioctl +****************************************************************************/ + +static int opamp_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct opamp_dev_s *dev = inode->i_private; + int ret; + + ret = dev->ad_ops->ao_ioctl(dev, cmd, arg); + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: opamp_register + ****************************************************************************/ + +int opamp_register(FAR const char *path, FAR struct opamp_dev_s *dev) +{ + int ret; + + /* Initialize the OPAMP device structure */ + + dev->ad_ocount = 0; + + /* Initialize semaphores */ + + sem_init(&dev->ad_closesem, 0, 1); + + /* Register the OPAMP character driver */ + + ret = register_driver(path, &opamp_fops, 0444, dev); + if (ret < 0) + { + sem_destroy(&dev->ad_closesem); + } + + return ret; +} diff --git a/include/nuttx/analog/opamp.h b/include/nuttx/analog/opamp.h new file mode 100644 index 00000000000..a0f3d55be07 --- /dev/null +++ b/include/nuttx/analog/opamp.h @@ -0,0 +1,109 @@ +/************************************************************************************ + * include/nuttx/analog/opamp.h + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Mateusz Szafoni + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ + +#ifndef __INCLUDE_NUTTX_ANALOG_OPAMP_H +#define __INCLUDE_NUTTX_ANALOG_OPAMP_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +struct opamp_dev_s; +struct opamp_ops_s +{ + /* Configure the OPAMP. This method is called the first time that the OPAMP + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching OPAMP interrupts. Interrupts + * are all disabled upon return. + */ + + CODE int (*ao_setup)(FAR struct opamp_dev_s *dev); + + /* Disable the OPAMP. This method is called when the OPAMP device is closed. + * This method reverses the operation the setup method. + * Works only if OPAMP device is not locked. + */ + + CODE void (*ao_shutdown)(FAR struct opamp_dev_s *dev); + + /* All ioctl calls will be routed through this method */ + + CODE int (*ao_ioctl)(FAR struct opamp_dev_s *dev, int cmd, unsigned long arg); +}; + +struct opamp_dev_s +{ +#ifdef CONFIG_OPAMP + /* Fields managed by common upper half OPAMP logic */ + + uint8_t ad_ocount; /* The number of times the device has been opened */ + sem_t ad_closesem; /* Locks out new opens while close is in progress */ +#endif + + /* Fields provided by lower half OPAMP logic */ + + FAR const struct opamp_ops_s *ad_ops; /* Arch-specific operations */ + FAR void *ad_priv; /* Used by the arch-specific logic */ +}; + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +#if defined(__cplusplus) +extern "C" +{ +#endif + +int opamp_register(FAR const char *path, FAR struct opamp_dev_s *dev); + +#if defined(__cplusplus) +} +#endif + +#endif /* __INCLUDE_NUTTX_ANALOG_OPAMP_H */ From c3109acb29abff1ed628c4fbbda7e36d8da92dc6 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sun, 30 Apr 2017 11:13:13 +0200 Subject: [PATCH 3/3] nucleo-f334r8: Add OPAMP support --- configs/nucleo-f334r8/include/board.h | 8 +- configs/nucleo-f334r8/src/nucleo-f334r8.h | 12 +++ configs/nucleo-f334r8/src/stm32_appinit.c | 10 +++ configs/nucleo-f334r8/src/stm32_opamp.c | 99 +++++++++++++++++++++++ 4 files changed, 128 insertions(+), 1 deletion(-) diff --git a/configs/nucleo-f334r8/include/board.h b/configs/nucleo-f334r8/include/board.h index 8d5ce807dcc..ecbb7eafefd 100644 --- a/configs/nucleo-f334r8/include/board.h +++ b/configs/nucleo-f334r8/include/board.h @@ -237,8 +237,14 @@ #define GPIO_USART1_RX GPIO_USART1_RX_1 /* PA10 */ #define GPIO_USART1_TX GPIO_USART1_TX_1 /* PA9 */ -/* HRTIM */ +/* COMP */ +/* OPAMP */ + +#define OPAMP2_VMSEL OPAMP2_VMSEL_PC5 +#define OPAMP2_VPSEL OPAMP2_VPSEL_PB14 + +/* HRTIM */ /* DMA channels *************************************************************/ /* ADC */ diff --git a/configs/nucleo-f334r8/src/nucleo-f334r8.h b/configs/nucleo-f334r8/src/nucleo-f334r8.h index 20b2dbbd5b4..6d7d41d330b 100644 --- a/configs/nucleo-f334r8/src/nucleo-f334r8.h +++ b/configs/nucleo-f334r8/src/nucleo-f334r8.h @@ -202,4 +202,16 @@ int stm32_can_setup(void); int stm32_comp_setup(void); #endif +/**************************************************************************** + * Name: stm32_opamp_setup + * + * Description: + * Initialize OPAMP peripheral for the board. + * + ****************************************************************************/ + +#ifdef CONFIG_OPAMP +int stm32_opamp_setup(void); +#endif + #endif /* __CONFIGS_NUCLEO_F334R8_SRC_NUCLEO_F334R8_H */ diff --git a/configs/nucleo-f334r8/src/stm32_appinit.c b/configs/nucleo-f334r8/src/stm32_appinit.c index 2eb43b85b08..3d1d8410924 100644 --- a/configs/nucleo-f334r8/src/stm32_appinit.c +++ b/configs/nucleo-f334r8/src/stm32_appinit.c @@ -137,6 +137,16 @@ int board_app_initialize(uintptr_t arg) } #endif +#ifdef CONFIG_OPAMP + /* Initialize OPAMP and register the OPAMP driver. */ + + ret = stm32_opamp_setup(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_opamp_setup failed: %d\n", ret); + } +#endif + UNUSED(ret); return OK; } diff --git a/configs/nucleo-f334r8/src/stm32_opamp.c b/configs/nucleo-f334r8/src/stm32_opamp.c index e69de29bb2d..42d2ce370ef 100644 --- a/configs/nucleo-f334r8/src/stm32_opamp.c +++ b/configs/nucleo-f334r8/src/stm32_opamp.c @@ -0,0 +1,99 @@ +/**************************************************************************** + * configs/nucleo-f334r8/src/stm32_opamp.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Mateusz Szafoni + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include "stm32.h" + +#if defined(CONFIG_OPAMP) && defined(CONFIG_STM32_OPAMP2) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_opamp_setup + * + * Description: + * Initialize OPAMP + * + ****************************************************************************/ + +int stm32_opamp_setup(void) +{ + static bool initialized = false; + struct opamp_dev_s* opamp = NULL; + int ret; + + if (!initialized) + { + /* Get the OPAMP interface */ + +#ifdef CONFIG_STM32_OPAMP2 + opamp = stm32_opampinitialize(2); + if (opamp == NULL) + { + aerr("ERROR: Failed to get OPAMP%d interface\n", 2); + return -ENODEV; + } +#endif + + /* Register the OPAMP character driver at /dev/opamp0 */ + + ret = opamp_register("/dev/opamp0", opamp); + if (ret < 0) + { + aerr("ERROR: opamp_register failed: %d\n", ret); + return ret; + } + + initialized = true; + } + + return OK; +} + +#endif /* CONFIG_OPAMP && CONFIG_STM32_OPAMP2 */