Skip to main content
CDew.1
Associate III
February 25, 2020
Solved

Can the STM32H743's FMC drive a 16-bit 8080 bus faster than 1.6MHz when clocked at 480MHz?

  • February 25, 2020
  • 5 replies
  • 3219 views

I'm using the FMC of the STM32H743 to drive a 16-bit 8080-bus LCD controller.

I've tried using DMA, MDMA and a CPU-loop to transfer data to the 8080-bus, via the FMC.

The transfer frequency does not depend on whether DMA, MDMA or CPU-loop is used. This make me think that the DMA/MDMA/CPU-loop is not the limiting factor.

At a 480MHz FMC clock, the transfer happens at just 1.6MHz, giving me only 20fps on a 16-bit colour 320x240 LCD.

At a 240MHz FMC clock, the transfer happens at just 0.8MHz, and so on at slower speeds.

I've also tried reducing the various setup and hold times to 1 and 0 cycles, but this has (surprisingly) not affected the waveform on the 8080-bus.

My (Cube-MX generated) FMC initialisation code is:

 
/* FMC initialization function */
static void MX_FMC_Init(void)
{
 
 /* USER CODE BEGIN FMC_Init 0 */
 
 /* USER CODE END FMC_Init 0 */
 
 FMC_NORSRAM_TimingTypeDef Timing = {0};
 FMC_NORSRAM_TimingTypeDef ExtTiming = {0};
 
 /* USER CODE BEGIN FMC_Init 1 */
 
 /* USER CODE END FMC_Init 1 */
 
 /** Perform the SRAM1 memory initialization sequence
 */
 hsram1.Instance = FMC_NORSRAM_DEVICE;
 hsram1.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
 /* hsram1.Init */
 hsram1.Init.NSBank = FMC_NORSRAM_BANK2;
 hsram1.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
 hsram1.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
 hsram1.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16;
 hsram1.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE;
 hsram1.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;
 hsram1.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
 hsram1.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
 hsram1.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
 hsram1.Init.ExtendedMode = FMC_EXTENDED_MODE_ENABLE;
 hsram1.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
 hsram1.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
 hsram1.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
 hsram1.Init.WriteFifo = FMC_WRITE_FIFO_DISABLE;
 hsram1.Init.PageSize = FMC_PAGE_SIZE_NONE;
 /* Timing */
 Timing.AddressSetupTime = 3;
 Timing.AddressHoldTime = 15;
 Timing.DataSetupTime = 4;
 Timing.BusTurnAroundDuration = 1;
 Timing.CLKDivision = 16;
 Timing.DataLatency = 17;
 Timing.AccessMode = FMC_ACCESS_MODE_A;
 /* ExtTiming */
 ExtTiming.AddressSetupTime = 3;
 ExtTiming.AddressHoldTime = 15;
 ExtTiming.DataSetupTime = 4;
 ExtTiming.BusTurnAroundDuration = 1;
 ExtTiming.CLKDivision = 16;
 ExtTiming.DataLatency = 17;
 ExtTiming.AccessMode = FMC_ACCESS_MODE_A;
 
 if (HAL_SRAM_Init(&hsram1, &Timing, &ExtTiming) != HAL_OK)
 {
 Error_Handler( );
 }
 
 HAL_SetFMCMemorySwappingConfig(FMC_SWAPBMAP_SDRAM_SRAM);
}

The (Cube-MX generated) clock setup is:

