improved SPI no DMA block read + added SPI DMA

This commit is contained in:
stevstrong 2017-05-10 20:48:14 +02:00
parent 28fa836f4f
commit 59ebf2a818
5 changed files with 71 additions and 58 deletions

View File

@ -117,33 +117,16 @@ void dma_detach_interrupt(dma_dev *dev, dma_stream stream) {
dev->handlers[stream].handler = NULL;
}
const uint8 dma_isr_bits_shift[] = { 0, 6, 16, 22};
uint8 dma_get_isr_bits(dma_dev *dev, dma_stream stream) {
if ( stream&0xFC ) return ((dev->regs->HISR)>>dma_isr_bits_shift[stream&0x03]) & 0x3d;
else return ((dev->regs->LISR)>>dma_isr_bits_shift[stream&0x03]) & 0x3d;
}
void dma_clear_isr_bits(dma_dev *dev, dma_stream stream) {
switch (stream) {
case 0:
dev->regs->LIFCR|=0x0000003d;
break;
case 1:
dev->regs->LIFCR|=0x00000f40;
break;
case 2:
dev->regs->LIFCR|=0x003d0000;
break;
case 3:
dev->regs->LIFCR|=0x0f400000;
break;
case 4:
dev->regs->HIFCR|=0x0000003d;
break;
case 5:
dev->regs->HIFCR|=0x00000f40;
break;
case 6:
dev->regs->HIFCR|=0x003d0000;
break;
case 7:
dev->regs->HIFCR|=0x0f400000;
break;
}
if ( stream&0xFC ) dev->regs->HIFCR = (uint32)0x0000003d << dma_isr_bits_shift[stream&0x03];
else dev->regs->LIFCR = (uint32)0x0000003d << dma_isr_bits_shift[stream&0x03];
}
/*

View File

@ -25,7 +25,7 @@
*****************************************************************************/
/**
* @file dma.h
* @file dmaF4.h
*
* @author Marti Bolivar <mbolivar@leaflabs.com>;
* Original implementation by Michael Hope
@ -84,7 +84,7 @@ typedef struct dma_reg_map {
* Register bit definitions
*/
/* Channel configuration register */
/* Stream configuration register */
#define DMA_CR_CH0 (0x0 << 25)
#define DMA_CR_CH1 (0x1 << 25)
@ -136,6 +136,25 @@ typedef struct dma_reg_map {
#define DMA_CR_DMEIE (0x1 << 1)
#define DMA_CR_EN (0x1)
typedef enum dma_channel {
DMA_CH0 = DMA_CR_CH0, /**< Channel 0 */
DMA_CH1 = DMA_CR_CH1, /**< Channel 1 */
DMA_CH2 = DMA_CR_CH2, /**< Channel 2 */
DMA_CH3 = DMA_CR_CH3, /**< Channel 3 */
DMA_CH4 = DMA_CR_CH4, /**< Channel 4 */
DMA_CH5 = DMA_CR_CH5, /**< Channel 5 */
DMA_CH6 = DMA_CR_CH6, /**< Channel 6 */
DMA_CH7 = DMA_CR_CH7, /**< Channel 7 */
} dma_channel;
/* Device interrupt status register flags */
#define DMA_ISR_TCIF (1 << 5)
#define DMA_ISR_HTIF (1 << 4)
#define DMA_ISR_TEIF (1 << 3)
#define DMA_ISR_DMEIF (1 << 2)
#define DMA_ISR_FEIF (1 << 0)
/*
* Devices
*/
@ -166,25 +185,35 @@ extern dma_dev *DMA2;
* Convenience functions
*/
void dma_init(dma_dev *dev);
extern void dma_init(dma_dev *dev);
/** Flags for DMA transfer configuration. */
typedef enum dma_mode_flags {
DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */
DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */
DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */
DMA_CIRC_MODE = 1 << 5, /**< Circular mode */
DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */
DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */
DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */
DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */
DMA_MEM_BUF_0 = DMA_CR_CT0, /**< Current memory target buffer 0 */
DMA_MEM_BUF_1 = DMA_CR_CT1, /**< Current memory target buffer 1 */
DMA_DBL_BUF_MODE = DMA_CR_DBM, /**< Current memory double buffer mode */
DMA_PINC_OFFSET = DMA_CR_PINCOS, /**< Peripheral increment offset size */
DMA_MINC_MODE = DMA_CR_MINC, /**< Memory increment mode */
DMA_PINC_MODE = DMA_CR_PINC, /**< Peripheral increment mode */
DMA_CIRC_MODE = DMA_CR_CIRC, /**< Memory Circular mode */
DMA_FROM_PER = DMA_CR_DIR_P2M, /**< Read from memory to peripheral */
DMA_FROM_MEM = DMA_CR_DIR_M2P, /**< Read from memory to peripheral */
DMA_MEM_TO_MEM = DMA_CR_DIR_M2M, /**< Read from memory to memory */
DMA_PERIF_CTRL = DMA_CR_PFCTRL, /**< Peripheral flow controller */
DMA_PRIO_MEDIUM = DMA_CR_PL_MEDIUM, /**< Medium priority */
DMA_PRIO_HIGH = DMA_CR_PL_HIGH, /**< High priority */
DMA_PRIO_VERY_HIGH = DMA_CR_PL_VERY_HIGH, /**< Very high priority */
DMA_TRNS_CMPLT = DMA_CR_TCIE, /**< Interrupt on transfer completion */
DMA_TRNS_HALF = DMA_CR_HTIE, /**< Interrupt on half-transfer */
DMA_TRNS_ERR = DMA_CR_TEIE, /**< Interrupt on transfer error */
DMA_DIR_MODE_ERR = DMA_CR_DMEIE /**< Interrupt on direct mode error */
} dma_mode_flags;
/** Source and destination transfer sizes. */
typedef enum dma_xfer_size {
DMA_SIZE_8BITS = 0, /**< 8-bit transfers */
DMA_SIZE_16BITS = 1, /**< 16-bit transfers */
DMA_SIZE_32BITS = 2 /**< 32-bit transfers */
DMA_SIZE_8BITS = ( DMA_CR_MSIZE_8BITS|DMA_CR_PSIZE_8BITS ), /**< 8-bit transfers */
DMA_SIZE_16BITS = (DMA_CR_MSIZE_16BITS|DMA_CR_PSIZE_16BITS), /**< 16-bit transfers */
DMA_SIZE_32BITS = (DMA_CR_MSIZE_32BITS|DMA_CR_PSIZE_32BITS) /**< 32-bit transfers */
} dma_xfer_size;
/** DMA channel */
@ -201,17 +230,17 @@ typedef enum dma_stream {
static inline void dma_setup_transfer(dma_dev *dev,
dma_stream stream,
dma_channel channel,
dma_xfer_size trx_size,
__io void *peripheral_address,
__io void *memory_address0,
__io void *memory_address1,
uint32 flags,
uint32 fifo_flags) {
uint32 flags) {
dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; // disable
dev->regs->STREAM[stream].PAR = (uint32)peripheral_address;
dev->regs->STREAM[stream].M0AR = (uint32)memory_address0;
dev->regs->STREAM[stream].M1AR = (uint32)memory_address1;
dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits
dev->regs->STREAM[stream].CR = flags & 0x0feffffe; // mask out reserved and enable
dev->regs->STREAM[stream].CR = ((flags|channel|trx_size) & 0x0feffffe); // mask out reserved and enable
}
static inline void dma_set_num_transfers(dma_dev *dev,
@ -220,6 +249,12 @@ static inline void dma_set_num_transfers(dma_dev *dev,
dev->regs->STREAM[stream].NDTR = num_transfers;
}
static inline void dma_set_fifo_flags(dma_dev *dev,
dma_stream stream,
uint8 fifo_flags) {
dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits
}
void dma_attach_interrupt(dma_dev *dev,
dma_stream stream,
void (*handler)(void));
@ -232,6 +267,7 @@ static inline void dma_enable(dma_dev *dev, dma_stream stream) {
static inline void dma_disable(dma_dev *dev, dma_stream stream) {
dev->regs->STREAM[stream].CR &= ~DMA_CR_EN;
while (dev->regs->STREAM[stream].CR & DMA_CR_EN); // wait till EN bit is reset, see AN4031, chapter 4.1
}
/**

View File

@ -56,7 +56,7 @@ extern "C"{
* Devices
*/
struct dma_reg_map;
//struct dma_reg_map;
/* Encapsulates state related to user interrupt handlers. You
* shouldn't touch these directly; use dma_attach_interrupt() and
@ -82,16 +82,6 @@ struct dma_reg_map;
*
* @see dma_tube
*/
typedef enum dma_channel {
DMA_CH0 = 0, /**< Channel 0 */
DMA_CH1 = 1, /**< Channel 1 */
DMA_CH2 = 2, /**< Channel 2 */
DMA_CH3 = 3, /**< Channel 3 */
DMA_CH4 = 4, /**< Channel 4 */
DMA_CH5 = 5, /**< Channel 5 */
DMA_CH6 = 6, /**< Channel 6 */
DMA_CH7 = 7, /**< Channel 7 */
} dma_channel;
/**
* @brief Source and destination transfer sizes.

View File

@ -28,7 +28,7 @@
/**
* @file libmaple/stm32f1/spi.c
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief STM32F1 SPI/I2S.
* @brief STM32F4 SPI/I2S.
*/
#include <libmaple/spi.h>

View File

@ -42,6 +42,8 @@
#include <libmaple/dma.h>
#include <wirish.h>
#define SPI_DMA
// SPI_HAS_TRANSACTION means SPI has
// - beginTransaction()
// - endTransaction()
@ -135,11 +137,12 @@ private:
uint32_t dataSize;
spi_dev *spi_d;
//uint8_t _SSPin;
uint32_t clockDivider;
#ifdef SPI_DMA
dma_channel spiRxDmaChannel, spiTxDmaChannel;
dma_dev* spiDmaDev;
dma_channel spiDmaChannel;
dma_stream spiRxDmaStream, spiTxDmaStream;
#endif
friend class SPIClass;
@ -396,5 +399,6 @@ private:
*/
};
extern SPIClass SPI;
#endif