cancel
Showing results for 
Search instead for 
Did you mean: 

Can't receive over duplex SPI with DMA

zdravko
Associate II
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.

9 REPLIES 9
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
Associate II
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.

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
Up vote any posts that you find helpful, it shows what's working..
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

Posted on August 01, 2017 at 17:26

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

Posted on August 01, 2017 at 17:29

So rxdma must be channel 0 or 2?

Posted on August 01, 2017 at 17:34

It should be channel 2. Why do you thing it should be 0?

Posted on August 01, 2017 at 17:35

I meant channel 3 DMA_Channel_3, DMA is 2.

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.