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 }
![(please configure the [header_logo] section in trac.ini)](/chrome/site/bertos_logo.png)