SPI DMA based on teensy DmaSpi library

Dependencies:   mbed

This is proof of concept, porting the teensy 3 DmaSpi library to mbed MK64F. Program does 8-bit DMA SPI transfers. Verified with jumper between MOSI and MISO and with logic analyzer. With SPI clock @12MHz, data rate for 1024 bytes is 10.6 mbs. With SPI clock @30MHz, 22.6 mbs

Committer:
manitou
Date:
Sun Feb 21 16:52:03 2016 +0000
Revision:
0:03cb2b9cf5d3
running version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
manitou 0:03cb2b9cf5d3 1 // DMA SPI 8-bit frames based on teensy 3
manitou 0:03cb2b9cf5d3 2 // https://github.com/crteensy/DmaSpi
manitou 0:03cb2b9cf5d3 3 // jumper MISO to MOSI for verification
manitou 0:03cb2b9cf5d3 4 #include "mbed.h"
manitou 0:03cb2b9cf5d3 5
manitou 0:03cb2b9cf5d3 6 #define PRREG(z) printf(#z" 0x%x\n",z)
manitou 0:03cb2b9cf5d3 7
manitou 0:03cb2b9cf5d3 8 Timer tmr;
manitou 0:03cb2b9cf5d3 9 DigitalOut CSpin(D10);
manitou 0:03cb2b9cf5d3 10 SPI spi(D11,D12,D13); // mosi, miso, sclk SPI0
manitou 0:03cb2b9cf5d3 11
manitou 0:03cb2b9cf5d3 12 #define SPIHZ 12000000
manitou 0:03cb2b9cf5d3 13 #define TXCHNL 0
manitou 0:03cb2b9cf5d3 14 #define RXCHNL 1
manitou 0:03cb2b9cf5d3 15 #define DMAMUX_SPI0RX 14
manitou 0:03cb2b9cf5d3 16 #define DMAMUX_SPI0TX 15
manitou 0:03cb2b9cf5d3 17
manitou 0:03cb2b9cf5d3 18 #define NBYTES 1024
manitou 0:03cb2b9cf5d3 19 uint8_t rx_buffer[NBYTES];
manitou 0:03cb2b9cf5d3 20 uint8_t tx_buffer[NBYTES];
manitou 0:03cb2b9cf5d3 21
manitou 0:03cb2b9cf5d3 22 volatile int dmadone;
manitou 0:03cb2b9cf5d3 23
manitou 0:03cb2b9cf5d3 24 void dmaisr() {
manitou 0:03cb2b9cf5d3 25 /// RX dma interrupt
manitou 0:03cb2b9cf5d3 26 DMA_CINT = RXCHNL; //clear interrupt
manitou 0:03cb2b9cf5d3 27 SPI0_RSER = 0;
manitou 0:03cb2b9cf5d3 28 SPI0_SR = 0xFF0F0000;
manitou 0:03cb2b9cf5d3 29 dmadone = 1;
manitou 0:03cb2b9cf5d3 30
manitou 0:03cb2b9cf5d3 31 }
manitou 0:03cb2b9cf5d3 32
manitou 0:03cb2b9cf5d3 33 void dma_init(void) {
manitou 0:03cb2b9cf5d3 34 // Enable clock for DMAMUX and DMA
manitou 0:03cb2b9cf5d3 35 SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;
manitou 0:03cb2b9cf5d3 36 SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;
manitou 0:03cb2b9cf5d3 37
manitou 0:03cb2b9cf5d3 38 DMA_CERQ = RXCHNL;
manitou 0:03cb2b9cf5d3 39 DMA_CERQ = TXCHNL;
manitou 0:03cb2b9cf5d3 40
manitou 0:03cb2b9cf5d3 41 // Enable TX channel and set SPI0_Tx as DMA request source
manitou 0:03cb2b9cf5d3 42 DMAMUX_CHCFG0 |= DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(DMAMUX_SPI0TX);
manitou 0:03cb2b9cf5d3 43 DMA0->TCD[TXCHNL].DADDR = (uint32_t)&SPI0_PUSHR;
manitou 0:03cb2b9cf5d3 44 DMA0->TCD[TXCHNL].SOFF = 1;
manitou 0:03cb2b9cf5d3 45 DMA0->TCD[TXCHNL].DOFF = 0;
manitou 0:03cb2b9cf5d3 46 DMA0->TCD[TXCHNL].ATTR = DMA_ATTR_SSIZE(0) | DMA_ATTR_DSIZE(0);
manitou 0:03cb2b9cf5d3 47 DMA0->TCD[TXCHNL].NBYTES_MLNO = 1;
manitou 0:03cb2b9cf5d3 48 DMA0->TCD[TXCHNL].DLAST_SGA=0;
manitou 0:03cb2b9cf5d3 49 DMA0->TCD[TXCHNL].SLAST=0;
manitou 0:03cb2b9cf5d3 50 DMA0->TCD[TXCHNL].CSR = DMA_CSR_DREQ_MASK;
manitou 0:03cb2b9cf5d3 51
manitou 0:03cb2b9cf5d3 52 // Enable SPI0 RX channel
manitou 0:03cb2b9cf5d3 53 DMAMUX_CHCFG1 |= DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(DMAMUX_SPI0RX);
manitou 0:03cb2b9cf5d3 54 DMA0->TCD[RXCHNL].SADDR = (uint32_t)&SPI0_POPR; // recv
manitou 0:03cb2b9cf5d3 55 DMA0->TCD[RXCHNL].SOFF = 0;
manitou 0:03cb2b9cf5d3 56 DMA0->TCD[RXCHNL].DOFF = 1;
manitou 0:03cb2b9cf5d3 57 DMA0->TCD[RXCHNL].ATTR = DMA_ATTR_SSIZE(0) | DMA_ATTR_DSIZE(0);
manitou 0:03cb2b9cf5d3 58 DMA0->TCD[RXCHNL].NBYTES_MLNO = 1;
manitou 0:03cb2b9cf5d3 59 DMA0->TCD[RXCHNL].DLAST_SGA=0;
manitou 0:03cb2b9cf5d3 60 DMA0->TCD[RXCHNL].SLAST=0;
manitou 0:03cb2b9cf5d3 61 DMA0->TCD[RXCHNL].CSR = DMA_CSR_DREQ_MASK | DMA_CSR_INTMAJOR_MASK;
manitou 0:03cb2b9cf5d3 62
manitou 0:03cb2b9cf5d3 63 // setup RX ISR
manitou 0:03cb2b9cf5d3 64 NVIC_EnableIRQ(DMA1_IRQn);
manitou 0:03cb2b9cf5d3 65 NVIC_SetVector(DMA1_IRQn, (uint32_t)&dmaisr);
manitou 0:03cb2b9cf5d3 66 }
manitou 0:03cb2b9cf5d3 67
manitou 0:03cb2b9cf5d3 68 void spidma(void *txbuff, void *rxbuff, int bytes) {
manitou 0:03cb2b9cf5d3 69 CSpin=0;
manitou 0:03cb2b9cf5d3 70 dmadone = 0;
manitou 0:03cb2b9cf5d3 71 SPI0_SR = 0xFF0F0000;
manitou 0:03cb2b9cf5d3 72 SPI0_RSER = SPI_RSER_TFFF_RE_MASK | SPI_RSER_TFFF_DIRS_MASK | SPI_RSER_RFDF_RE_MASK | SPI_RSER_RFDF_DIRS_MASK;
manitou 0:03cb2b9cf5d3 73
manitou 0:03cb2b9cf5d3 74 // Set memory address for source and destination
manitou 0:03cb2b9cf5d3 75 DMA0->TCD[TXCHNL].SADDR = (uint32_t)txbuff; // xmit
manitou 0:03cb2b9cf5d3 76 DMA0->TCD[RXCHNL].DADDR = (uint32_t)rxbuff;
manitou 0:03cb2b9cf5d3 77
manitou 0:03cb2b9cf5d3 78 // Current major iteration count
manitou 0:03cb2b9cf5d3 79 DMA0->TCD[TXCHNL].BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(bytes);
manitou 0:03cb2b9cf5d3 80 DMA0->TCD[TXCHNL].CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(bytes);
manitou 0:03cb2b9cf5d3 81 DMA0->TCD[RXCHNL].BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(bytes);
manitou 0:03cb2b9cf5d3 82 DMA0->TCD[RXCHNL].CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(bytes);
manitou 0:03cb2b9cf5d3 83
manitou 0:03cb2b9cf5d3 84 // Enable request signal for channels
manitou 0:03cb2b9cf5d3 85 DMA_SERQ = RXCHNL;
manitou 0:03cb2b9cf5d3 86 DMA_SERQ = TXCHNL;
manitou 0:03cb2b9cf5d3 87
manitou 0:03cb2b9cf5d3 88 while (!dmadone); // wait for completion
manitou 0:03cb2b9cf5d3 89 // while(!(DMA0->TCD[RXCHNL].CSR & BM_DMA_TCDn_CSR_DONE)); // wait
manitou 0:03cb2b9cf5d3 90
manitou 0:03cb2b9cf5d3 91 CSpin=1;
manitou 0:03cb2b9cf5d3 92 }
manitou 0:03cb2b9cf5d3 93
manitou 0:03cb2b9cf5d3 94 void spiperf(int mhz) {
manitou 0:03cb2b9cf5d3 95 int i, us;
manitou 0:03cb2b9cf5d3 96
manitou 0:03cb2b9cf5d3 97 spi.frequency(mhz*1000000);
manitou 0:03cb2b9cf5d3 98 CSpin=0;
manitou 0:03cb2b9cf5d3 99 us = tmr.read_us();
manitou 0:03cb2b9cf5d3 100 for(i=0;i<NBYTES;i++) spi.write(tx_buffer[i]); // old school
manitou 0:03cb2b9cf5d3 101 us = tmr.read_us()-us;
manitou 0:03cb2b9cf5d3 102 CSpin=1;
manitou 0:03cb2b9cf5d3 103 printf("spi %d mhz %d us %.2f mbs %d bytes %0x\n",mhz,us,8.*NBYTES/us,NBYTES,SPI0_CTAR0);
manitou 0:03cb2b9cf5d3 104 }
manitou 0:03cb2b9cf5d3 105
manitou 0:03cb2b9cf5d3 106 int main() {
manitou 0:03cb2b9cf5d3 107 int i, errs;
manitou 0:03cb2b9cf5d3 108 uint32_t us;
manitou 0:03cb2b9cf5d3 109
manitou 0:03cb2b9cf5d3 110 printf("SystemCoreClock %d %s %s\n",SystemCoreClock,__TIME__,__DATE__);
manitou 0:03cb2b9cf5d3 111 wait(2.0);
manitou 0:03cb2b9cf5d3 112 tmr.start();
manitou 0:03cb2b9cf5d3 113 CSpin=1;
manitou 0:03cb2b9cf5d3 114 spi.format (8, 0);
manitou 0:03cb2b9cf5d3 115 spi.frequency (SPIHZ);
manitou 0:03cb2b9cf5d3 116
manitou 0:03cb2b9cf5d3 117 // Load some exciting data into the buffers
manitou 0:03cb2b9cf5d3 118 for (i=0; i<NBYTES; i++) tx_buffer[i] = i;
manitou 0:03cb2b9cf5d3 119
manitou 0:03cb2b9cf5d3 120 dma_init();
manitou 0:03cb2b9cf5d3 121
manitou 0:03cb2b9cf5d3 122
manitou 0:03cb2b9cf5d3 123 while (1){
manitou 0:03cb2b9cf5d3 124 // spiperf(SPIHZ/1000000);
manitou 0:03cb2b9cf5d3 125 memset(rx_buffer,0,NBYTES);
manitou 0:03cb2b9cf5d3 126 us = tmr.read_us();
manitou 0:03cb2b9cf5d3 127 spidma(tx_buffer,rx_buffer,NBYTES);
manitou 0:03cb2b9cf5d3 128 us = tmr.read_us()-us;
manitou 0:03cb2b9cf5d3 129 errs=0;
manitou 0:03cb2b9cf5d3 130 for (i=0; i<NBYTES; i++) if (rx_buffer[i] != i%256) errs++; // MISO to MOSI
manitou 0:03cb2b9cf5d3 131 printf("dmaspi %d hz %d us %.2f mbs %d bytes errs %d %0x\n",SPIHZ,us,8.*NBYTES/us,NBYTES,errs,SPI0_CTAR0);
manitou 0:03cb2b9cf5d3 132 wait(4.0);
manitou 0:03cb2b9cf5d3 133 }
manitou 0:03cb2b9cf5d3 134 }