diff options
-rw-r--r-- | libmaple/stm32f1/dma.c | 62 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/dma.h | 2 |
2 files changed, 60 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, diff --git a/libmaple/stm32f1/include/series/dma.h b/libmaple/stm32f1/include/series/dma.h index 6da3246..3b19e2b 100644 --- a/libmaple/stm32f1/include/series/dma.h +++ b/libmaple/stm32f1/include/series/dma.h @@ -293,6 +293,8 @@ typedef struct dma_tube_reg_map { #define DMA_CCR_PINC (1U << DMA_CCR_PINC_BIT) #define DMA_CCR_CIRC (1U << DMA_CCR_CIRC_BIT) #define DMA_CCR_DIR (1U << DMA_CCR_DIR_BIT) +#define DMA_CCR_DIR_FROM_PER (0U << DMA_CCR_DIR_BIT) +#define DMA_CCR_DIR_FROM_MEM (1U << DMA_CCR_DIR_BIT) #define DMA_CCR_TEIE (1U << DMA_CCR_TEIE_BIT) #define DMA_CCR_HTIE (1U << DMA_CCR_HTIE_BIT) #define DMA_CCR_TCIE (1U << DMA_CCR_TCIE_BIT) |