cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 Discovery SPI with DMA Ghost byte

muhammaduzairafzal45
Associate III
Posted on July 10, 2013 at 14:28

I want to write a buffer into Winbond SPI flash using SPI DMA. When I write buffer, DMA write a null byte at first location and then start writing my buffer from second location and hence writes one character less than it should write. I donot know from where this null byte is comming. For example when I write ''ALI'' at 0x00 address, Data read from flash is ''<NULL>AL''. Without DMA all works fine. Below is the Code(I have included only necessary functions)

uint8_t TxBuffer1[] = ''ALI'';

&sharpdefine countof(a)   (sizeof(a) / sizeof(*(a)))

&sharpdefine TxBufferSize1   (countof(TxBuffer1)-1)

/**

  * @brief  Initializes the peripherals used by the SPI FLASH driver.

  * @param  None

  * @retval None

  */

void sFLASH_Init(void)

{

  SPI_InitTypeDef  SPI_InitStructure;

  sFLASH_LowLevel_Init();

    

  /*!< 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_High;// also works at SPI_CPOL_Low with SPI_CPHA_1Edge

  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft ;

  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;//(APB1/2=21MHz SPI Clock)

  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

  SPI_InitStructure.SPI_CRCPolynomial = 7;

  SPI_Init(sFLASH_SPI, &SPI_InitStructure);

  /*!< Enable the sFLASH_SPI  */

  SPI_Cmd(sFLASH_SPI, ENABLE);

}

/**

  * @brief  Writes more than one byte to the FLASH with a single WRITE cycle 

  *         (Page WRITE sequence).

  * @note   The number of byte can't exceed the FLASH page size.

  * @param  pBuffer: pointer to the buffer  containing the data to be written

  *         to the FLASH.

  * @param  WriteAddr: FLASH's internal address to write to.

  * @param  NumByteToWrite: number of bytes to write to the FLASH, must be equal

  *         or less than ''sFLASH_PAGESIZE'' value.

  * @retval None

  */

void sFLASH_DMA_WritePage(uint32_t WriteAddr)

{

  /*!< Enable the write access to the FLASH */

  sFLASH_WriteEnable();

  /*!< Select the FLASH: Chip Select low */

  sFLASH_CS_LOW();

  /*!< Send ''Write to Memory '' instruction */

  sFLASH_SendByte(sFLASH_CMD_WR_PAGE);

  /*!< Send WriteAddr high nibble address byte to write to */

  sFLASH_SendByte((WriteAddr & 0xFF0000) >> 16);

  /*!< Send WriteAddr medium nibble address byte to write to */

  sFLASH_SendByte((WriteAddr & 0xFF00) >> 8);

  /*!< Send WriteAddr low nibble address byte to write to */

  sFLASH_SendByte(WriteAddr & 0xFF);

  while (SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_TXE) == RESET);

  /*!< while there is data to be written on the FLASH */

  DMA_Cmd(DMA1_Stream4, ENABLE);

}

/**

  * @brief  Sends a byte through the SPI interface and return the byte received

  *         from the SPI bus.

  * @param  byte: byte to send.

  * @retval The value of the received byte.

  */

uint8_t sFLASH_SendByte(uint8_t byte)

{

  /*!< Loop while DR register in not emplty */

  while (SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_TXE) == RESET);

  /*!< Send byte through the SPI1 peripheral */

  SPI_I2S_SendData(sFLASH_SPI, byte);

  /*!< Wait to receive a byte */

  while (SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_RXNE) == RESET);

  /*!< Return the byte read from the SPI bus */

  return SPI_I2S_ReceiveData(sFLASH_SPI);

}

/**

  * @brief  Configures the DMA.

  * @param  None

  * @retval None

  */

void DMA_Configuration(void)

