aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple
diff options
context:
space:
mode:
Diffstat (limited to 'libmaple')
-rw-r--r--libmaple/dac.c89
-rw-r--r--libmaple/dac.h121
2 files changed, 141 insertions, 69 deletions
diff --git a/libmaple/dac.c b/libmaple/dac.c
index 63a96ac..54b555b 100644
--- a/libmaple/dac.c
+++ b/libmaple/dac.c
@@ -23,7 +23,6 @@
*****************************************************************************/
#include "libmaple.h"
-#include "rcc.h"
#include "gpio.h"
#include "dac.h"
@@ -31,35 +30,81 @@
* @brief DAC peripheral routines.
*/
-/* This numbering follows the registers (1-indexed) */
-#define DAC_CH1 1
-#define DAC_CH2 2
+dac_dev dac = {
+ .regs = DAC_BASE,
+};
+const dac_dev *DAC = &dac;
-DAC_Map *dac = (DAC_Map*)(DAC_BASE);
-
-/* Sets up the DAC peripheral */
-void dac_init(void) {
+/**
+ * @brief Initialize the digital to analog converter
+ * @param flags Flags:
+ * DAC_CH1: Enable channel 1
+ * DAC_CH2: Enable channel 2
+ * @sideeffect May set PA4 or PA5 to INPUT_ANALOG
+ */
+void dac_init(uint32 flags) {
/* First turn on the clock */
rcc_clk_enable(RCC_DAC);
+ rcc_reset_dev(RCC_DAC);
- /* Then setup ANALOG mode on PA4 and PA5 */
- gpio_set_mode(GPIOA_BASE, 4, CNF_INPUT_ANALOG);
- gpio_set_mode(GPIOA_BASE, 5, CNF_INPUT_ANALOG);
+ if (flags & DAC_CH1) {
+ dac_enable_channel(1);
+ }
- /* Then do register stuff. Default does no triggering, and
- * buffered output, so all good. */
- dac->CR = DAC_CR_EN1 | DAC_CR_EN2;
+ if (flags & DAC_CH2) {
+ dac_enable_channel(2);
+ }
}
-void dac_write(uint8 chan, uint16 val) {
- switch(chan) {
- case DAC_CH1:
- dac->DHR12R1 = 0x0FFF & val;
+/**
+ * @brief Write a 12-bit value to the DAC to output
+ * @param channel channel to select (1 or 2)
+ * @param val value to write
+ */
+void dac_write_channel(uint8 channel, uint16 val) {
+ switch(channel) {
+ case 1:
+ DAC->regs->DHR12R1 = DAC_DHR12R1_DACC1DHR & val;
+ break;
+ case 2:
+ DAC->regs->DHR12R2 = DAC_DHR12R2_DACC2DHR & val;
+ break;
+ }
+}
+
+/**
+ * @brief Enable a DAC channel
+ * @param channel channel to enable, either 1 or 2
+ * @sideeffect May change pin mode of PA4 or PA5
+ */
+void dac_enable_channel(uint8 channel) {
+ /*
+ * Setup ANALOG mode on PA4 and PA5. This mapping is consistent across
+ * all STM32 chips with a DAC. See RM008 12.2.
+ */
+ switch (channel) {
+ case 1:
+ gpio_set_mode(GPIOA_BASE, 4, GPIO_MODE_INPUT_ANALOG);
+ DAC->regs->CR |= DAC_CR_EN1;
+ break;
+ case 2:
+ gpio_set_mode(GPIOA_BASE, 5, GPIO_MODE_INPUT_ANALOG);
+ DAC->regs->CR |= DAC_CR_EN2;
+ break;
+ }
+}
+
+/**
+ * @brief Disable a DAC channel
+ * @param channel channel to disable, either 1 or 2
+ */
+void dac_disable_channel(uint8 channel) {
+ switch (channel) {
+ case 1:
+ DAC->regs->CR &= ~DAC_CR_EN1;
break;
- case DAC_CH2:
- dac->DHR12R2 = 0x0FFF & val;
+ case 2:
+ DAC->regs->CR &= ~DAC_CR_EN2;
break;
- default:
- ASSERT(0); // can't happen
}
}
diff --git a/libmaple/dac.h b/libmaple/dac.h
index 340a49a..3148809 100644
--- a/libmaple/dac.h
+++ b/libmaple/dac.h
@@ -22,88 +22,115 @@
* THE SOFTWARE.
*****************************************************************************/
-/*
- * See ../notes/dac.txt for more info
- */
-
/**
* @file dac.h
+ * @brief Digital to analog converter header file
+ * See notes/dac.txt for more info
*/
#ifndef _DAC_H_
#define _DAC_H_
+#include "rcc.h"
+
#ifdef __cplusplus
extern "C"{
#endif
-#define DAC_BASE 0x40007400
-
-typedef struct {
- volatile uint32 CR;
- volatile uint32 SWTRIGR;
- volatile uint32 DHR12R1;
- volatile uint32 DHR12L1;
- volatile uint32 DHR8R1;
- volatile uint32 DHR12R2;
- volatile uint32 DHR12L2;
- volatile uint32 DHR8R2;
- volatile uint32 DHR12RD;
- volatile uint32 DHR12LD;
- volatile uint32 DHR8RD;
- volatile uint32 DOR1;
- volatile uint32 DOR2;
-} DAC_Map;
-
-/* There's only one DAC, so expose it. */
-extern DAC_Map *dac;
-
-// And here are the register bit ranges
-#define DAC_CR_EN1 BIT(0)
-#define DAC_CR_BOFF1 BIT(1)
-#define DAC_CR_TEN1 BIT(2)
-#define DAC_CR_TSEL1 (BIT(3) | BIT(4) | BIT(5))
-#define DAC_CR_WAVE1 (BIT(6) | BIT(7))
-#define DAC_CR_MAMP1 (BIT(8) | BIT(9) | BIT(10) | BIT(11))
-#define DAC_CR_DMAEN1 BIT(12)
-#define DAC_CR_EN2 BIT(16)
-#define DAC_CR_BOFF2 BIT(17)
-#define DAC_CR_TEN2 BIT(18)
-#define DAC_CR_TSEL2 (BIT(19) | BIT(20) | BIT(21))
-#define DAC_CR_WAVE2 (BIT(22) | BIT(23))
-#define DAC_CR_MAMP2 (BIT(24) | BIT(25) | BIT(26) | BIT(27))
-#define DAC_CR_DMAEN2 BIT(28)
-
-#define DAC_SWTRIGR_SWTRIG1 BIT(0)
-#define DAC_SWTRIGR_SWTRIG2 BIT(1)
+typedef struct dac_reg_map {
+ __io uint32 CR; ///< Control register
+ __io uint32 SWTRIGR; ///< Software trigger register
+ __io uint32 DHR12R1; ///< Channel 1 12-bit right aligned data holding register
+ __io uint32 DHR12L1; ///< Channel 1 12-bit left aligned data holding register
+ __io uint32 DHR8R1; ///< Channel 1 8-bit left aligned data holding register
+ __io uint32 DHR12R2; ///< Channel 2 12-bit right aligned data holding register
+ __io uint32 DHR12L2; ///< Channel 2 12-bit left aligned data holding register
+ __io uint32 DHR8R2; ///< Channel 2 8-bit left aligned data holding register
+ __io uint32 DHR12RD; ///< Dual DAC 12-bit right aligned data holding register
+ __io uint32 DHR12LD; ///< Dual DAC 12-bit left aligned data holding register
+ __io uint32 DHR8RD; ///< Dual DAC 8-bit left aligned data holding register
+ __io uint32 DOR1; ///< Channel 1 data output register
+ __io uint32 DOR2; ///< Channel 2 data output register
+} dac_reg_map;
+
+typedef struct dac_dev {
+ dac_reg_map *regs;
+} dac_dev;
+
+extern const dac_dev *DAC;
+/*
+ * DAC peripheral base address
+ */
+#define DAC_BASE ((dac_reg_map*)0x40007400)
+
+/*
+ * Register bit definitions and masks
+ */
+
+/* Control register */
+#define DAC_CR_EN1 BIT(0) // Channel 1 enable
+#define DAC_CR_BOFF1 BIT(1) // Channel 1 output buffer disable
+#define DAC_CR_TEN1 BIT(2) // Channel 1 trigger enable
+#define DAC_CR_TSEL1 (0x7 << 3) // Channel 1 trigger selection
+#define DAC_CR_WAVE1 (0x3 << 6) // Channel 1 noise/triangle wave generationg enable
+#define DAC_CR_MAMP1 (0xF << 8) // Channel 1 mask/amplitude selector
+#define DAC_CR_DMAEN1 BIT(12) // Channel 1 DMA enable
+#define DAC_CR_EN2 BIT(16) // Channel 2 enable
+#define DAC_CR_BOFF2 BIT(17) // Channel 2 output buffer disable
+#define DAC_CR_TEN2 BIT(18) // Channel 2 trigger enable
+#define DAC_CR_TSEL2 (0x7 << 19) // Channel 2 trigger selection
+#define DAC_CR_WAVE2 (0x3 << 22) // Channel 2 noise/triangle wave generationg enable
+#define DAC_CR_MAMP2 (0xF << 24) // Channel 2 mask/amplitude selector
+#define DAC_CR_DMAEN2 BIT(28) // Channel 2 DMA enable
+
+/* Software trigger register */
+#define DAC_SWTRIGR_SWTRIG1 BIT(0) // Channel 1 software trigger
+#define DAC_SWTRIGR_SWTRIG2 BIT(1) // Channel 2 software trigger
+
+/* Channel 1 12-bit right aligned data holding register */
#define DAC_DHR12R1_DACC1DHR 0x00000FFF
+/* Channel 1 12-bit left aligned data holding register */
#define DAC_DHR12L1_DACC1DHR 0x0000FFF0
+/* Channel 1 8-bit left aligned data holding register */
#define DAC_DHR8R1_DACC1DHR 0x000000FF
+/* Channel 2 12-bit right aligned data holding register */
#define DAC_DHR12R2_DACC2DHR 0x00000FFF
+/* Channel 2 12-bit left aligned data holding register */
#define DAC_DHR12L2_DACC2DHR 0x0000FFF0
+/* Channel 2 8-bit left aligned data holding register */
#define DAC_DHR8R2_DACC2DHR 0x000000FF
+/* Dual DAC 12-bit right aligned data holding register */
#define DAC_DHR12RD_DACC1DHR 0x00000FFF
#define DAC_DHR12RD_DACC2DHR 0x0FFF0000
+/* Dual DAC 12-bit left aligned data holding register */
#define DAC_DHR12LD_DACC1DHR 0x0000FFF0
#define DAC_DHR12LD_DACC2DHR 0xFFF00000
+/* Dual DAC 8-bit left aligned data holding register */
#define DAC_DHR8RD_DACC1DHR 0x000000FF
#define DAC_DHR8RD_DACC2DHR 0x0000FF00
-#define DAC_DOR1 0x00000FFF
+/* Channel 1 data output register */
+#define DAC_DOR1_DACC1DOR 0x00000FFF
+
+/* Channel 1 data output register */
+#define DAC_DOR2_DACC2DOR 0x00000FFF
-#define DAC_DOR2 0x00000FFF
+#define DAC_CH1 0x1
+#define DAC_CH2 0x2
+void dac_init(uint32 flags);
-void dac_init(void);
-void dac_write(uint8 chan, uint16 val);
+void dac_write_channel(uint8 channel, uint16 val);
+void dac_enable_channel(uint8 channel);
+void dac_disable_channel(uint8 channel);
#ifdef __cplusplus
} // extern "C"