Skip to main content
abhisheke
Associate II
May 27, 2015
Question

STM32F407 SPI-DMA Continuous Transmit and Receive.

  • May 27, 2015
  • 6 replies
  • 1313 views
Posted on May 27, 2015 at 12:11

Hi,

I am trying to configure the DMA based SPI communication for STM32F407.

STM32F407 is the host controller(master), the slave is CC3100 WiFi module.

I am implementing the DMA for SPI2.

Following is my configuration code:-

static void InitSPI(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

SPI_InitTypeDef SPI_InitStructure;

// Enable peripheral clock

RCC_APB1PeriphClockCmd(WIFI_SPI_CLK, ENABLE);

// CLK pin

RCC_AHB1PeriphClockCmd(WIFI_SPI_CLK_GPIO_CLK, ENABLE);

GPIO_InitStructure.GPIO_Pin = WIFI_SPI_CLK_PIN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

GPIO_InitStructure.GPIO_Speed = WIFI_GPIO_SPEED;

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; // GPIO_PuPd_UP

GPIO_Init(WIFI_SPI_CLK_GPIO_PORT, &GPIO_InitStructure);

GPIO_PinAFConfig(WIFI_SPI_CLK_GPIO_PORT, WIFI_SPI_CLK_SOURCE, WIFI_SPI_CLK_AF);

// MISO pin

RCC_AHB1PeriphClockCmd(WIFI_SPI_MISO_GPIO_CLK, ENABLE);

GPIO_InitStructure.GPIO_Pin = WIFI_SPI_MISO_PIN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

GPIO_InitStructure.GPIO_Speed = WIFI_GPIO_SPEED;

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; // GPIO_PuPd_UP

GPIO_Init(WIFI_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);

GPIO_PinAFConfig(WIFI_SPI_MISO_GPIO_PORT, WIFI_SPI_MISO_SOURCE, WIFI_SPI_MISO_AF);

// MOSI pin

RCC_AHB1PeriphClockCmd(WIFI_SPI_MOSI_GPIO_CLK, ENABLE);

GPIO_InitStructure.GPIO_Pin = WIFI_SPI_MOSI_PIN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

GPIO_InitStructure.GPIO_Speed = WIFI_GPIO_SPEED;

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; // GPIO_PuPd_UP

GPIO_Init(WIFI_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);

GPIO_PinAFConfig(WIFI_SPI_MOSI_GPIO_PORT, WIFI_SPI_MOSI_SOURCE, WIFI_SPI_MOSI_AF);

//

http://www.ti.com/product/CC3100

SPI configuration

SPI_I2S_DeInit(WIFI_SPI);

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; // SPI_CPOL_High

SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; // SPI_CPHA_2Edge

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // SPI_NSS_Hard / SPI_NSSInternalSoft_Set

SPI_InitStructure.SPI_BaudRatePrescaler = WIFI_SPI_BAUDRATE_PRESCALER;

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

SPI_InitStructure.SPI_CRCPolynomial = 7;

SPI_Init(WIFI_SPI, &SPI_InitStructure);

DMA_InitTypeDef DMA_InitStructure;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);

DMA_DeInit(DMA1_Stream4); //SPI1_TX_DMA_STREAM

DMA_DeInit(DMA1_Stream3); //SPI1_RX_DMA_STREAM

//Enabling DMA for SPI

DMA_InitStructure.DMA_BufferSize = WIFI_DMA_SIZE;

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)(&(SPI2->DR));

DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

DMA_InitStructure.DMA_Priority = DMA_Priority_High;

/* Configure Tx DMA */

DMA_InitStructure.DMA_Channel = DMA_Channel_0;

DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) gu8a_INIT_DmaWifiTx;

DMA_Init(DMA1_Stream4, &DMA_InitStructure);

/* Configure Rx DMA */

DMA_InitStructure.DMA_Channel = DMA_Channel_0;

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) gu8a_INIT_DmaWifiRx;

DMA_Init(DMA1_Stream3, &DMA_InitStructure);

DMA_Cmd(DMA1_Stream4, ENABLE); /* Enable the DMA SPI TX Stream */

DMA_Cmd(DMA1_Stream3, ENABLE); /* Enable the DMA SPI RX Stream */

/* Enable the SPI Rx/Tx DMA request */

SPI_I2S_DMACmd(WIFI_SPI, SPI_I2S_DMAReq_Rx, ENABLE);

SPI_I2S_DMACmd(WIFI_SPI, SPI_I2S_DMAReq_Tx, ENABLE);

