This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Interfacing CC3100 to host controller through SPI-DMA

Other Parts Discussed in Thread: CC3100, CC3200

Hi,

I have interfaced the CC3100 to my host controller STM32F407. The interfacing is discussed in the link:-

Now, I want to communicate with the CC3100 through SPI-DMA.

Is it possible to implement DMA based SPI communication with CC3100 ??

Please provide any links on how to achieve the same.

Thanks and regards,

Abhishek.

  • Hi Abhishek,

    Yes, it is possible. Please take a look at the port available for CC3100 with MSP430F5529LP. The implementation under 'ENABLE_DMA' flag (in spi.c) is used for this purpose.

    Regards,
    Raghavendra

  • Hi Raghavendra,
    Thank you very much for replying.
    I will go through the DMA implementation and reply back.

    Regards,
    Abhishek.
  • Hi Raghavendra,
    I went through the MSP430F5529LP code.
    I have implemented SPI based DMA to communicate with CC3100.
    Here's my initialization...

    static void WiFiDvr_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);

    // 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 SPI1
    SPI_Cmd(WIFI_SPI, ENABLE);

    NVIC_InitTypeDef NVIC_InitStructure;
    /* Enable the SPI-WiFi Interrupt */

    NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);


    /* Enable the DMA Receive Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);


    /* Enable the DMA Transmit Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    }

    /*CC3100 interrupt handler*/
    void WiFiDvr_IRQHandler(void)
    {
    if (pIrqEvtHdlr) {
    pIrqEvtHdlr(NULL);
    }
    }

    I have written the SPI and DMA interrupts and put breakpoints in them. But execution doesn't reach the breakpoints.

    Is there anything that i am missing out.

    Please reply.

    Warm regards,
    Abhishek.
  • Hi Abhishek,

    I would suggest you to post the platform specific queries on the respective MCUs forum.

    Regards,
    Raghavendra
  • Hi Raghavendra,
    Atleast, can you please explain me how the DMA is configured for MSP430F5529LP ??
    Are both the SPI as well as DMA interrupts implemented or only one of them is implemented ??

    I tried to see the flow for sending and receiving data in spi.c for MSP430F5529LP.
    What do the functions spi_Write, spi_Read, void SetupDMAReceive(unsigned char *ucBuff,int len)
    and void SetupDMASend(unsigned char *ucBuff,int len) exactly do ??

    Please reply as I might be able to configure my host controller if i find some answers.

    Thank you,
    Abhishek.

  • Hi Raghavendra,

    I am still stuck-up with my problem.

    Any inputs from your side ??

    Regards,

    Abhishek.

  • Hi Abhishek,

    Neither of interrupt handler implemented. It is based on CPU-mode.

    In non-DMA case spi_read and spi_write read and write data to/from register in while loop.

    In DMA case spi_read and spi_write call SetupDMAReceive amd SetupDMASend. These two DMA function configure DMA for requested length and for other params and wait in loop until DMA complete(continuously checking interrupt flag register, rather than handling in interrupt).

    Regards,

    Aashish

  • Hi Aashish,
    Thank you for the explanation.
    So the application is non-DMA.
    But i want to implement both the transmit and receive for CC3100 using DMA transfer.
    Can you provide any example/steps on how to achieve that ??

    Regards,
    Abhishek.
  • Hi Abhishek,


    Application is DMA based(ENABLE_DMA). We are not using interrupt handler to indicate transaction completed rather we continuously checking interrupt register whether DMA completed or not. So in real data transfer in DMA mode.

    In DMA case CPU-mode means was waiting for DMA completion not DMA transfer. 

    Regards,
    Aashish

  • Hi Aashish,
    Can you please tell me step-by-step how the "So in real data transfer in DMA mode" is done in the MSP430F5529LP platform, so i can implement the same steps in my host controller.
    Please reply.

    Regards,
    Abhishek.
  • HI Abhishek,

    Below is explanation for DMA send:

     

    DMA0 use for copy data from RAM to SPI

    DMA 1 use for copy dummy data from SPI to RAM

     

    code with explanation:

      UCB0IFG &= ~UCTXIFG;  // We are clearing interrupt

       __data16_write_addr((unsigned short) &DMA0SA,(unsigned long) ucBuff); //configuring source buffer in this case  ucBuff (RAM) as source

       __data16_write_addr((unsigned short) &DMA0DA,(unsigned long) &UCB0TXBUF); //configuring destination buffer in this case SPI register/hardware buffer (UCB0TXBUF) as detination

       DMA0SZ = len;                           /* Configuring how many bytes need to transfer using DMA */

       DMA0CTL = DMADT_0 + DMASRCINCR_3 + DMASBDB + DMAEN + DMALEVEL; /* Enabling DMA, configuring source increments and word size

       __data16_write_addr((unsigned short) &DMA1SA,(unsigned long) &UCB0RXBUF); //Configuring dummy read as SPI generally RW combination. Configuring SPI hardware rx buffer as source

       __data16_write_addr((unsigned short) &DMA1DA,(unsigned long) &g_ucDinDout[5]); //configuring dummy read. Configuring g_ucDinDout (RAM) as destnation

       DMA1SZ = len;                             /* Number of dummy bytes to read*/

       DMA1CTL = DMADT_0 + DMADSTINCR_0 + DMASBDB + DMALEVEL + DMAEN; /* Enabling DMA for dummt read, configuring source increments and word size

       /* Signal to start xfer */

       UCB0IFG |=  UCTXIFG; //Trigirring or enabling DMA0 Transfer

       

       while(!(DMA0CTL&DMAIFG) || !(DMA1CTL&DMAIFG)); /* Wait for completation interrupt */

     

    same way DMA recieve implemented.

     

     

    Regards,

    Aashish

  • Hi Aashish,
    Thank you very much for such detailed explanation.
    I will implement the same and get back.

    Thank you very much,
    Abhishek.
  • Hi Aashish,

    Can you also please explain the condition if( len > DMA_BUFF_SIZE_MIN && ((pBuffAddr % 2 == 0))) from spi_Write ??

    If this condition is false, the code executes:-

            len_to_return = len;
            while (len)
            {
                while (!(UCB0IFG&UCTXIFG));
                UCB0TXBUF = *pBuff;
                while (!(UCB0IFG&UCRXIFG));
                UCB0RXBUF;
                len --;
                pBuff++;
            }

    Please explain these lines.

    Regards,

    Abhishek.

  • Hi Abhishek,

    We do DMA only in case of more than 100bytes as there is no advantage of doing DMA for less than 100 bytes because of overhead. So if bytes need to copy/transfer is less than 100 bytes we do normal CPU-mode to copy/transfer else use DMA.


    Regards,
    Aashish
  • Hi Aashish,
    Thank you for the explanation.
    Also, which flags are you using for clearing, triggering and completion of interrupts ??
    Are these USART flags or DMA flags ??
    1)UCB0IFG &= ~UCTXIFG; // We are clearing interrupt
    2)UCB0IFG |= UCTXIFG; //Trigirring or enabling DMA0 Transfer
    3) while(!(DMA0CTL&DMAIFG) || !(DMA1CTL&DMAIFG)); /* Wait for completation interrupt */

    Also, does the length of data to be transferred through DMA change for each transfer ??
    i.e. DMA0SZ = len; /* Configuring how many bytes need to transfer using DMA */
    and DMA1SZ = len; /* Number of dummy bytes to read

    Please reply.

    Thank you very much,
    Abhishek.
  • Hi Aashish,
    I followed the same steps explained by you and wrote the DMA functions of MSP430F5529LP analogous to my host controller.
    But it doesn't work.

    Regards,
    Abhishek.
  • Hi Aashish,
    Can you provide any steps or example code which communicates with the CC3100 through SPI-DMA(not UART) ??
    So that i can follow them to modify my code accordingly.

    Thanks,
    Abhishek.
  • Hi,

    I am still unable to achieve the SPI-DMA communication with CC3100!!

    Is it mandatory to poll the DMA flags to check data transfer in case of CC3100 ??

    Can't we use DMA vectored interrupt handlers to achieve communication with CC3100 ??

    Please reply.

    Regards,

    Abhishek.

  • Hi,
    I mean to say that is it mandatory to send the initialization sequence (0x65, 0x87, 0x78,0x56...) one-by-one to the CC3100 ??
    Because, the MSP430F5529LP platform code uses DMA transfer only if the number of bytes is more than 100. Else it send the bytes one-by-one by writing them into the UART register.

    Please reply.

    Regards,
    Abhishek.
  • Hi,

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

    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.

    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.

  • Hi Aashish,

    I couldn't configure the interrupts and have decided to follow the MSP430F5529LP platform's dma implementation.

    Now, as you explained from the code, the MSP platform does dma transfer only when data size > 100 bytes and polls the DMA transfer complete flags.
    Else it writes data bytes directly into the UART data register and polls the UART transfer complete flags.
    So, at a time, either DMA transfer or direct UART transfer is going on.

    I have some questions regarding the MSP platform code:-
    Referring to the spi.c file of MSP430F5529LP platform from CC3100 SDK,

    1. In case of DMA transfer, does the BLOCK SIZE change for every transfer ??
    eg: DMA0SZ = len; /* Block size */
    DMA1SZ = len; /* Block size */

    2. From the code, the DMA is configured for each data transfer.
    eg: DMA0CTL = DMADT_0 + DMASRCINCR_3 + DMASBDB + DMAEN + DMALEVEL;
    Doesn't this consume too much execution time ??
    Why isn't the DMA configured only once, and after that, for each transfer, the data only loaded into the dma ??

    3. What is the use of g_ucDinDout[5] ?? Why only 5 bytes are used in SetupDMASend and 10 bytes in SetupDMAReceive ??

    Please answer.

    Thank you in advance,
    Abhishek.
  • Hi,
    Any suggestions regarding the above MSP430F5529LP related questions ??
    I am still stuck with my application, and any suggestions might help me reach a final conclusion.

    Warm regards,
    Abhishek.
  • Hi,

    I managed to find answers to my questions.

    1) Yes, the block size changes for every transfer for transfers greater than 100 bytes. For transfer less than 100 bytes, the normal UART transfer is used.

    2) The DMA transfer is configured every-time because the DMA transfer size may not be the same for every transfer.

    3) g_ucDinDout is a dummy data buffer.

    Thank you for all answers and suggestions. Really helped me with my development.

    I have some other doubts regarding CC3200 DMA implementation which i will post in another thread.

    Warm regards,

    Abhishek.