Skip to main content
zdravko
Associate III
August 1, 2017
Question

Can't receive over duplex SPI with DMA

  • August 1, 2017
  • 4 replies
  • 1635 views
Posted on August 01, 2017 at 16:39

I'm trying to communicate with AD5750 over the SPI. It requires full duplex SPI, where according to the timing diagram on page 9 of 36 in the data sheet, AD5750 is a slave SPI device, which is responding to a command with a readback. I wan't to fetch this readback and I'm able to poll it. However I would like to use the DMA so that I'm not loosing any time for waiting the communication to finish. The problem is that though I'm able to transmit data over the DMA, I'm not able to receive it, because RXEN flag is never set. Here is my initialization code:

static void SPI_Config(void) {

    GPIO_InitTypeDef GPIO_InitStructure;

    SPI_InitTypeDef  SPI_InitStructure;

    DMA_InitTypeDef DMA_Init_Structure;

    NVIC_InitTypeDef NVIC_InitStructure;

//     NVIC_InitTypeDef NVIC_InitStructure;

    

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    /* Connect SPI pins to AF5 */

  //     GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1); //SS

  GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1); //SCK   

  GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1); //MISO

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1); //MOSI

    

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_DOWN;

    

    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_5; //SCK

  GPIO_Init(GPIOA, &GPIO_InitStructure);

    

    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6; //MISO

  GPIO_Init(GPIOA, &GPIO_InitStructure);

    

    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_7; //MOSI

  GPIO_Init(GPIOA, &GPIO_InitStructure);

    

    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4; //SS

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

    

    //SPI Configuration

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);

    SPI_I2S_DeInit(SPI1);

    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;

    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //AD5620 doku page 18 falling edge of SCLK

    SPI_InitStructure.SPI_CRCPolynomial = 0; //x_8+x_2+x_1+1 in python hex(2**8+2**2+2+1)

    SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; //AD5620 input register is 16 bit

    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

    SPI_Init(SPI1, &SPI_InitStructure);

    

    //DMA Globul Interrupt

    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream2_IRQn;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

    

    //DMA Globul Interrupt

    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream2_IRQn;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

    

    //DMA Configuration

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

    DMA_DeInit(DMA2_Stream3);

    DMA_DeInit(DMA2_Stream2);

    

    DMA_Init_Structure.DMA_BufferSize = 1;

    

    DMA_Init_Structure.DMA_FIFOMode = DMA_FIFOMode_Disable;

    DMA_Init_Structure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;

    DMA_Init_Structure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

    DMA_Init_Structure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

    DMA_Init_Structure.DMA_MemoryInc = DMA_MemoryInc_Disable;

    DMA_Init_Structure.DMA_Mode = DMA_Mode_Normal;

    DMA_Init_Structure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

    DMA_Init_Structure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

    DMA_Init_Structure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_Init_Structure.DMA_Priority = DMA_Priority_High;

    

    //Configure Tx DMA

    DMA_Init_Structure.DMA_Channel = DMA_Channel_3;

    DMA_Init_Structure.DMA_Memory0BaseAddr = (uint32_t)(&spi_tx_val);

    DMA_Init_Structure.DMA_PeripheralBaseAddr = (uint32_t) (&(SPI1->DR));

    DMA_Init_Structure.DMA_DIR = DMA_DIR_MemoryToPeripheral;

    DMA_Cmd(DMA2_Stream3, DISABLE);

    while (DMA2_Stream3->CR & DMA_SxCR_EN);

    DMA_Init(DMA2_Stream3,&DMA_Init_Structure);

    

    //Configure Rx DMA

    DMA_Init_Structure.DMA_Channel = DMA_Channel_3;

    DMA_Init_Structure.DMA_Memory0BaseAddr = (uint32_t)(&spi_rx_val);

    DMA_Init_Structure.DMA_PeripheralBaseAddr = (uint32_t) (&(SPI1->DR));

    DMA_Init_Structure.DMA_DIR = DMA_DIR_PeripheralToMemory;

    DMA_Cmd(DMA2_Stream2, DISABLE);

    while (DMA2_Stream2->CR & DMA_SxCR_EN);

    DMA_Init(DMA2_Stream2,&DMA_Init_Structure);

    

