AnsweredAssumed Answered

SPI with DMA loopback

Question asked by hinnant.neil on Jun 18, 2013
Latest reply on Jun 20, 2013 by hinnant.neil
Hey all,

I'm attempting to get an SPI with DMA loopback going on my STM32F4.
I have successfully gotten an SPI-only loopback running, and now I'm trying to add DMA support.

Here is my code:
<code>
#include <stm32f4xx.h>
#include <stm32f4xx_spi.h>
#include <stm32f4xx_dma.h>
#include "main.h"

uint8_t aTxBuffer[200] = {0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA};


uint8_t aRxBuffer[200];

void init_SPI1(void);
void init_DMA(void);
uint8_t SPI1_send(uint8_t data);
void put_buffer_DMA(uint8_t *buffer, uint8_t length);

// this function initializes the SPI1 peripheral
void init_SPI1(void){
    
    GPIO_InitTypeDef GPIO_InitStruct;
    SPI_InitTypeDef SPI_InitStruct;
    
    // enable clock for used IO pins
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    
    /* configure pins used by SPI1
     * PA5 = SCK
     * PA6 = MISO
     * PA7 = MOSI
     */
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    // connect SPI1 pins to SPI alternate function
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
    
    // enable clock for used IO pins
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
    
    /* Configure the chip select pin
       in this case we will use PE7 */
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOE, &GPIO_InitStruct);
    
    GPIOE->BSRRL |= GPIO_Pin_7; // set PE7 high
    
    // enable peripheral clock
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    
    /* configure SPI1 in Mode 0
     * CPOL = 0 --> clock is low when idle
     * CPHA = 0 --> data is sampled at the first edge
     */
    SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines
    SPI_InitStruct.SPI_Mode = SPI_Mode_Master;     // transmit in master mode, NSS pin has to be always high
    SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide
    SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;        // clock is low when idle
    SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;      // data sampled at first edge
    SPI_InitStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set; // set the NSS management to internal and pull internal NSS high
    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // SPI frequency is APB2 frequency / 4
    SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first
    SPI_Init(SPI1, &SPI_InitStruct);
    
    SPI_Cmd(SPI1, ENABLE); // enable SPI1
}

void init_DMA(void)
{
    DMA_InitTypeDef DMA_InitStructure;

     /* DMA configuration -------------------------------------------------------*/
    /* Deinitialize DMA Streams */
    DMA_DeInit(SPIx_TX_DMA_STREAM);
    DMA_DeInit(SPIx_RX_DMA_STREAM);
 
    /* Configure DMA Initialization Structure */
    DMA_InitStructure.DMA_BufferSize = BUFFERSIZE ;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable ;
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull ;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single ;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t) (&(SPIx->DR)) ;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    /* Configure TX DMA */
    DMA_InitStructure.DMA_Channel = SPIx_TX_DMA_CHANNEL ;
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral ;
    DMA_InitStructure.DMA_Memory0BaseAddr =(uint32_t)aTxBuffer ;
    DMA_Init(SPIx_TX_DMA_STREAM, &DMA_InitStructure);
    /* Configure RX DMA */
    DMA_InitStructure.DMA_Channel = SPIx_RX_DMA_CHANNEL ;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory ;
    DMA_InitStructure.DMA_Memory0BaseAddr =(uint32_t)aRxBuffer ;  
    DMA_Init(SPIx_RX_DMA_STREAM, &DMA_InitStructure);


    /* Enable DMA SPI TX Stream */
    DMA_Cmd(SPIx_TX_DMA_STREAM,ENABLE);
 
    /* Enable DMA SPI RX Stream */
    DMA_Cmd(SPIx_RX_DMA_STREAM,ENABLE);
 
    /* Enable SPI DMA TX Requsts */
    SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Tx, ENABLE);
 
    /* Enable SPI DMA RX Requsts */
    SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Rx, ENABLE);
}


int main(void){
    
    uint8_t received_val = 0;
    
    init_SPI1();
    
    init_DMA();
    
    /* LEDs configuration */       
    STM_EVAL_LEDInit(LED3);
    STM_EVAL_LEDInit(LED4);
    STM_EVAL_LEDInit(LED5);
    STM_EVAL_LEDInit(LED6);    

    while(1)
    {
        
        GPIOE->BSRRH |= GPIO_Pin_7; // set PE7 (CS) low
    
        while (DMA_GetFlagStatus(SPIx_TX_DMA_STREAM,SPIx_TX_DMA_FLAG_TCIF)==RESET);
          while (DMA_GetFlagStatus(SPIx_RX_DMA_STREAM,SPIx_RX_DMA_FLAG_TCIF)==RESET);
    
        DMA_ClearFlag(SPIx_TX_DMA_STREAM, SPIx_TX_DMA_FLAG_TCIF);
        DMA_ClearFlag(SPIx_RX_DMA_STREAM, SPIx_RX_DMA_FLAG_TCIF);

    
        if (aRxBuffer[10] == 0xAA)
        {
            //blue & red
            /* Turn ON LED5 and LED6 */
            STM_EVAL_LEDOn(LED5);  
            STM_EVAL_LEDOn(LED6);
        }            
        GPIOE->BSRRL |= GPIO_Pin_7; // set PE7 (CS) high
    }
}
</code>


When I run this code, I do not see the LED's turn on as they do for the
SPI only loopback (I can post that code if necessary).

My understanding of the DMA configuration/operation process isn't
great. Can anyone show me the errors of my ways, or point me to some suitable sample code?

Thanks!

Outcomes