2013-07-10 05:28 AM
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
2013-07-10 07:51 AM
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... JW2013-07-10 08:12 AM
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); } }2013-07-11 01:42 AM
Thanks for sharing your finding.
JW