DMA SPI achieves wire speed, 44.3 mbs for block transfers Proof-of-concept
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
main.cpp
- Committer:
- manitou
- Date:
- 2015-11-10
- Revision:
- 0:6242d93d3c51
File content as of revision 0:6242d93d3c51:
//nucleo DMA SPI from pyboard SPI proof of concept // need DMA channel for TX and another for RX //tx DMA2_Stream5, DMA_CHANNEL_3 rx DMA2_Stream2, DMA_CHANNEL_3 // SPI1 and 4 max 45mbs SPI3 4 max 22.5mbs #include "mbed.h" #define PRREG(z) printf(#z" 0x%x\n",z) Timer tmr; DigitalOut CSpin(D10); SPI spi(SPI_MOSI, SPI_MISO, SPI_SCK); // mosi, miso, sclk SPI1 #define SPI_BUFF_SIZE 1024 uint8_t rx_buffer[SPI_BUFF_SIZE]; uint8_t tx_buffer[SPI_BUFF_SIZE]; void spiperf(int mhz) { int i, us; spi.frequency(mhz*1000000); CSpin=0; us = tmr.read_us(); for(i=0;i<SPI_BUFF_SIZE;i++) spi.write(tx_buffer[i]); us = tmr.read_us()-us; CSpin=1; printf("spi %d mhz %d us %.2f mbs %0x\n",mhz,us,8.*SPI_BUFF_SIZE/us,SPI1->CR1); } // need to re-create SPI firmware to access SPI handle static SPI_HandleTypeDef SpiHandle; static void spiInit() { SpiHandle.Instance = SPI1; __HAL_SPI_DISABLE(&SpiHandle); SpiHandle.Init.Mode = SPI_MODE_MASTER; SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; // 2 is 45 mhz 32 is 2.81mhz SpiHandle.Init.Direction = SPI_DIRECTION_2LINES; SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE; // mode 0 SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW; SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED; SpiHandle.Init.CRCPolynomial = 7; SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT; SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB; SpiHandle.Init.NSS = SPI_NSS_SOFT; SpiHandle.Init.TIMode = SPI_TIMODE_DISABLED; if (HAL_SPI_Init(&SpiHandle) != HAL_OK) { error("Cannot initialize SPI"); } __HAL_SPI_ENABLE(&SpiHandle); } DMA_HandleTypeDef tx_DMA_Handle, rx_DMA_Handle; static void dmaInit() { __DMA2_CLK_ENABLE(); tx_DMA_Handle.Instance = DMA2_Stream5; // Need to deinit DMA first tx_DMA_Handle.State = HAL_DMA_STATE_READY; HAL_DMA_DeInit(&tx_DMA_Handle); tx_DMA_Handle.Init.Channel = DMA_CHANNEL_3; tx_DMA_Handle.Init.Direction = DMA_MEMORY_TO_PERIPH; tx_DMA_Handle.Init.PeriphInc = DMA_PINC_DISABLE; tx_DMA_Handle.Init.MemInc = DMA_MINC_ENABLE; tx_DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; tx_DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; tx_DMA_Handle.Init.Mode = DMA_NORMAL; tx_DMA_Handle.Init.Priority = DMA_PRIORITY_LOW; tx_DMA_Handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE; tx_DMA_Handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; tx_DMA_Handle.Init.MemBurst = DMA_MBURST_INC4; tx_DMA_Handle.Init.PeriphBurst = DMA_PBURST_INC4; HAL_DMA_Init(&tx_DMA_Handle); //__HAL_LINKDMA(spiHandle, DMA_Handle, tx_DMA_Handle); // TODO macro tx_DMA_Handle.Parent = &SpiHandle; SpiHandle.hdmatx = &tx_DMA_Handle; SpiHandle.hdmarx = NULL; } static void spiSend(uint8_t *data, uint16_t bytes) { // ? need SPI handle HAL_SPI_Transmit_DMA(&SpiHandle, data, bytes); // TODO HAL_DMA_PollForTransfer(&tx_DMA_Handle, HAL_DMA_FULL_TRANSFER , 2000); // while (tx_DMA_Handle.Instance->CR & DMA_SxCR_EN); // spin } int main() { uint32_t us, i; printf("SystemCoreClock %d %s %s\n",SystemCoreClock,__TIME__,__DATE__); tmr.start(); CSpin =1; for(i=0;i<SPI_BUFF_SIZE;i++) tx_buffer[i]=i; PRREG(SPI1->CR1); PRREG(SPI1->CR2); PRREG(SPI1->SR); spiperf(1); spiperf(2); spiperf(4); spiperf(8); spiperf(15); spiperf(30); spiperf(45); spiInit(); dmaInit(); CSpin = 0; us = tmr.read_us(); spiSend(tx_buffer,SPI_BUFF_SIZE); us = tmr.read_us()-us; CSpin=1; printf("DMAspi %d us %.2f mbs %0x\n",us,8.*SPI_BUFF_SIZE/us,SPI1->CR1); }