From b2bdefee5cfcca0d4c5633f0ef486e7ddca0887f Mon Sep 17 00:00:00 2001 From: asterix Date: Mon, 13 Jun 2011 09:04:24 +0000 Subject: [PATCH] Add spi with dma implementation for sam3, and define generic header for both. Note: this module should be refactor! git-svn-id: https://src.develer.com/svnoss/bertos/trunk@4950 38d2e660-2303-0410-9eaa-f027e97ec537 --- bertos/cpu/arm/drv/spi_dma_at91.c | 11 +- bertos/cpu/cortex-m3/drv/spi_dma_sam3.c | 170 ++++++++++++++++++++++++ bertos/cpu/cortex-m3/drv/spi_dma_sam3.h | 73 ++++++++++ bertos/drv/spi_dma.h | 73 ++++++++++ 4 files changed, 323 insertions(+), 4 deletions(-) create mode 100644 bertos/cpu/cortex-m3/drv/spi_dma_sam3.c create mode 100644 bertos/cpu/cortex-m3/drv/spi_dma_sam3.h create mode 100644 bertos/drv/spi_dma.h diff --git a/bertos/cpu/arm/drv/spi_dma_at91.c b/bertos/cpu/arm/drv/spi_dma_at91.c index c4cbf2da..57ed2fbd 100644 --- a/bertos/cpu/arm/drv/spi_dma_at91.c +++ b/bertos/cpu/arm/drv/spi_dma_at91.c @@ -36,14 +36,17 @@ * \author Luca Ottaviano */ -#include "cfg/cfg_spi_dma.h" +#include -#include "spi_dma_at91.h" +#include "cfg/cfg_spi_dma.h" #include "hw/hw_spi_dma.h" +#include #include + #include #include + #include #include @@ -129,7 +132,7 @@ static size_t spi_dma_read(UNUSED_ARG(struct KFile *, fd), void *_buf, size_t si #define SPI_DMA_IRQ_PRIORITY 4 -void spi_dma_init(SpiDmaAt91 *spi) +void spi_dma_init(SpiDma *spi) { /* Disable PIO on SPI pins */ PIOA_PDR = BV(SPI0_SPCK) | BV(SPI0_MOSI) | BV(SPI0_MISO); @@ -158,7 +161,7 @@ void spi_dma_init(SpiDmaAt91 *spi) /* Enable SPI */ SPI0_CR = BV(SPI_SPIEN); - DB(spi->fd._type = KFT_SPIDMAAT91); + DB(spi->fd._type = KFT_SPIDMA); spi->fd.write = spi_dma_write; spi->fd.read = spi_dma_read; spi->fd.flush = spi_dma_flush; diff --git a/bertos/cpu/cortex-m3/drv/spi_dma_sam3.c b/bertos/cpu/cortex-m3/drv/spi_dma_sam3.c new file mode 100644 index 00000000..a1370810 --- /dev/null +++ b/bertos/cpu/cortex-m3/drv/spi_dma_sam3.c @@ -0,0 +1,170 @@ +/** + * \file + * + * + * \brief SPI driver with DMA. + * + * \author Francesco Sacchi + * \author Luca Ottaviano + */ + +#include + +#include "cfg/cfg_spi_dma.h" +#include "hw/hw_spi_dma.h" + +#include +#include + +#include +#include + +#include + +#include +#include + +#include /* memset */ + + +void spi_dma_setclock(uint32_t rate) +{ + SPI0_CSR0 &= ~SPI_SCBR; + + ASSERT((uint8_t)DIV_ROUND(CPU_FREQ, rate)); + SPI0_CSR0 |= DIV_ROUND(CPU_FREQ, rate) << SPI_SCBR_SHIFT; +} + + +static int spi_dma_flush(UNUSED_ARG(struct KFile *, fd)) +{ + /* Wait for DMA to finish */ + while (!(SPI0_SR & BV(SPI_TXBUFE))) + cpu_relax(); + + /* Wait until last bit has been shifted out */ + while (!(SPI0_SR & BV(SPI_TXEMPTY))) + cpu_relax(); + + return 0; +} + +static size_t spi_dma_write(struct KFile *fd, const void *_buf, size_t size) +{ + SPI0_PTCR = BV(PDC_PTCR_TXTDIS); + SPI0_TPR = (reg32_t)_buf; + SPI0_TCR = size; + SPI0_PTCR = BV(PDC_PTSR_TXTEN); + spi_dma_flush(fd); + return size; +} + + +/* + * Dummy buffer used to transmit 0xff chars while receiving data. + * This buffer is completetly constant and the compiler should allocate it + * in flash memory. + */ +static const uint8_t tx_dummy_buf[CONFIG_SPI_DMA_MAX_RX] = { [0 ... (CONFIG_SPI_DMA_MAX_RX - 1)] = 0xFF }; + +static size_t spi_dma_read(UNUSED_ARG(struct KFile *, fd), void *_buf, size_t size) +{ + size_t count, total_rx = 0; + uint8_t *buf = (uint8_t *)_buf; + + while (size) + { + count = MIN(size, (size_t)CONFIG_SPI_DMA_MAX_RX); + + SPI0_PTCR = BV(PDC_PTCR_TXTDIS) | BV(PDC_PTCR_RXTDIS); + + SPI0_RPR = (reg32_t)buf; + SPI0_RCR = count; + SPI0_TPR = (reg32_t)tx_dummy_buf; + SPI0_TCR = count; + + /* Avoid reading the previous sent char */ + *buf = SPI0_RDR; + + /* Start transfer */ + SPI0_PTCR = BV(PDC_PTCR_RXTEN) | BV(PDC_PTCR_TXTEN); + + /* wait for transfer to finish */ + while (!(SPI0_SR & BV(SPI_ENDRX))) + cpu_relax(); + + size -= count; + total_rx += count; + buf += count; + } + SPI0_PTCR = BV(PDC_PTCR_RXTDIS) | BV(PDC_PTCR_TXTDIS); + + return total_rx; +} + +#define SPI_DMA_IRQ_PRIORITY 4 + +void spi_dma_init(SpiDma *spi) +{ + /* Disable PIO on SPI pins */ + PIOA_PDR = BV(SPI0_SPCK) | BV(SPI0_MOSI) | BV(SPI0_MISO); + + /* Reset device */ + SPI0_CR = BV(SPI_SWRST); + + /* + * Set SPI to master mode, fixed peripheral select, chip select directly connected to a peripheral device, + * SPI clock set to MCK, mode fault detection disabled, loopback disable, NPCS0 active, Delay between CS = 0 + */ + SPI0_MR = BV(SPI_MSTR) | BV(SPI_MODFDIS); + + /* + * Set SPI mode. + * At reset clock division factor is set to 0, that is + * *forbidden*. Set SPI clock to minimum to keep it valid. + */ + SPI0_CSR0 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT); + + /* Disable all irqs */ + SPI0_IDR = 0xFFFFFFFF; + /* Enable SPI clock. */ + PMC_PCER = BV(SPI0_ID); + + /* Enable SPI */ + SPI0_CR = BV(SPI_SPIEN); + + DB(spi->fd._type = KFT_SPIDMA); + spi->fd.write = spi_dma_write; + spi->fd.read = spi_dma_read; + spi->fd.flush = spi_dma_flush; + + SPI_DMA_STROBE_INIT(); +} diff --git a/bertos/cpu/cortex-m3/drv/spi_dma_sam3.h b/bertos/cpu/cortex-m3/drv/spi_dma_sam3.h new file mode 100644 index 00000000..db9d55fb --- /dev/null +++ b/bertos/cpu/cortex-m3/drv/spi_dma_sam3.h @@ -0,0 +1,73 @@ +/** + * \file + * + * + * \brief SPI driver with DMA. + * + * \note Only one copy of SpiDma is allowed for each application. + * + * \author Francesco Sacchi + * \author Luca Ottaviano + * \author Daniele Basile + */ + +#ifndef DRV_SPI_DMA_H +#define DRV_SPI_DMA_H + +#include + +typedef struct SpiDma +{ + KFile fd; +} SpiDma; + +#define KFT_SPIDMA MAKE_ID('S', 'P', 'I', 'D') + +INLINE SpiDma * SPIDMA_CAST(KFile *fd) +{ + ASSERT(fd->_type == KFT_SPIDMA); + return (SpiDma *)fd; +} + +/** + * Init DMA SPI driver. + * \param spi A pointer to a SpiDma structure. + */ +void spi_dma_init(SpiDma *spi); + +/** + * Set the clock rate for SPI bus. + * + * \param rate The rate you want to set for SPI. + */ +void spi_dma_setclock(uint32_t rate); + +#endif /* DRV_SPI_DMA_H */ diff --git a/bertos/drv/spi_dma.h b/bertos/drv/spi_dma.h new file mode 100644 index 00000000..db9d55fb --- /dev/null +++ b/bertos/drv/spi_dma.h @@ -0,0 +1,73 @@ +/** + * \file + * + * + * \brief SPI driver with DMA. + * + * \note Only one copy of SpiDma is allowed for each application. + * + * \author Francesco Sacchi + * \author Luca Ottaviano + * \author Daniele Basile + */ + +#ifndef DRV_SPI_DMA_H +#define DRV_SPI_DMA_H + +#include + +typedef struct SpiDma +{ + KFile fd; +} SpiDma; + +#define KFT_SPIDMA MAKE_ID('S', 'P', 'I', 'D') + +INLINE SpiDma * SPIDMA_CAST(KFile *fd) +{ + ASSERT(fd->_type == KFT_SPIDMA); + return (SpiDma *)fd; +} + +/** + * Init DMA SPI driver. + * \param spi A pointer to a SpiDma structure. + */ +void spi_dma_init(SpiDma *spi); + +/** + * Set the clock rate for SPI bus. + * + * \param rate The rate you want to set for SPI. + */ +void spi_dma_setclock(uint32_t rate); + +#endif /* DRV_SPI_DMA_H */ -- 2.25.1