aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple/stm32f1/dma.c
diff options
context:
space:
mode:
authorMarti Bolivar <mbolivar@leaflabs.com>2012-06-13 12:52:16 -0400
committerMarti Bolivar <mbolivar@leaflabs.com>2012-06-15 17:41:37 -0400
commit0da5a577296ff3388feddb12bc86c43b61f54066 (patch)
tree5c28e100d1645b2998be27e74a831b1be318a682 /libmaple/stm32f1/dma.c
parente51c60e03661cc924420eba757e15044016b7c1f (diff)
downloadlibrambutan-0da5a577296ff3388feddb12bc86c43b61f54066.tar.gz
librambutan-0da5a577296ff3388feddb12bc86c43b61f54066.zip
Implement DMA tube API on STM32F1.
Signed-off-by: Marti Bolivar <mbolivar@leaflabs.com>
Diffstat (limited to 'libmaple/stm32f1/dma.c')
-rw-r--r--libmaple/stm32f1/dma.c62
1 files changed, 58 insertions, 4 deletions
diff --git a/libmaple/stm32f1/dma.c b/libmaple/stm32f1/dma.c
index fc502a1..5364a04 100644
--- a/libmaple/stm32f1/dma.c
+++ b/libmaple/stm32f1/dma.c
@@ -121,14 +121,57 @@ static int preconfig_check(dma_dev *dev, dma_channel channel,
return DMA_TUBE_CFG_SUCCESS;
}
+static inline void set_ccr(dma_tube_reg_map *chregs,
+ dma_xfer_size msize, int minc,
+ dma_xfer_size psize, int pinc,
+ uint32 other_flags) {
+ chregs->CCR = ((msize << 10) | (psize << 8) |
+ (minc ? DMA_CCR_MINC : 0) | (pinc ? DMA_CCR_PINC : 0) |
+ other_flags);
+}
+
+static inline uint32 cfg_ccr_flags(unsigned tube_flags) {
+ /* DMA_CFG_SRC_INC and DMA_CFG_DST_INC are special */
+ return tube_flags & ~(DMA_CFG_SRC_INC | DMA_CFG_DST_INC);
+}
+
/* Configure chregs according to cfg, where cfg->tube_dst is peripheral. */
static int config_to_per(dma_tube_reg_map *chregs, dma_tube_config *cfg) {
- return -DMA_TUBE_CFG_ECFG; /* FIXME implement */
+ /* Check that ->tube_src is memory (if it's anything else, we
+ * shouldn't have been called). */
+ ASSERT(_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM);
+
+ set_ccr(chregs,
+ cfg->tube_src_size, cfg->tube_flags & DMA_CFG_SRC_INC,
+ cfg->tube_dst_size, cfg->tube_flags & DMA_CFG_DST_INC,
+ (cfg_ccr_flags(cfg->tube_flags) | DMA_CCR_DIR_FROM_MEM));
+ chregs->CMAR = (uint32)cfg->tube_src;
+ chregs->CPAR = (uint32)cfg->tube_dst;
+ return DMA_TUBE_CFG_SUCCESS;
}
/* Configure chregs according to cfg, where cfg->tube_dst is memory. */
static int config_to_mem(dma_tube_reg_map *chregs, dma_tube_config *cfg) {
- return -DMA_TUBE_CFG_ECFG; /* FIXME implement */
+ uint32 mem2mem;
+
+ if ((_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM) &&
+ (cfg->tube_flags & DMA_CFG_CIRC)) {
+ /* Can't do mem-to-mem and circular mode */
+ return -DMA_TUBE_CFG_ECFG;
+ }
+
+ mem2mem = (_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM ?
+ DMA_CCR_MEM2MEM : 0);
+ set_ccr(chregs,
+ cfg->tube_dst_size, cfg->tube_flags & DMA_CFG_DST_INC,
+ cfg->tube_src_size, cfg->tube_flags & DMA_CFG_SRC_INC,
+ (cfg_ccr_flags(cfg->tube_flags) |
+ DMA_CCR_DIR_FROM_PER |
+ mem2mem));
+ chregs->CNDTR = cfg->tube_nr_xfers;
+ chregs->CMAR = (uint32)cfg->tube_dst;
+ chregs->CPAR = (uint32)cfg->tube_src;
+ return DMA_TUBE_CFG_SUCCESS;
}
/*
@@ -143,17 +186,28 @@ int dma_tube_cfg(dma_dev *dev, dma_channel channel, dma_tube_config *cfg) {
return ret;
}
+ dma_disable(dev, channel); /* Must disable before reconfiguring */
+ dma_clear_isr_bits(dev, channel); /* For sanity and consistency
+ * with STM32F2. */
+
chregs = dma_tube_regs(dev, channel);
switch (_dma_addr_type(cfg->tube_dst)) {
case DMA_ATYPE_PER:
- return config_to_per(chregs, cfg);
+ ret = config_to_per(chregs, cfg);
+ break;
case DMA_ATYPE_MEM:
- return config_to_mem(chregs, cfg);
+ ret = config_to_mem(chregs, cfg);
+ break;
default:
/* Can't happen */
ASSERT(0);
return -DMA_TUBE_CFG_ECFG;
}
+ if (ret < 0) {
+ return ret;
+ }
+ chregs->CNDTR = cfg->tube_nr_xfers;
+ return DMA_TUBE_CFG_SUCCESS;
}
void dma_set_priority(dma_dev *dev,