STM32F429ZIT SDRAM to SPI using DMA
Hello,
I'm facing a problem with the DMA and FMC. This is my setup:
I'm using a STM32F429ZIT at 180MHz.
I am using the same SDRAM as the STM32F429-DISCOVERY board.
For the HAL configuration, I am using the STM32CubeMX software, version 4.25.
This is what I'm willing to do.
I've got 4081 bytes of data. This data should be clocked out using the SPI module.
In this first situation, the data is stored on the stack on internal memory:
Firstly, I am transmitting 64 'zeros' (needed for my application):
HAL_SPI_Transmit_DMA(&hspi6, zeroBuffer, 64)Then, using the TX complete interrupt, I am starting to transmit a chunk of data:
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi){
//Removed lines for readability
HAL_SPI_Transmit_DMA(hspi, (uint8_t *) datachunkpointer, 4081)
//Removed lines for readability
}This works well.
But!
In another situation my to-be-transmitted data was becomming to big to be stored on the internal memory, so this time, it is stored on the external SDRAM.
I create a buffer with the size of the data on the SDRAM (address 0xC0000000).
This time, the transmit complete callback looks like this:
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi){
//Removed lines for readability
HAL_SPI_Transmit_DMA(hspi, (uint8_t *) getdatachunkpointer(), 4081)
//Removed lines for readability
}It is getting the right pointer (e.g. 0xC0000000).
But the result is not the same as before.
Sometimes this works, like 2 or 3 times, but after that the FEIFx error bit goes high and the DMA is aborted.
My first assumption is a misconfiguration in the DMA.
It is configured like this:
hdma_spi6_tx.Instance = DMA2_Stream5;
hdma_spi6_tx.Init.Channel = DMA_CHANNEL_1;
hdma_spi6_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi6_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi6_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi6_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi6_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi6_tx.Init.Mode = DMA_NORMAL;
hdma_spi6_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi6_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_spi6_tx) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
__HAL_LINKDMA(spiHandle,hdmatx,hdma_spi6_tx);A (not so nice) fix what worked for me was this:
Copying the chunck of data from the SDRAM to the stack, and from there transmitting it using DMA.
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi){
//Removed lines for readability
memcpy((void *)stack_buffer, getdatachunkpointer, 4081);
HAL_SPI_Transmit_DMA(hspi, (uint8_t *) stack_buffer, 4081)
//Removed lines for readability
}The disadvantage of this is that the duration of the memcpy is to long for my application.
I verified the SDRAM connections. I wrote a testprogram using a write/read from and to the stack, but without DMA, and checking the data for errors but found not a single error in about 45000 loops.
Has anybody got any ideas? Or is my DMA Perhaps not right configured?
I never used the FMC before, so a potential misconfiguration is possible.
Thanks for your reply!
Marcel
P.S. The FMC is configured as below:
FMC_SDRAM_TimingTypeDef SdramTiming;
/** Perform the SDRAM1 memory initialization sequence
*/
hsdram1.Instance = FMC_SDRAM_DEVICE;
/* hsdram1.Init */
hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8;
hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2;
hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE;
hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1;
/* SdramTiming */
SdramTiming.LoadToActiveDelay = 16;
SdramTiming.ExitSelfRefreshDelay = 16;
SdramTiming.SelfRefreshTime = 16;
SdramTiming.RowCycleDelay = 16;
SdramTiming.WriteRecoveryTime = 16;
SdramTiming.RPDelay = 16;
SdramTiming.RCDDelay = 16;
if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}