DMA SPI achieves wire speed, 44.3 mbs for block transfers Proof-of-concept

Dependencies:   mbed

Proof-of-concept SPI block transfer using DMA to achieve wire speeds. SPI1 runs at 45mhz, standard SPI write() achieves only 11mbs, DMA version does 44.3 mbs.

More/comparative SPI results at https://github.com/manitou48/DUEZoo/blob/master/SPIperf.txt

Committer:
manitou
Date:
Tue Nov 10 12:07:03 2015 +0000
Revision:
0:6242d93d3c51
DMA SPI proof of concept, wire speed 44.3 mbs

Who changed what in which revision?

UserRevisionLine numberNew contents of line
manitou 0:6242d93d3c51 1 //nucleo DMA SPI from pyboard SPI proof of concept
manitou 0:6242d93d3c51 2 // need DMA channel for TX and another for RX
manitou 0:6242d93d3c51 3 //tx DMA2_Stream5, DMA_CHANNEL_3 rx DMA2_Stream2, DMA_CHANNEL_3
manitou 0:6242d93d3c51 4 // SPI1 and 4 max 45mbs SPI3 4 max 22.5mbs
manitou 0:6242d93d3c51 5 #include "mbed.h"
manitou 0:6242d93d3c51 6
manitou 0:6242d93d3c51 7 #define PRREG(z) printf(#z" 0x%x\n",z)
manitou 0:6242d93d3c51 8 Timer tmr;
manitou 0:6242d93d3c51 9 DigitalOut CSpin(D10);
manitou 0:6242d93d3c51 10 SPI spi(SPI_MOSI, SPI_MISO, SPI_SCK); // mosi, miso, sclk SPI1
manitou 0:6242d93d3c51 11
manitou 0:6242d93d3c51 12 #define SPI_BUFF_SIZE 1024
manitou 0:6242d93d3c51 13 uint8_t rx_buffer[SPI_BUFF_SIZE];
manitou 0:6242d93d3c51 14 uint8_t tx_buffer[SPI_BUFF_SIZE];
manitou 0:6242d93d3c51 15
manitou 0:6242d93d3c51 16 void spiperf(int mhz) {
manitou 0:6242d93d3c51 17 int i, us;
manitou 0:6242d93d3c51 18
manitou 0:6242d93d3c51 19 spi.frequency(mhz*1000000);
manitou 0:6242d93d3c51 20 CSpin=0;
manitou 0:6242d93d3c51 21 us = tmr.read_us();
manitou 0:6242d93d3c51 22 for(i=0;i<SPI_BUFF_SIZE;i++) spi.write(tx_buffer[i]);
manitou 0:6242d93d3c51 23 us = tmr.read_us()-us;
manitou 0:6242d93d3c51 24 CSpin=1;
manitou 0:6242d93d3c51 25 printf("spi %d mhz %d us %.2f mbs %0x\n",mhz,us,8.*SPI_BUFF_SIZE/us,SPI1->CR1);
manitou 0:6242d93d3c51 26 }
manitou 0:6242d93d3c51 27
manitou 0:6242d93d3c51 28 // need to re-create SPI firmware to access SPI handle
manitou 0:6242d93d3c51 29 static SPI_HandleTypeDef SpiHandle;
manitou 0:6242d93d3c51 30
manitou 0:6242d93d3c51 31 static void spiInit() {
manitou 0:6242d93d3c51 32 SpiHandle.Instance = SPI1;
manitou 0:6242d93d3c51 33
manitou 0:6242d93d3c51 34 __HAL_SPI_DISABLE(&SpiHandle);
manitou 0:6242d93d3c51 35
manitou 0:6242d93d3c51 36 SpiHandle.Init.Mode = SPI_MODE_MASTER;
manitou 0:6242d93d3c51 37 SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; // 2 is 45 mhz 32 is 2.81mhz
manitou 0:6242d93d3c51 38 SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
manitou 0:6242d93d3c51 39 SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE; // mode 0
manitou 0:6242d93d3c51 40 SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
manitou 0:6242d93d3c51 41 SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
manitou 0:6242d93d3c51 42 SpiHandle.Init.CRCPolynomial = 7;
manitou 0:6242d93d3c51 43 SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
manitou 0:6242d93d3c51 44 SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
manitou 0:6242d93d3c51 45 SpiHandle.Init.NSS = SPI_NSS_SOFT;
manitou 0:6242d93d3c51 46 SpiHandle.Init.TIMode = SPI_TIMODE_DISABLED;
manitou 0:6242d93d3c51 47
manitou 0:6242d93d3c51 48 if (HAL_SPI_Init(&SpiHandle) != HAL_OK) {
manitou 0:6242d93d3c51 49 error("Cannot initialize SPI");
manitou 0:6242d93d3c51 50 }
manitou 0:6242d93d3c51 51
manitou 0:6242d93d3c51 52 __HAL_SPI_ENABLE(&SpiHandle);
manitou 0:6242d93d3c51 53 }
manitou 0:6242d93d3c51 54
manitou 0:6242d93d3c51 55 DMA_HandleTypeDef tx_DMA_Handle, rx_DMA_Handle;
manitou 0:6242d93d3c51 56
manitou 0:6242d93d3c51 57 static void dmaInit() {
manitou 0:6242d93d3c51 58 __DMA2_CLK_ENABLE();
manitou 0:6242d93d3c51 59 tx_DMA_Handle.Instance = DMA2_Stream5;
manitou 0:6242d93d3c51 60
manitou 0:6242d93d3c51 61 // Need to deinit DMA first
manitou 0:6242d93d3c51 62 tx_DMA_Handle.State = HAL_DMA_STATE_READY;
manitou 0:6242d93d3c51 63 HAL_DMA_DeInit(&tx_DMA_Handle);
manitou 0:6242d93d3c51 64
manitou 0:6242d93d3c51 65 tx_DMA_Handle.Init.Channel = DMA_CHANNEL_3;
manitou 0:6242d93d3c51 66 tx_DMA_Handle.Init.Direction = DMA_MEMORY_TO_PERIPH;
manitou 0:6242d93d3c51 67 tx_DMA_Handle.Init.PeriphInc = DMA_PINC_DISABLE;
manitou 0:6242d93d3c51 68 tx_DMA_Handle.Init.MemInc = DMA_MINC_ENABLE;
manitou 0:6242d93d3c51 69 tx_DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
manitou 0:6242d93d3c51 70 tx_DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
manitou 0:6242d93d3c51 71 tx_DMA_Handle.Init.Mode = DMA_NORMAL;
manitou 0:6242d93d3c51 72 tx_DMA_Handle.Init.Priority = DMA_PRIORITY_LOW;
manitou 0:6242d93d3c51 73 tx_DMA_Handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
manitou 0:6242d93d3c51 74 tx_DMA_Handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
manitou 0:6242d93d3c51 75 tx_DMA_Handle.Init.MemBurst = DMA_MBURST_INC4;
manitou 0:6242d93d3c51 76 tx_DMA_Handle.Init.PeriphBurst = DMA_PBURST_INC4;
manitou 0:6242d93d3c51 77 HAL_DMA_Init(&tx_DMA_Handle);
manitou 0:6242d93d3c51 78 //__HAL_LINKDMA(spiHandle, DMA_Handle, tx_DMA_Handle); // TODO macro
manitou 0:6242d93d3c51 79 tx_DMA_Handle.Parent = &SpiHandle;
manitou 0:6242d93d3c51 80 SpiHandle.hdmatx = &tx_DMA_Handle;
manitou 0:6242d93d3c51 81 SpiHandle.hdmarx = NULL;
manitou 0:6242d93d3c51 82 }
manitou 0:6242d93d3c51 83
manitou 0:6242d93d3c51 84
manitou 0:6242d93d3c51 85 static void spiSend(uint8_t *data, uint16_t bytes) {
manitou 0:6242d93d3c51 86 // ? need SPI handle
manitou 0:6242d93d3c51 87 HAL_SPI_Transmit_DMA(&SpiHandle, data, bytes); // TODO
manitou 0:6242d93d3c51 88 HAL_DMA_PollForTransfer(&tx_DMA_Handle, HAL_DMA_FULL_TRANSFER , 2000);
manitou 0:6242d93d3c51 89 // while (tx_DMA_Handle.Instance->CR & DMA_SxCR_EN); // spin
manitou 0:6242d93d3c51 90 }
manitou 0:6242d93d3c51 91
manitou 0:6242d93d3c51 92 int main() {
manitou 0:6242d93d3c51 93 uint32_t us, i;
manitou 0:6242d93d3c51 94
manitou 0:6242d93d3c51 95 printf("SystemCoreClock %d %s %s\n",SystemCoreClock,__TIME__,__DATE__);
manitou 0:6242d93d3c51 96 tmr.start();
manitou 0:6242d93d3c51 97 CSpin =1;
manitou 0:6242d93d3c51 98 for(i=0;i<SPI_BUFF_SIZE;i++) tx_buffer[i]=i;
manitou 0:6242d93d3c51 99 PRREG(SPI1->CR1);
manitou 0:6242d93d3c51 100 PRREG(SPI1->CR2);
manitou 0:6242d93d3c51 101 PRREG(SPI1->SR);
manitou 0:6242d93d3c51 102
manitou 0:6242d93d3c51 103 spiperf(1);
manitou 0:6242d93d3c51 104 spiperf(2);
manitou 0:6242d93d3c51 105 spiperf(4);
manitou 0:6242d93d3c51 106 spiperf(8);
manitou 0:6242d93d3c51 107 spiperf(15);
manitou 0:6242d93d3c51 108 spiperf(30);
manitou 0:6242d93d3c51 109 spiperf(45);
manitou 0:6242d93d3c51 110
manitou 0:6242d93d3c51 111 spiInit();
manitou 0:6242d93d3c51 112 dmaInit();
manitou 0:6242d93d3c51 113 CSpin = 0;
manitou 0:6242d93d3c51 114 us = tmr.read_us();
manitou 0:6242d93d3c51 115 spiSend(tx_buffer,SPI_BUFF_SIZE);
manitou 0:6242d93d3c51 116 us = tmr.read_us()-us;
manitou 0:6242d93d3c51 117 CSpin=1;
manitou 0:6242d93d3c51 118 printf("DMAspi %d us %.2f mbs %0x\n",us,8.*SPI_BUFF_SIZE/us,SPI1->CR1);
manitou 0:6242d93d3c51 119 }