// Enable SPI2

SPI_Cmd(WIFI_SPI, ENABLE);

}
    This topic has been closed for replies.

    6 replies

    abhisheke
    abhishekeAuthor
    Associate II
    May 29, 2015
    Posted on May 29, 2015 at 10:30

    Further, the slave CC3100 is configured to call the functions sl_IfWrite and sl_IfRead for sending and receiving data.

    The following are the two functions:-

    sl_IfWrite()

    {

        /* SPI in Tramitter mode */

      if (SPI_I2S_GetITStatus(WIFI_SPI, SPI_I2S_IT_TXE) == SET)

      {

        if (WiFiTxIndex < WIFI_DMA_SIZE)

        {

          /* Send Transaction data */

          SPI_I2S_SendData(WIFI_SPI, gu8a_INIT_DmaWifiTx[WiFiTxIndex++]);

        }

        else

        {

            WiFiTxIndex=0;

          /* Disable the Tx buffer empty interrupt */

          SPI_I2S_ITConfig(WIFI_SPI, SPI_I2S_IT_TXE, DISABLE);

        }

    while (DMA_GetFlagStatus(DMA1_Stream4,DMA_FLAG_TCIF4)==RESET);

      /* Clear DMA Transfer Complete Flags */

      //DMA_ClearFlag(DMA1_Stream4,DMA_FLAG_TCIF4);

      }

    }

    sl_IfRead()

    {

      /* SPI in Receiver mode */

      if (SPI_I2S_GetITStatus(WIFI_SPI, SPI_I2S_IT_RXNE) == SET)

      {

        if (WiFiRxIndex < WIFI_DMA_SIZE)

        {

          /* Receive Transaction data */

          gu8a_INIT_DmaWifiRx[WiFiRxIndex++] = SPI_I2S_ReceiveData(WIFI_SPI);

        }

        else

        {

            WiFiRxIndex=0;

          /* Disable the Rx buffer not empty interrupt */

          SPI_I2S_ITConfig(WIFI_SPI, SPI_I2S_IT_RXNE, DISABLE);

        }

    while (DMA_GetFlagStatus(DMA1_Stream3,DMA_FLAG_TCIF3)==RESET);

      /* Clear DMA Transfer Complete Flags */

      //DMA_ClearFlag(DMA1_Stream3,DMA_FLAG_TCIF3);

      }

    }

    But i am unable to achieve the communication.

    Any suggestion would be helpful.

    Regards,

    Abhishek.

    abhisheke
    abhishekeAuthor
    Associate II
    June 1, 2015
    Posted on June 01, 2015 at 07:26

    Hi,

    I tried changing the send and receive functions to achieve DMA data transfer, as follows:-

    sl_IfWrite(int fd, unsigned char* data, unsigned char length)

    {

    WIFI_CS_LOW();

        for (i = 0; i < length; i++)

       {  

          gu8a_WifiTx[i] = data[i];

        }

        WIFI_CS_HIGH();

    }

    sl_IfRead(int fd, unsigned char* data, unsigned char length)

    {

        int i;

        WIFI_CS_LOW();

        for (i = 0; i < length; i++)

        {

          data[i] = gu8a_WifiRx[i];

        }

        WIFI_CS_HIGH();

    }

    and the DMA interrupt handlers:-

    void DMA1_Stream4_IRQHandler()

    {

      unsigned char TXcnt = 0;

      if(DMA_GetITStatus(DMA1_Stream4, DMA_IT_TCIF4) /*||

         DMA_GetITStatus(DMA1_Stream4, DMA_IT_HTIF4)*/)

      {

        TXcnt = DMA_GetCurrDataCounter(DMA1_Stream4);

        while(TXcnt)

        {

          gu8a_INIT_DmaWifiTx[WiFiDMATxIndex]  =  gu8a_WifiTx[WiFiTxIndex];

          WiFiTxIndex++;

          if(WiFiTxIndex >= WIFI_TX_RX_SIZE)

            WiFiTxIndex = 0;

          TXcnt--;

          WiFiDMATxIndex++;

          if(WiFiDMATxIndex == WIFI_DMA_SIZE)

          {

            WiFiDMATxIndex = 0;

          }

        }

        ErrorOnDevice.btCommandError = 0;

        //DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_HTIF4);

        DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TCIF4);

      }

    }

    void DMA1_Stream3_IRQHandler()

    {

         unsigned char RXcnt = 0;

         if(DMA_GetITStatus(DMA1_Stream3, DMA_IT_TCIF3) /*||

            DMA_GetITStatus(DMA1_Stream3, DMA_IT_HTIF3)*/)

         {

              RXcnt = DMA_GetCurrDataCounter(DMA1_Stream3);

              while(RXcnt)

              {

                gu8a_WifiRx[WiFiRxIndex] = gu8a_INIT_DmaWifiRx[WiFiDMARxIndex];

                WiFiRxIndex++;

                if(WiFiRxIndex >= WIFI_TX_RX_SIZE)

                  WiFiRxIndex = 0;

                RXcnt--;

                WiFiDMARxIndex++;

                if(WiFiDMARxIndex == WIFI_DMA_SIZE)

                {

                  WiFiDMARxIndex = 0;

                }

              }

              ErrorOnDevice.btCommandError = 0;

              //DMA_ClearITPendingBit(DMA1_Stream3, DMA_IT_HTIF3);

              DMA_ClearITPendingBit(DMA1_Stream3, DMA_IT_TCIF3);

         }

    }

    In this trial, i am getting both the DMA interrupts only once.

    Still unable to achieve the SPI-DMA communication.

    Please help!!

    Thank you in advance,

    Abhishek.

    waclawek.jan
    Super User
    June 1, 2015
    Posted on June 01, 2015 at 08:40

    You might want to test the communication without DMA, in polled mode, first.

    JW

    abhisheke
    abhishekeAuthor
    Associate II
    June 1, 2015
    Posted on June 01, 2015 at 09:08

    Hi Jan Waclawek,

    Thank you very much for replying.

    Sorry i didn't mention that, but i did check with polled mode.

    It is working when i poll the SPI flags and send data one-by-one.

    But it is not working when i fill the DMA Tx and Rx buffers and poll the DMA Flags.

    Thanks and regards,

    Abhishek.

    abhisheke
    abhishekeAuthor
    Associate II
    June 2, 2015
    Posted on June 02, 2015 at 07:15

    Hi Jan,

    I checked in polled mode.

    I am able to do the communication in polled mode, by polling the TXE and RXNE flags.

    Here are the functions:-

    int SendData(int fd, unsigned char* data, unsigned char length)

    {

        int i;

        WIFI_CS_LOW();

        for (i = 0; i < length; i++)

        {

            SendByte(data[i]);

        }

        WIFI_CS_HIGH();

        return i;

    }

    int ReceiveData(int fd, unsigned char* data, unsigned char length)

    {

        int i;

        WIFI_CS_LOW();

        for (i = 0; i < length; i++) {

            data[i] = SendByte(WIFI_DUMMY_BYTE);

        }

        WIFI_CS_HIGH();

        return i;

    }

    static unsigned char SendByte(unsigned char data)

    {

        unsigned char b = 0;

        int i;

        // Wait until the transmit buffer is empty

        i = 0;

        while (SPI_I2S_GetFlagStatus(WIFI_SPI, SPI_I2S_FLAG_TXE) == RESET)

            i++;

        // Send the byte to the SPI bus

        SPI_I2S_SendData(WIFI_SPI, data);

        // Wait to Read a byte

        i = 0;

        while (SPI_I2S_GetFlagStatus(WIFI_SPI, SPI_I2S_FLAG_RXNE) == RESET)

            i++;

        // Wait until SPI is not busy anymore

        while (SPI_I2S_GetFlagStatus(WIFI_SPI, SPI_I2S_FLAG_BSY) == SET) ;

        // Return the byte read from the SPI bus

        b = SPI_I2S_ReceiveData(WIFI_SPI);

        return b;

    }

    abhisheke
    abhishekeAuthor
    Associate II
    June 2, 2015
    Posted on June 02, 2015 at 09:15

    Hi,

    Let me explain where i am exactly stuck. Probably that will make it easier for you to help me...

    The CC3100 is WIFI chip, connected through SPI interface to my HOST controller STM32F407.

    I am using non-os based environment.

    1)The CC3100 gives an interrupt (external IRQ) to the HOST controller that it is ready to transmit/receive data.

    2)The functions sl_IfWrite and sl_IfRead are called internally.

    3)The sl_IfWrite writes data into the SPI to send to CC3100 and the sl_IfRead reads data on the SPI from the CC3100.

    I have achieved the communication by polling the SPI flags.

    Now, my problem is, i don't want to poll the flags and wait for the SPI transfer to complete.

    I want to achieve this SPI transfer on SPI or DMA interrupt.

    But i am unable to achieve this.

    Maybe you can point me in the right direction now.

    Thanks and regards,

    Abhishek.