You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/12/15 13:03:07 UTC
[incubator-nuttx] branch master updated: drivers/analog: add mcp48xx dac support
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 6c255f2 drivers/analog: add mcp48xx dac support
6c255f2 is described below
commit 6c255f2d075d23e70ed41bc78b701cec2ae4d8b5
Author: Petro Karashchenko <pe...@gmail.com>
AuthorDate: Tue Dec 14 14:47:11 2021 +0200
drivers/analog: add mcp48xx dac support
Signed-off-by: Petro Karashchenko <pe...@gmail.com>
---
drivers/analog/Kconfig | 28 ++++
drivers/analog/Make.defs | 4 +
drivers/analog/mcp48xx.c | 362 +++++++++++++++++++++++++++++++++++++++++
include/nuttx/analog/dac.h | 22 ++-
include/nuttx/analog/ioctl.h | 5 +
include/nuttx/analog/mcp48xx.h | 73 +++++++++
6 files changed, 492 insertions(+), 2 deletions(-)
diff --git a/drivers/analog/Kconfig b/drivers/analog/Kconfig
index c33dd53..6294f15 100644
--- a/drivers/analog/Kconfig
+++ b/drivers/analog/Kconfig
@@ -228,6 +228,34 @@ config DAC7554
---help---
Enable driver support for the Texas Instruments DAC7554 dac.
+config MCP48XX
+ bool "MCP4802/4812/4822 support"
+ default n
+ select SPI
+ ---help---
+ Enable driver support for the Microchip MCP4802/4812/4822 dac.
+
+choice
+ prompt "MCP48XX variant"
+ default MCP4802
+ depends on MCP48XX
+
+config MCP4802
+ bool "MCP4802 (8-bit) dac"
+
+config MCP4812
+ bool "MCP4812 (10-bit) dac"
+
+config MCP4822
+ bool "MCP4822 (12-bit) dac"
+
+endchoice # MCP48XX variant
+
+config MCP48XX_SPI_FREQUENCY
+ int "MCP48XX SPI frequency"
+ default 4000000
+ depends on MCP48XX
+
endif # DAC
config OPAMP
diff --git a/drivers/analog/Make.defs b/drivers/analog/Make.defs
index 50473cd..b54613d 100644
--- a/drivers/analog/Make.defs
+++ b/drivers/analog/Make.defs
@@ -42,6 +42,10 @@ ifeq ($(CONFIG_DAC7554),y)
CSRCS += dac7554.c
endif
+ifeq ($(CONFIG_MCP48XX),y)
+ CSRCS += mcp48xx.c
+endif
+
endif
# Check for COMP devices
diff --git a/drivers/analog/mcp48xx.c b/drivers/analog/mcp48xx.c
new file mode 100644
index 0000000..63ea0b2
--- /dev/null
+++ b/drivers/analog/mcp48xx.c
@@ -0,0 +1,362 @@
+/****************************************************************************
+ * drivers/analog/mcp48xx.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/arch.h>
+#include <nuttx/analog/dac.h>
+#include <nuttx/spi/spi.h>
+
+#include <nuttx/analog/mcp48xx.h>
+
+/****************************************************************************
+ * Preprocessor definitions
+ ****************************************************************************/
+
+#if !defined(CONFIG_SPI)
+# error SPI Support Required.
+#endif
+
+#if defined(CONFIG_MCP48XX)
+
+#if defined(CONFIG_MCP4802)
+# define MCP48XX_DATA_BITS 8u
+#elif defined(CONFIG_MCP4812)
+# define MCP48XX_DATA_BITS 10u
+#elif defined(CONFIG_MCP4822)
+# define MCP48XX_DATA_BITS 12u
+#else
+# error MCP48XX variant selection required
+#endif
+
+#ifndef CONFIG_MCP48XX_SPI_FREQUENCY
+# define CONFIG_MCP48XX_SPI_FREQUENCY 4000000
+#endif
+
+#define MCP48XX_SPI_MODE (SPIDEV_MODE0) /* SPI Mode 0: CPOL=0 CPHA=0 */
+
+#define MCP48XX_MAX_CHANNELS 2u
+
+#define MCP48XX_SHDN (1u << 12) /* Output Shutdown Control bit */
+#define MCP48XX_GA (1u << 13) /* Output Gain Selection bit */
+
+#define MCP48XX_MAX_BITS 12u
+
+#define MCP48XX_DATA_MASK ((1u << MCP48XX_DATA_BITS) - 1u)
+#define MCP48XX_DATA_SHIFT (MCP48XX_MAX_BITS - MCP48XX_DATA_BITS)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct mcp48xx_dev_s
+{
+ FAR struct spi_dev_s *spi; /* SPI interface */
+ uint32_t spidev; /* SPI Chip Select number */
+ uint16_t cmd[MCP48XX_MAX_CHANNELS]; /* Output Gain Selection and Output
+ * Shutdown Control bits */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* DAC methods */
+
+static void mcp48xx_reset(FAR struct dac_dev_s *dev);
+static int mcp48xx_setup(FAR struct dac_dev_s *dev);
+static void mcp48xx_shutdown(FAR struct dac_dev_s *dev);
+static void mcp48xx_txint(FAR struct dac_dev_s *dev, bool enable);
+static int mcp48xx_send(FAR struct dac_dev_s *dev,
+ FAR struct dac_msg_s *msg);
+static int mcp48xx_ioctl(FAR struct dac_dev_s *dev, int cmd,
+ unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct mcp48xx_dev_s g_devpriv;
+
+static const struct dac_ops_s g_dacops =
+{
+ .ao_reset = mcp48xx_reset,
+ .ao_setup = mcp48xx_setup,
+ .ao_shutdown = mcp48xx_shutdown,
+ .ao_txint = mcp48xx_txint,
+ .ao_send = mcp48xx_send,
+ .ao_ioctl = mcp48xx_ioctl,
+};
+
+static struct dac_dev_s g_dacdev =
+{
+ .ad_ops = &g_dacops,
+ .ad_priv = &g_devpriv,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mcp48xx_configspi
+ *
+ * Description:
+ * Configure the SPI interface
+ *
+ ****************************************************************************/
+
+static inline void mcp48xx_configspi(FAR struct spi_dev_s *spi)
+{
+ SPI_SETMODE(spi, MCP48XX_SPI_MODE);
+ SPI_SETBITS(spi, 8);
+ SPI_HWFEATURES(spi, 0);
+ SPI_SETFREQUENCY(spi, CONFIG_MCP48XX_SPI_FREQUENCY);
+}
+
+/****************************************************************************
+ * Name: mcp48xx_reset
+ *
+ * Description:
+ * Reset the DAC device. Called early to initialize the hardware. This
+ * is called, before ao_setup() and on error conditions.
+ *
+ ****************************************************************************/
+
+static void mcp48xx_reset(FAR struct dac_dev_s *dev)
+{
+}
+
+/****************************************************************************
+ * Name: mcp48xx_setup
+ *
+ * Description:
+ * Configure the DAC. This method is called the first time that the DAC
+ * device is opened. This will occur when the port is first opened. This
+ * setup includes configuring and attaching DAC interrupts. Interrupts are
+ * all disabled upon return.
+ *
+ ****************************************************************************/
+
+static int mcp48xx_setup(FAR struct dac_dev_s *dev)
+{
+ return OK;
+}
+
+/****************************************************************************
+ * Name: mcp48xx_shutdown
+ *
+ * Description:
+ * Disable the DAC. This method is called when the DAC device is closed.
+ * This method reverses the operation the setup method.
+ *
+ ****************************************************************************/
+
+static void mcp48xx_shutdown(FAR struct dac_dev_s *dev)
+{
+}
+
+/****************************************************************************
+ * Name: mcp48xx_txint
+ *
+ * Description:
+ * Call to enable or disable TX interrupts
+ *
+ ****************************************************************************/
+
+static void mcp48xx_txint(FAR struct dac_dev_s *dev, bool enable)
+{
+}
+
+/****************************************************************************
+ * Name: mcp48xx_send
+ ****************************************************************************/
+
+static int mcp48xx_send(FAR struct dac_dev_s *dev, FAR struct dac_msg_s *msg)
+{
+ FAR struct mcp48xx_dev_s *priv = (FAR struct mcp48xx_dev_s *)dev->ad_priv;
+ uint16_t data;
+
+ /* Sanity check */
+
+ DEBUGASSERT(priv->spi != NULL);
+
+ /* Set up message to send */
+
+ ainfo("value: %08"PRIx32"\n", msg->am_data);
+
+ SPI_LOCK(priv->spi, true);
+
+ mcp48xx_configspi(priv->spi);
+
+ data = ((msg->am_data & MCP48XX_DATA_MASK) << MCP48XX_DATA_SHIFT)
+ | ((msg->am_channel & 0x01) << 15)
+ | priv->cmd[msg->am_channel & 0x01];
+
+ SPI_SELECT(priv->spi, priv->spidev, true);
+
+ SPI_SEND(priv->spi, (data >> 8));
+ SPI_SEND(priv->spi, (data & 0xff));
+
+ SPI_SELECT(priv->spi, priv->spidev, false);
+
+ SPI_LOCK(priv->spi, false);
+
+ dac_txdone(dev);
+ return 0;
+}
+
+/****************************************************************************
+ * Name: mcp48xx_ioctl
+ ****************************************************************************/
+
+static int mcp48xx_ioctl(FAR struct dac_dev_s *dev, int cmd,
+ unsigned long arg)
+{
+ FAR struct mcp48xx_dev_s *priv = (FAR struct mcp48xx_dev_s *)dev->ad_priv;
+ int ret = OK;
+
+ switch (cmd)
+ {
+ case ANIOC_MCP48XX_DAC_SET_GAIN:
+ {
+ int i;
+
+ if ((arg & MCP48XX_GAIN_1X) != 0)
+ {
+ for (i = 0; i < MCP48XX_MAX_CHANNELS; i++)
+ {
+ if ((arg & (1u << i)) != 0)
+ {
+ priv->cmd[i] |= MCP48XX_GA;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < MCP48XX_MAX_CHANNELS; i++)
+ {
+ if ((arg & (1u << i)) != 0)
+ {
+ priv->cmd[i] &= ~MCP48XX_GA;
+ }
+ }
+ }
+ }
+ break;
+
+ case ANIOC_MCP48XX_DAC_ENABLE:
+ {
+ int i;
+
+ for (i = 0; i < MCP48XX_MAX_CHANNELS; i++)
+ {
+ if ((arg & (1u << i)) != 0)
+ {
+ priv->cmd[i] |= MCP48XX_SHDN;
+ }
+ }
+ }
+ break;
+
+ case ANIOC_MCP48XX_DAC_DISABLE:
+ {
+ int i;
+
+ for (i = 0; i < MCP48XX_MAX_CHANNELS; i++)
+ {
+ if ((arg & (1u << i)) != 0)
+ {
+ priv->cmd[i] &= ~MCP48XX_SHDN;
+ }
+ }
+ }
+ break;
+
+ /* Command was not recognized */
+
+ default:
+ aerr("MCP48XX ERROR: Unrecognized cmd: %d\n", cmd);
+ ret = -ENOTTY;
+ break;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mcp48xx_initialize
+ *
+ * Description:
+ * Initialize DAC
+ *
+ * Input Parameters:
+ * spi - SPI driver instance
+ * spidev - SPI Chip Select number
+ *
+ * Returned Value:
+ * Valid MCP48XX device structure reference on success; a NULL on failure
+ *
+ ****************************************************************************/
+
+FAR struct dac_dev_s *mcp48xx_initialize(FAR struct spi_dev_s *spi,
+ uint32_t spidev)
+{
+ FAR struct mcp48xx_dev_s *priv;
+ int i;
+
+ /* Sanity check */
+
+ DEBUGASSERT(spi != NULL);
+
+ /* Initialize the MCP48XX device structure */
+
+ priv = (FAR struct mcp48xx_dev_s *)g_dacdev.ad_priv;
+ priv->spi = spi;
+ priv->spidev = spidev;
+
+ /* Enable both channels with 1x gain by default */
+
+ for (i = 0; i < MCP48XX_MAX_CHANNELS; i++)
+ {
+ priv->cmd[i] = MCP48XX_SHDN | MCP48XX_GA;
+ }
+
+ return &g_dacdev;
+}
+
+#endif /* CONFIG_MCP48XX */
diff --git a/include/nuttx/analog/dac.h b/include/nuttx/analog/dac.h
index 08af76d..f6b8e61 100644
--- a/include/nuttx/analog/dac.h
+++ b/include/nuttx/analog/dac.h
@@ -180,7 +180,7 @@ extern "C"
*
* Input Parameters:
* path - The full path to the DAC device to be registered. This could
- * be, as an example, "/dev/dac0"
+ * be, as an example, "/dev/dac0"
* dev - An instance of the device-specific DAC interface
*
* Returned Value:
@@ -241,7 +241,25 @@ FAR struct dac_dev_s *dac7554_initialize(FAR struct spi_dev_s *spi,
****************************************************************************/
FAR struct dac_dev_s *lmp92001_dac_initialize(FAR struct i2c_master_s *i2c,
- uint8_t addr);
+ uint8_t addr);
+
+/****************************************************************************
+ * Name: mcp48xx_initialize
+ *
+ * Description:
+ * Initialize DAC
+ *
+ * Input Parameters:
+ * spi - SPI driver instance
+ * spidev - SPI Chip Select number
+ *
+ * Returned Value:
+ * Valid MCP48XX device structure reference on success; a NULL on failure
+ *
+ ****************************************************************************/
+
+FAR struct dac_dev_s *mcp48xx_initialize(FAR struct spi_dev_s *spi,
+ uint32_t spidev);
#if defined(__cplusplus)
}
diff --git a/include/nuttx/analog/ioctl.h b/include/nuttx/analog/ioctl.h
index 6859af9..5656f1c 100644
--- a/include/nuttx/analog/ioctl.h
+++ b/include/nuttx/analog/ioctl.h
@@ -99,6 +99,11 @@
#define AN_MAX1161X_FIRST (AN_STM32L4_FIRST + AN_STM32L4_NCMDS)
#define AN_MAX1161X_NCMDS 8
+/* See include/nuttx/analog/mcp48xx.h */
+
+#define AN_MCP48XX_FIRST (AN_MAX1161X_FIRST + AN_MAX1161X_NCMDS)
+#define AN_MCP48XX_NCMDS 3
+
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
diff --git a/include/nuttx/analog/mcp48xx.h b/include/nuttx/analog/mcp48xx.h
new file mode 100644
index 0000000..01fa912
--- /dev/null
+++ b/include/nuttx/analog/mcp48xx.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+ * include/nuttx/analog/mcp48xx.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_ANALOG_MCP48XX_H
+#define __INCLUDE_NUTTX_ANALOG_MCP48XX_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/analog/ioctl.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* IOCTL Commands ***********************************************************/
+
+/* Cmd: ANIOC_MCP48XX_DAC_SET_GAIN Arg: mcp48xx_set_gain_e value
+ * Cmd: ANIOC_MCP48XX_DAC_ENABLE Arg: mcp48xx_dac_channel_e channel
+ * Cmd: ANIOC_MCP48XX_DAC_DISABLE Arg: mcp48xx_dac_channel_e channel
+ */
+
+#define ANIOC_MCP48XX_DAC_SET_GAIN _ANIOC(AN_MCP48XX_FIRST + 0)
+#define ANIOC_MCP48XX_DAC_ENABLE _ANIOC(AN_MCP48XX_FIRST + 1)
+#define ANIOC_MCP48XX_DAC_DISABLE _ANIOC(AN_MCP48XX_FIRST + 2)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+enum mcp48xx_gain_select_e
+{
+ MCP48XX_GAIN_2X = 0 << 8U, /* VOUT = 2 * VREF * D/4096 */
+ MCP48XX_GAIN_1X = 1 << 8U /* VOUT = VREF * D/4096 */
+};
+
+enum mcp48xx_dac_channel_e
+{
+ MCP48XX_DAC_CHA = 1 << 0U, /* Select channel A */
+ MCP48XX_DAC_CHB = 1 << 1U, /* Select channel B */
+ MCP48XX_DAC_ALL = 0x3u /* Select both channels A and B */
+};
+
+enum mcp48xx_set_gain_e
+{
+ MCP48XX_DAC_CHA_GAIN_2X = MCP48XX_DAC_CHA | MCP48XX_GAIN_2X,
+ MCP48XX_DAC_CHB_GAIN_2X = MCP48XX_DAC_CHB | MCP48XX_GAIN_2X,
+ MCP48XX_DAC_CHA_GAIN_1X = MCP48XX_DAC_CHA | MCP48XX_GAIN_1X,
+ MCP48XX_DAC_CHB_GAIN_1X = MCP48XX_DAC_CHB | MCP48XX_GAIN_1X,
+ MCP48XX_DAC_ALL_GAIN_2X = MCP48XX_DAC_ALL | MCP48XX_GAIN_2X,
+ MCP48XX_DAC_ALL_GAIN_1X = MCP48XX_DAC_ALL | MCP48XX_GAIN_1X
+};
+
+#endif /* __INCLUDE_NUTTX_ANALOG_MCP48XX_H */