From 663be1b8109551ad5cf2a6cb482469bd535f825c Mon Sep 17 00:00:00 2001
From: Hauke Petersen <hauke.petersen@fu-berlin.de>
Date: Mon, 26 Jun 2017 22:18:45 +0200
Subject: [PATCH] cpu/sam3: added DAC (DACC) driver implementation

---
 boards/arduino-due/Makefile.features |  1 +
 cpu/sam3/include/periph_cpu.h        | 13 +++++
 cpu/sam3/periph/dac.c                | 79 ++++++++++++++++++++++++++++
 3 files changed, 93 insertions(+)
 create mode 100644 cpu/sam3/periph/dac.c

diff --git a/boards/arduino-due/Makefile.features b/boards/arduino-due/Makefile.features
index 6e911845de..336368630c 100644
--- a/boards/arduino-due/Makefile.features
+++ b/boards/arduino-due/Makefile.features
@@ -1,6 +1,7 @@
 # Put defined MCU peripherals here (in alphabetical order)
 FEATURES_PROVIDED += periph_adc
 FEATURES_PROVIDED += periph_cpuid
+FEATURES_PROVIDED += periph_dac
 FEATURES_PROVIDED += periph_gpio
 FEATURES_PROVIDED += periph_hwrng
 FEATURES_PROVIDED += periph_pwm
diff --git a/cpu/sam3/include/periph_cpu.h b/cpu/sam3/include/periph_cpu.h
index 117e772d38..f8553ac08f 100644
--- a/cpu/sam3/include/periph_cpu.h
+++ b/cpu/sam3/include/periph_cpu.h
@@ -89,6 +89,19 @@ typedef uint32_t gpio_t;
  */
 #define ADC_NUMOF           (16U)
 
+/**
+ * @brief   DAC configuration, valid for all boards using this CPU
+ *
+ * The sam3 has a fixed mapping of DAC pins and a fixed number of DAC channels,
+ * so this DAC configuration is valid for all boards using this CPU. No need for
+ * any board specific configuration.
+ *
+ * The sam3's DAC channels are mapped to the following fixed pins:
+ * - line 0 (ch0): PB15
+ * - line 1 (ch1): PB16
+ */
+#define DAC_NUMOF           (2U)
+
 #ifndef DOXYGEN
 /**
  * @brief   Override GPIO modes
diff --git a/cpu/sam3/periph/dac.c b/cpu/sam3/periph/dac.c
new file mode 100644
index 0000000000..98074a4e99
--- /dev/null
+++ b/cpu/sam3/periph/dac.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     cpu_sam3
+ * @{
+ *
+ * @file
+ * @brief       Low-level DAC driver implementation
+ *
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ *
+ * @}
+ */
+
+#include "cpu.h"
+#include "assert.h"
+#include "periph/dac.h"
+
+#define WP_KEY              (0x444143)
+#define PMC_BIT             (1 << (ID_DACC - 32))
+
+#ifndef DAC_STARTUP
+#define DAC_STARTUP         (DACC_MR_STARTUP_1984)
+#endif
+#ifndef DAC_REFRESH
+#define DAC_REFRESH         (DACC_MR_REFRESH(128))
+#endif
+
+int8_t dac_init(dac_t line)
+{
+    assert(line < DAC_NUMOF);
+
+    /* power on DACC peripheral */
+    PMC->PMC_PCER1 = PMC_BIT;
+
+    /* unlock DACC registers */
+    DACC->DACC_WPMR = DACC_WPMR_WPKEY(WP_KEY);
+    /* configure mode register */
+    DACC->DACC_MR = (DAC_STARTUP | DACC_MR_TAG_EN | DAC_REFRESH);
+    /* enable the selected channel/line */
+    DACC->DACC_CHER = (1 << line);
+    /* set line initially to 0 volts -> this will startup the channel and the
+     * channel is ready after the defined number of startup cycles
+     * (DAC_STARTUP) have passed */
+    dac_set(line, 0);
+
+    return 0;
+}
+
+void dac_set(dac_t line, uint16_t value)
+{
+    assert(line < DAC_NUMOF);
+
+    DACC->DACC_CDR = ((value >> 4) | (line << 12));
+}
+
+void dac_poweron(dac_t line)
+{
+    assert(line < DAC_NUMOF);
+
+    PMC->PMC_PCER1 = (1 << (ID_DACC - 32));
+    DACC->DACC_CHER = PMC_BIT;
+}
+
+void dac_poweroff(dac_t line)
+{
+    assert(line < DAC_NUMOF);
+
+    DACC->DACC_CHDR = (1 << line);
+    if (!(DACC->DACC_CHSR)) {
+        PMC->PMC_PCDR1 = PMC_BIT;
+    }
+}
-- 
GitLab