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 */