spi_dma_sam3.c
Go to the documentation of this file.
00001
00039 #include "cfg/cfg_spi_dma.h"
00040 #include "hw/hw_spi_dma.h"
00041
00042 #include <io/cm3.h>
00043 #include <io/kfile.h>
00044
00045 #include <struct/fifobuf.h>
00046 #include <struct/kfile_fifo.h>
00047
00048 #include <drv/timer.h>
00049 #include <drv/spi_dma.h>
00050
00051
00052 #include <cpu/attr.h>
00053 #include <cpu/power.h>
00054
00055 #include <string.h> /* memset */
00056
00057
00058 void spi_dma_setclock(uint32_t rate)
00059 {
00060     SPI0_CSR0 &= ~SPI_SCBR;
00061
00062     ASSERT((uint8_t)DIV_ROUND(CPU_FREQ, rate));
00063     SPI0_CSR0 |= DIV_ROUND(CPU_FREQ, rate) << SPI_SCBR_SHIFT;
00064 }
00065
00066
00067 static int spi_dma_flush(UNUSED_ARG(struct KFile *, fd))
00068 {
00069     /* Wait for DMA to finish */
00070     while (!(SPI0_SR & BV(SPI_TXBUFE)))
00071         cpu_relax();
00072
00073     /* Wait until last bit has been shifted out */
00074     while (!(SPI0_SR & BV(SPI_TXEMPTY)))
00075         cpu_relax();
00076
00077     return 0;
00078 }
00079
00080 static size_t spi_dma_write(struct KFile *fd, const void *_buf, size_t size)
00081 {
00082     SPI0_PTCR = BV(PDC_PTCR_TXTDIS);
00083     SPI0_TPR = (reg32_t)_buf;
00084     SPI0_TCR = size;
00085     SPI0_PTCR = BV(PDC_PTSR_TXTEN);
00086     spi_dma_flush(fd);
00087     return size;
00088 }
00089
00090
00091 /*
00092  * Dummy buffer used to transmit 0xff chars while receiving data.
00093  * This buffer is completetly constant and the compiler should allocate it
00094  * in flash memory.
00095  */
00096 static const uint8_t tx_dummy_buf[CONFIG_SPI_DMA_MAX_RX] = { [0 ... (CONFIG_SPI_DMA_MAX_RX - 1)] = 0xFF };
00097
00098 static size_t spi_dma_read(UNUSED_ARG(struct KFile *, fd), void *_buf, size_t size)
00099 {
00100     size_t count, total_rx = 0;
00101     uint8_t *buf = (uint8_t *)_buf;
00102
00103     while (size)
00104     {
00105         count = MIN(size, (size_t)CONFIG_SPI_DMA_MAX_RX);
00106
00107         SPI0_PTCR = BV(PDC_PTCR_TXTDIS) | BV(PDC_PTCR_RXTDIS);
00108
00109         SPI0_RPR = (reg32_t)buf;
00110         SPI0_RCR = count;
00111         SPI0_TPR = (reg32_t)tx_dummy_buf;
00112         SPI0_TCR = count;
00113
00114         /* Avoid reading the previous sent char */
00115         *buf = SPI0_RDR;
00116
00117         /* Start transfer */
00118         SPI0_PTCR = BV(PDC_PTCR_RXTEN) | BV(PDC_PTCR_TXTEN);
00119
00120         /* wait for transfer to finish */
00121         while (!(SPI0_SR & BV(SPI_ENDRX)))
00122             cpu_relax();
00123
00124         size -= count;
00125         total_rx += count;
00126         buf += count;
00127     }
00128     SPI0_PTCR = BV(PDC_PTCR_RXTDIS) | BV(PDC_PTCR_TXTDIS);
00129
00130     return total_rx;
00131 }
00132
00133 #define SPI_DMA_IRQ_PRIORITY 4
00134 
00135 void spi_dma_init(SpiDma *spi)
00136 {
00137     /* Disable PIO on SPI pins */
00138     PIOA_PDR = BV(SPI0_SPCK) | BV(SPI0_MOSI) | BV(SPI0_MISO);
00139
00140     /* Reset device */
00141     SPI0_CR = BV(SPI_SWRST);
00142
00143     /*
00144      * Set SPI to master mode, fixed peripheral select, chip select directly connected to a peripheral device,
00145      * SPI clock set to MCK, mode fault detection disabled, loopback disable, NPCS0 active, Delay between CS = 0
00146      */
00147     SPI0_MR = BV(SPI_MSTR) | BV(SPI_MODFDIS);
00148
00149     /*
00150      * Set SPI mode.
00151      * At reset clock division factor is set to 0, that is
00152      * *forbidden*. Set SPI clock to minimum to keep it valid.
00153      */
00154     SPI0_CSR0 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
00155
00156     /* Disable all irqs */
00157     SPI0_IDR = 0xFFFFFFFF;
00158     /* Enable SPI clock. */
00159     PMC_PCER = BV(SPI0_ID);
00160
00161     /* Enable SPI */
00162     SPI0_CR = BV(SPI_SPIEN);
00163
00164     DB(spi->fd._type = KFT_SPIDMA);
00165     spi->fd.write = spi_dma_write;
00166     spi->fd.read = spi_dma_read;
00167     spi->fd.flush = spi_dma_flush;
00168
00169     SPI_DMA_STROBE_INIT();
00170 }