//     DMA_ITConfig(DMA2_Stream3,DMA_IT_TC,ENABLE);

    DMA_ClearFlag(DMA2_Stream3, DMA_FLAG_FEIF3|DMA_FLAG_DMEIF3|DMA_FLAG_TEIF3|DMA_FLAG_HTIF3|DMA_FLAG_TCIF3);

    DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_FEIF2|DMA_FLAG_DMEIF2|DMA_FLAG_TEIF2|DMA_FLAG_HTIF2|DMA_FLAG_TCIF2);

    

    DMA_Cmd(DMA2_Stream3, ENABLE); //DMA SPI TX stream

    DMA_Cmd(DMA2_Stream2, ENABLE); //DMA SPI RX stream

    

    

//     SPI_SSOutputCmd(SPI1, ENABLE);

//     SPI_NSSInternalSoftwareConfig(SPI1,SPI_NSSInternalSoft_Set);

    SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx, ENABLE);

    SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Rx, ENABLE);

    SPI_Cmd(SPI1, ENABLE);

    

}

I have a breakpoint at DMA2_Stream3_IRQHandler which is never triggered. Why is the RXEN flag never set? It should be set after the last SCLK front.  Should I use the SPI_SSOutputCmd()? I've tried it both ways, but neither is working.

    This topic has been closed for replies.

    4 replies

    Vangelis Fortounas
    Associate II
    August 1, 2017
    Posted on August 01, 2017 at 17:17

    Hello!

    At your NVIC initialization , you initialised twice the stream 2 interrupts.(not stream 3)

    Please, provide more details about your hardware to encourage the community to help you.

    zdravko
    zdravkoAuthor
    Associate III
    August 1, 2017
    Posted on August 01, 2017 at 17:26

    Yes. I'm sorry about that. The microcontroller ist smt32f405.

    Vangelis Fortounas
    Associate II
    August 1, 2017
    Posted on August 01, 2017 at 17:29

    So rxdma must be channel 0 or 2?

    zdravko
    zdravkoAuthor
    Associate III
    August 1, 2017
    Posted on August 01, 2017 at 17:39

    So here is the latest code I'm trying and it's not working on stm32f405

    static void SPI_Config(void) {

        GPIO_InitTypeDef GPIO_InitStructure;

        SPI_InitTypeDef  SPI_InitStructure;

        DMA_InitTypeDef DMA_Init_Structure;

        NVIC_InitTypeDef NVIC_InitStructure;

    //     NVIC_InitTypeDef NVIC_InitStructure;

        

        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

        /* Connect SPI pins to AF5 */

      //     GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1); //SS

      GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1); //SCK   

      GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1); //MISO

        GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1); //MOSI

        

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

      GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_DOWN;

        

        GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_5; //SCK

      GPIO_Init(GPIOA, &GPIO_InitStructure);

        

        GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6; //MISO

      GPIO_Init(GPIOA, &GPIO_InitStructure);

        

        GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_7; //MOSI

      GPIO_Init(GPIOA, &GPIO_InitStructure);

        

        GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4; //SS

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

      GPIO_Init(GPIOA, &GPIO_InitStructure);

        

        //SPI Configuration

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);

        SPI_I2S_DeInit(SPI1);

        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;

        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

        SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //AD5620 doku page 18 falling edge of SCLK

        SPI_InitStructure.SPI_CRCPolynomial = 0; //x_8+x_2+x_1+1 in python hex(2**8+2**2+2+1)

        SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; //AD5620 input register is 16 bit

        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

        SPI_Init(SPI1, &SPI_InitStructure);

        

        //DMA Globul Interrupt

        NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream3_IRQn;

      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;

      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;

      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

      NVIC_Init(&NVIC_InitStructure);

        //DMA Globul Interrupt

        NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream2_IRQn;

      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;

      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;

      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

      NVIC_Init(&NVIC_InitStructure);

        

        //DMA Configuration

        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

        DMA_DeInit(DMA2_Stream3);

        DMA_DeInit(DMA2_Stream2);

        

        DMA_Init_Structure.DMA_BufferSize = 1;

        

        DMA_Init_Structure.DMA_FIFOMode = DMA_FIFOMode_Disable;

        DMA_Init_Structure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;

        DMA_Init_Structure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

        DMA_Init_Structure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

        DMA_Init_Structure.DMA_MemoryInc = DMA_MemoryInc_Disable;

        DMA_Init_Structure.DMA_Mode = DMA_Mode_Normal;

        DMA_Init_Structure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

        DMA_Init_Structure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

        DMA_Init_Structure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

        DMA_Init_Structure.DMA_Priority = DMA_Priority_High;

        

        //Configure Tx DMA

        DMA_Init_Structure.DMA_Channel = DMA_Channel_3;

        DMA_Init_Structure.DMA_Memory0BaseAddr = (uint32_t)(&spi_tx_val);

        DMA_Init_Structure.DMA_PeripheralBaseAddr = (uint32_t) (&(SPI1->DR));

        DMA_Init_Structure.DMA_DIR = DMA_DIR_MemoryToPeripheral;

        DMA_Cmd(DMA2_Stream3, DISABLE);

        while (DMA2_Stream3->CR & DMA_SxCR_EN);

        DMA_Init(DMA2_Stream3,&DMA_Init_Structure);

        

        //Configure Rx DMA

        DMA_Init_Structure.DMA_Channel = DMA_Channel_3;

        DMA_Init_Structure.DMA_Memory0BaseAddr = (uint32_t)(&spi_rx_val);

        DMA_Init_Structure.DMA_PeripheralBaseAddr = (uint32_t) (&(SPI1->DR));

        DMA_Init_Structure.DMA_DIR = DMA_DIR_PeripheralToMemory;

        DMA_Cmd(DMA2_Stream2, DISABLE);

        while (DMA2_Stream2->CR & DMA_SxCR_EN);

        DMA_Init(DMA2_Stream2,&DMA_Init_Structure);

        

    //     DMA_ITConfig(DMA2_Stream3,DMA_IT_TC,ENABLE);

        DMA_ClearFlag(DMA2_Stream3, DMA_FLAG_FEIF3|DMA_FLAG_DMEIF3|DMA_FLAG_TEIF3|DMA_FLAG_HTIF3|DMA_FLAG_TCIF3);

    //     DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_FEIF2|DMA_FLAG_DMEIF2|DMA_FLAG_TEIF2|DMA_FLAG_HTIF2|DMA_FLAG_TCIF2);

        

        DMA_Cmd(DMA2_Stream3, ENABLE); //DMA SPI TX stream

        DMA_Cmd(DMA2_Stream2, ENABLE); //DMA SPI RX stream

        

        

    //     SPI_SSOutputCmd(SPI1, ENABLE);

    //     SPI_NSSInternalSoftwareConfig(SPI1,SPI_NSSInternalSoft_Set);

        SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx, ENABLE);

        SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Rx, ENABLE);

        SPI_Cmd(SPI1, ENABLE);

        

    }

    void DMA2_Stream2_IRQHandler(void)  

    {

      /* Test on DMA Stream Transfer Complete interrupt */

      if(DMA_GetITStatus(DMA2_Stream2, DMA_IT_TCIF2))

      {

        /* Clear DMA Stream Transfer Complete interrupt pending bit */

        DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2);

            

      }

    }

    And I have a breakpoint at DMA2_Stream2_IRQHandler which never triggers, because the RXNE flag is never 1. I assume so because I can't seen it with the debugger.

    Tesla DeLorean
    Guru
    August 1, 2017
    Posted on August 01, 2017 at 17:50

    DMA_ITConfig(DMA2_Stream2, DMA_IT_TC,ENABLE); // You enable it for Stream 2 ?

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    waclawek.jan
    Super User
    August 1, 2017
    Posted on August 01, 2017 at 17:53

    //     SPI_NSSInternalSoftwareConfig(SPI1,SPI_NSSInternalSoft_Set);

    Why did you comment it out? Do you understand the implications of

     SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

    ?

    JW

    zdravko
    zdravkoAuthor
    Associate III
    August 2, 2017
    Posted on August 02, 2017 at 09:45

    My understanding is that SPI_NSS_Soft configure the chip select signal to be controlled by the software. I don't know why SPI_NSSInternalSoftwareConfig(SPI1,SPI_NSSInternalSoft_Set); is needed, because I see no difference when I comment it.

    FORTOUNAS.EVANGELOS

    DMA_ITConfig(DMA2_Stream2, DMA_IT_TC,ENABLE);

    make the breakpoint in the DMA2_Stream2_IRQHandler be triggered in the beginning and then no more. Even though if I try to pull a message with

    if(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE)==SET)

    SPI_I2S_ReceiveData(SPI1);

    It's working.