Electrical – STM32F401RE SPI DMA flash driver read/write not working

dmaflashmemoryspistm32f4

I am facing problem with STM32F401RE with SPI flash driver.
I am able to do normal SPI operations like read,write etc…
But I need to use DMA to read and write to FLASH.
/********************************
I am trying to read the data(DMA Methos) from specific address location 0x700000 which was written already.
*********************/

Now I was able to DMA sent sucessfully but on the DMA Receiving buffer it has starting four bytes of NULL data followed by actual Data and last four bytes are missing.

Original: STM32F4xx SPI Firmware Library Example: communication with an S25FL164K SPI FLASH from SPANSION

Receiving : "0x00 0x00 0x00 0x00 STM32F4xx SPI Firmware Library Example: communication with an S25FL164K SPI FLASH from SPAN"

Can some one please suggest why I am getting junk characters like NULL in the first four bytes and why the last four bytes are missing??

Is there any issue issues with clock cycles??
And one more thing I have to clear/read all the data present on "SPI1->DR " before the dma transfer

This is the code..
Please suggest if any issues in the below code

   SPI_InitTypeDef  SPI_InitStructure;
   GPIO_InitTypeDef GPIO_InitStructure;

/*!< Enable the SPI clock */
sFLASH_SPI_CLK_INIT(sFLASH_SPI_CLK, ENABLE);

/*!< Enable GPIO clocks */

/*!< Enable GPIO clocks */
RCC_AHB1PeriphClockCmd(sFLASH_SPI_SCK_GPIO_CLK | sFLASH_SPI_MISO_GPIO_CLK |
                     sFLASH_SPI_MOSI_GPIO_CLK | sFLASH_CS_GPIO_CLK, ENABLE);

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
/*!< SPI pins configuration *************************************************/

/*!< Connect SPI pins to AF5 */
GPIO_PinAFConfig(sFLASH_SPI_SCK_GPIO_PORT, sFLASH_SPI_SCK_SOURCE, sFLASH_SPI_SCK_AF);
GPIO_PinAFConfig(sFLASH_SPI_MISO_GPIO_PORT, sFLASH_SPI_MISO_SOURCE, sFLASH_SPI_MISO_AF);
GPIO_PinAFConfig(sFLASH_SPI_MOSI_GPIO_PORT, sFLASH_SPI_MOSI_SOURCE, sFLASH_SPI_MOSI_AF);
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;

/*!< SPI SCK pin configuration */
GPIO_InitStructure.GPIO_Pin = sFLASH_SPI_SCK_PIN;
GPIO_Init(sFLASH_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);

/*!< SPI MOSI pin configuration */
GPIO_InitStructure.GPIO_Pin =  sFLASH_SPI_MOSI_PIN;
GPIO_Init(sFLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);

/*!< SPI MISO pin configuration */
GPIO_InitStructure.GPIO_Pin =  sFLASH_SPI_MISO_PIN;
GPIO_Init(sFLASH_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);

/*!< Configure sFLASH Card CS pin in output pushpull mode ********************/
GPIO_InitStructure.GPIO_Pin = sFLASH_CS_PIN;
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(sFLASH_CS_GPIO_PORT, &GPIO_InitStructure);

/*!< Deselect the FLASH: Chip Select high */
sFLASH_CS_HIGH();

/*!< SPI configuration */
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_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(sFLASH_SPI, &SPI_InitStructure);
void SPI_DMA_READ(uint8_t* Addref, uint8_t* pRxBuf, uint16_t rx_len)
{
    uint16_t i;

    memset(pTmpBuf1, 0, rx_len + 3);
    memset(pTmpBuf2, 0, rx_len + 3);

      pTmpBuf1[0] = sFLASH_CMD_READ;
    pTmpBuf1[1] = Addref[0];
    pTmpBuf1[2] = Addref[1];
    pTmpBuf1[3] = Addref[2];


  DMA_InitStructure.DMA_BufferSize = (uint16_t)(rx_len);
  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)(&(SPI1->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_3;
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    DMA_InitStructure.DMA_Memory0BaseAddr =(uint32_t)pTmpBuf1;
    DMA_Init(DMA2_Stream3, &DMA_InitStructure);

/* Configure Rx DMA */
    DMA_InitStructure.DMA_Channel = DMA_Channel_3;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_Memory0BaseAddr =(uint32_t)pTmpBuf2;
    DMA_Init(DMA2_Stream2, &DMA_InitStructure);
 #if 1      
      //DMA Interrupt Structure Initialisation
    static NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel =                  DMA2_Stream2_IRQn;//SPI_PORT_DMA_TX_IRQn;
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    //Initialise the Interrupt
NVIC_Init(&NVIC_InitStructure);

// Enable DMA1 channel IRQ Channel */
DMA_ITConfig(DMA2_Stream2, DMA_IT_TC, ENABLE);

 #endif
/* Enable the DMA channel */

   /* Enable the DMA SPI TX Stream */
DMA_Cmd(DMA2_Stream3, ENABLE);
/* Enable the DMA SPI RX Stream */
DMA_Cmd(DMA2_Stream2, ENABLE);

    /* Enable the SPI Rx DMA request */
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);

sFLASH_CS_LOW();

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET)
{}


 SPI_Cmd(SPI1, ENABLE);
    while(trasfer_complete_rx == 0);