{

/* SPI2_Tx   DMA1_Channel0_Stream4 */

/* DMA clock enable */

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

DMA_DeInit(DMA1_Stream4);

  DMA_InitStructure.DMA_Channel = DMA_Channel_0;  

  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR;

  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)TxBuffer1;

  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;

  DMA_InitStructure.DMA_BufferSize = TxBufferSize1;

  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_Normal;

  DMA_InitStructure.DMA_Priority = DMA_Priority_High;

  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;         

  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;

  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

     

  DMA_Init(DMA1_Stream4, &DMA_InitStructure); 

  DMA_ITConfig(DMA1_Stream4, DMA_IT_TC, ENABLE);

  

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

 

  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

}

void DMA1_Stream4_IRQHandler(void)

{

  /* Test on DMA Stream Transfer Complete interrupt */

  if (DMA_GetITStatus(DMA1_Stream4, DMA_IT_TCIF4))

  {

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

    DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TCIF4);

sFLASH_CS_HIGH();

sFLASH_WaitForWriteEnd();

while(SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_TXE) == RESET);

while(SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_BSY) == SET);

/*!< while there is data to be written on the FLASH */

DMA_Cmd(DMA1_Stream4, DISABLE);

    

  }

}

int main(void)

{   

  // Configure the DMA 

  DMA_Configuration();

  // Enable SPI DMA TX request 

  SPI_I2S_DMACmd(sFLASH_SPI,SPI_I2S_DMAReq_Tx, ENABLE);

  sFLASH_Erase4KB_32KB_64KB_Chip(0x00,sFLASH_CMD_ER_SECTOR_4KB);

  sFLASH_DMA_WritePage(0x00);

  /* Read data from SPI FLASH memory */

  sFLASH_ReadBuffer(Read_Buf1, 0x00, TxBufferSize1);

  for (Index = 0; Index < TxBufferSize1; Index++)

  {

USART1_Put(Read_Buf1[Index]);

  }

 while (1);

}

#spi-dma-stm32
3 REPLIES 3
Posted on July 10, 2013 at 16:51

I am lazy to go through your code to find out whether this is the case here, but the DMA appears to ''remember'' the input stimulus (here the SPI's RXNE being set) even if it is disabled.

https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a%2f%2fmy.st.com%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex_mx_stm32%2fHow%20to%20clear%20pending%20DMA%20request&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD065...

JW

muhammaduzairafzal45
Associate III
Posted on July 10, 2013 at 17:12

Ok solved the problem. It turned out that SPI->DR register has to be read after DMA transfer completes. Below is the changed code and ISR:

void sFLASH_DMA_WritePage(uint32_t WriteAddr)

{    

    

  /*!< Enable the write access to the FLASH */

  sFLASH_WriteEnable();

  /*!< Select the FLASH: Chip Select low */

  sFLASH_CS_LOW();

  /*!< Send ''Write to Memory '' instruction */

  sFLASH_SendByte(sFLASH_CMD_WR_PAGE);

  /*!< Send WriteAddr high nibble address byte to write to */

  sFLASH_SendByte((WriteAddr & 0xFF0000) >> 16);

  /*!< Send WriteAddr medium nibble address byte to write to */

  sFLASH_SendByte((WriteAddr & 0xFF00) >> 8);

  /*!< Send WriteAddr low nibble address byte to write to */

  sFLASH_SendByte(WriteAddr & 0xFF);

    

  DMA_Cmd(DMA1_Stream4, ENABLE);

}

void DMA1_Stream4_IRQHandler(void)

{

    uint16_t temp=0;

  /* Test on DMA Stream Transfer Complete interrupt */

  if (DMA_GetITStatus(DMA1_Stream4, DMA_IT_TCIF4))

  {

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

    DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TCIF4);

        /*!< Disable DMA */

        DMA_Cmd(DMA1_Stream4, DISABLE);

        Delay(0x1);//This Delay is necessary

        /*!< Deselect the FLASH: Chip Select high */

        sFLASH_CS_HIGH();

        /*!< Check If SPI Transmission is complete i.e; DR register is empty */

        while(SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_TXE) == RESET);

        /*!< Check If SPI bus is free i.e; DR shift register is shifted out completely */

        while(SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_BSY) == SET);

        /*!< Read out DR register to clear it */

        temp=(sFLASH_SPI->DR);

  }

}

Posted on July 11, 2013 at 10:42

Thanks for sharing your finding.

JW