/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
 RCC_OscInitTypeDef RCC_OscInitStruct = {0};
 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
 
 /** Supply configuration update enable 
 */
 HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
 /** Configure the main internal regulator output voltage 
 */
 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);
 
 while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
 /** Macro to configure the PLL clock source 
 */
 __HAL_RCC_PLL_PLLSOURCE_CONFIG(RCC_PLLSOURCE_HSE);
 /** Initializes the CPU, AHB and APB busses clocks 
 */
 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
 RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
 RCC_OscInitStruct.PLL.PLLM = 4;
 RCC_OscInitStruct.PLL.PLLN = 480;
 RCC_OscInitStruct.PLL.PLLP = 2;
 RCC_OscInitStruct.PLL.PLLQ = 20;
 RCC_OscInitStruct.PLL.PLLR = 2;
 RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1;
 RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
 RCC_OscInitStruct.PLL.PLLFRACN = 0;
 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
 {
 Error_Handler();
 }
 /** Initializes the CPU, AHB and APB busses clocks 
 */
 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
 |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
 |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
 RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
 RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
 RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
 RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
 RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
 RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
 
 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
 {
 Error_Handler();
 }
 PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI1|RCC_PERIPHCLK_USB
 |RCC_PERIPHCLK_QSPI|RCC_PERIPHCLK_FMC;
 PeriphClkInitStruct.PLL2.PLL2M = 2;
 PeriphClkInitStruct.PLL2.PLL2N = 120;
 PeriphClkInitStruct.PLL2.PLL2P = 8;
 PeriphClkInitStruct.PLL2.PLL2Q = 2;
 PeriphClkInitStruct.PLL2.PLL2R = 1;
 PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_2;
 PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
 PeriphClkInitStruct.PLL2.PLL2FRACN = 0;
 PeriphClkInitStruct.FmcClockSelection = RCC_FMCCLKSOURCE_PLL2;
 PeriphClkInitStruct.QspiClockSelection = RCC_QSPICLKSOURCE_D1HCLK;
 PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL;
 PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLL;
 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
 {
 Error_Handler();
 }
 /** Enable USB Voltage detector 
 */
 HAL_PWREx_EnableUSBVoltageDetector();
}

How can I make the FMC on the STM32H743 transfer half-words faster than 1.6MHz, when driven with a 480MHz clock?

(I'd like to achieve 5MHz for 60fps.)

This topic has been closed for replies.
Best answer by CDew.1

I've changed to using NE1 and continued using 0xC000 0000.

Now that I'm configuring (NE) bank 1 and using NE bank 1, I'm getting 5MHz with just a 48MHz FMC clock and the default timings and clock division.

Previously I was configuring the NE bank 2, but writing to the entirely unconfigured NE bank 1's address. The fact that it worked at all is surprising.

5 replies

Mike_ST
Technical Moderator
February 25, 2020

Check the timings...

You can try the following changes

Timing.CLKDivision = 8;

ExtTiming.CLKDivision = 8;

And see whether something happens.

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. 
CDew.1
CDew.1Author
Associate III
February 25, 2020

@Mike_ST​ I tried that, but it didn't make any difference.

I think I may have spotted the cause of the problem, though I have not yet fixed it.

I have set :

 hsram1.Init.NSBank = FMC_NORSRAM_BANK2;

but I am writing to 0xC000 0000. (When I wrote to 0x6000 0000, before swapping banks, I was getting spurious writes: https://community.st.com/s/question/0D50X00009XkWQE/stm32h743ii-fmc-8080-lcd-spurious-writes .)

I don't care about FMC's chip select, because the LCD is the only other thing on the bus, and its #CS is wired to GND.

I think that the problem is that I'm *configuring* NE bank 2 and then *using* NE bank 1 (by writing to 0xC000 0000).

(The definition of 4 "NE banks" within "FMC bank" 1 confuses me, as it's never clear which type of bank an argument is referring to.)

I will spend some time fixing the hard faults that changing NE2 to NE1 has caused.

Is the address 0xC000 0000 correct to write to NE bank 1 of FMC bank 1 after "HAL_SetFMCMemorySwappingConfig(FMC_SWAPBMAP_SDRAM_SRAM);"?

Mike_ST
Technical Moderator
February 25, 2020

I don't know how addressing issues can influence timings.

Please check TABLE 147 in RM 0433, maybe that can help a bit.

HAL_SetFMCMemorySwappingConfig(FMC_SWAPBMAP_SDRAM_SRAM); will set BMAP[1:0]=01.

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. 
CDew.1
CDew.1AuthorBest answer
Associate III
February 25, 2020

I've changed to using NE1 and continued using 0xC000 0000.

Now that I'm configuring (NE) bank 1 and using NE bank 1, I'm getting 5MHz with just a 48MHz FMC clock and the default timings and clock division.

Previously I was configuring the NE bank 2, but writing to the entirely unconfigured NE bank 1's address. The fact that it worked at all is surprising.

CDew.1
CDew.1Author
Associate III
February 25, 2020

@Mike_ST​ Thanks for your help. Can you close this ticket please?

Mike_ST
Technical Moderator
February 25, 2020

You are welcome.

I can't close topics myself, if you like you can flag it as answered, .

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question.