memcpy(pRxBuf, pTmpBuf2 ,rx_len);

/*******************************************/
IRQ Handler
/***************************************/

  void DMA2_Stream2_IRQHandler()
  {

if(DMA_GetITStatus(DMA2_Stream2,DMA_IT_TCIF2))
 DMA_ClearITPendingBit(DMA2_Stream2,DMA_IT_TCIF2);

DMA_ClearITPendingBit(DMA2_Stream3,DMA_IT_TCIF3);
DMA_ClearITPendingBit(DMA2_Stream2,DMA_IT_TCIF2);

DMA_Cmd(DMA2_Stream3, DISABLE);
DMA_Cmd(DMA2_Stream2, DISABLE);

SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, DISABLE);
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, DISABLE);

SPI_Cmd(SPI1, DISABLE);
sFLASH_CS_HIGH();
trasfer_complete_rx =1;
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); // Wait for Empty

USART_SendData(USART2,*(pTmpBuf2+2)); // Send 'I'
}

Best Answer

This is for stm32f401re
First the DMA initialization

void init_spi1_dma(void)
{
  DMA_InitTypeDef DMA_InitStructure;
  DMA_StructInit(&DMA_InitStructure);
  //
  // spi1 rx configuration
  //
  DMA_Cmd(DMA2_Stream0, DISABLE);
  while(DMA2_Stream0_BASE & 0x00000001); // wait for disable to take effect
  DMA_DeInit(DMA2_Stream0);
  DMA_InitStructure.DMA_Channel = DMA_Channel_3;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // receive
// tell the DMA where to place the incoming characters
// in this case only one char at a time
// let the interrupt routine sort it out
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dma_rx_buffer;
  DMA_InitStructure.DMA_BufferSize = (char)sizeof(dma_rx_buffer);
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  //
  // the interrupt flags for the DMA Stream:
  // DMA_IT: specifies the DMA interrupt pending bit to clear.
  //          This parameter can be any combination of the following values:
  //            DMA_IT_TCIFx:  Streamx transfer complete interrupt
  //            DMA_IT_HTIFx:  Streamx half transfer complete interrupt
  //            DMA_IT_TEIFx:  Streamx transfer error interrupt
  //            DMA_IT_DMEIFx: Streamx direct mode error interrupt
  //            DMA_IT_FEIFx:  Streamx FIFO error interrupt
  //         Where x can be 0 to 7 to select the DMA Stream.
  DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF2 | DMA_IT_TEIF2 | DMA_IT_HTIF2 | DMA_IT_FEIF2 | DMA_IT_DMEIF2);
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);

// Enable the SPI Rx DMA request
  SPI_DMACmd(SPI1, SPI_DMAReq_Rx, ENABLE);                            
// Enable DMA Stream Transfer Complete interrupt
  DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_TE | DMA_IT_DME, ENABLE);   
// Enable the DMA Rx Stream
  DMA_Cmd(DMA2_Stream0, ENABLE);                                            

}

now the interrupt

//
// dma spi interrupt
//
void init_spi_dma_nvic()
{
  NVIC_InitTypeDef nvic_params;

  //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  nvic_params.NVIC_IRQChannel = DMA2_Stream0_IRQn;
  nvic_params.NVIC_IRQChannelPreemptionPriority = 3;
  nvic_params.NVIC_IRQChannelSubPriority = 0;
  nvic_params.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&nvic_params);
}

//
// spi1 rx dma interrupt
//
void DMA2_Stream0_IRQHandler(void)
{
  static uint16_t i = 0;

  if(rcvd == 0)
    i = 0;

  rcvd++;
  /* Test on DMA Stream Transfer Complete interrupt */
  if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0))
  {
    // place the incoming char away
    rx_buffer[i++] = dma_rx_buffer[0];
    // Clear DMA Stream Transfer Complete interrupt pending bit
    DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);

  }
}

have fun!