AnsweredAssumed Answered

Can't receive over duplex SPI with DMA

Question asked by georgiev.zdravko on Aug 1, 2017
Latest reply on Aug 2, 2017 by georgiev.zdravko

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.

Outcomes