cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F429ZIT SDRAM to SPI using DMA

Mvan.13
Associate II

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__);
  }

7 REPLIES 7

> hdma_spi6_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

[...]

> Sometimes this works, like 2 or 3 times, but after that the FEIFx error bit goes high and the DMA is aborted.

As you don't use FIFO, you can ignore FIFO errors. Don't enable the FIFO error in DMA.

I don't Cube.

JW

S.Ma
Principal

Why not use a DMA for memory to memory transfer if the number of data to transfer is big?

Mvan.13
Associate II

@Community member​ 

I do disable FIFO but the error does keep coming back.

@S.Ma​ 

So you are proposing to use a DMA to transfer the data from the external SDRAM to internal memory and start a DMA transfer from the internal memory to the SPI module?

> I do disable FIFO but the error does keep coming back.

Ignore the error. Or, better, don't enable the FIFO error interrupt.

JW

Mvan.13
Associate II

@Community member​ 

We fixed using by editing the HAL. From I2C HAL error we found out that the FE error bit is ignored. Our HAL SPI DMA error callback now looks like this

/**
  * @brief  DMA SPI communication error callback.
  * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
  *               the configuration information for the specified DMA module.
  * @retval None
  */
static void SPI_DMAError(DMA_HandleTypeDef *hdma)
{
  SPI_HandleTypeDef* hspi = (SPI_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
	if(HAL_DMA_GetError(hdma) != HAL_DMA_ERROR_FE)
  {
		/* Stop the disable DMA transfer on SPI side */
			CLEAR_BIT(hspi->Instance->CR2, SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN);
 
			SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA);
			hspi->State = HAL_SPI_STATE_READY;
			HAL_SPI_ErrorCallback(hspi);
	}
}

The problem looks solved. I don't know if this is OK to do, but if not I would like to know how it should be done. Also, why is this solution already implemented with I2C but not with SPI in the HAL?

Anyway we can use our SDRAM, thanks for your help!

Yes, at least can help pinpoint the issue roots

DWhit.1
Associate II

Looks great! Looking at 1st STM32 board and was among many thing impressed by the ones that sold with SRAM extension underneath the board.

I assume with these can just solder a compatible chip in and then all you have to do is configure the board to use it.

Unless I am wrong... seemed can get 1MB chips for < $10 which seems too good to be true.

Also, for me it seems promising as I'm in need of SPI with DMA as my device library would prefer native DMA underneath.