我正在使用 STM32H743 的 FMC 来驱动 16 位 8080 总线 LCD 控制器。
我尝试使用 DMA、MDMA 和 CPU 循环通过 FMC 将数据传输到 8080 总线。
传输频率与使用 DMA、MDMA 还是 CPU 循环无关。这让我认为 DMA/MDMA/CPU 循环不是限制因素。
在 480MHz FMC 时钟下,传输频率仅为 1.6MHz,在 16 位彩色 320x240 LCD 上只有 20fps。
在 240MHz FMC 时钟下,传输仅以 0.8MHz 发生,以此类推。
我还尝试将各种设置和保持时间减少到 1 和 0 周期,但这(令人惊讶地)并没有影响 8080 总线上的波形。
我的(Cube-MX 生成)FMC 初始化代码是:
/* 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);
}
我修改后的设置是:
Timing.AddressSetupTime = 1;
Timing.AddressHoldTime = 1;
Timing.DataSetupTime = 1;
Timing.BusTurnAroundDuration = 1; // not needed
Timing.CLKDivision = 1; // not needed
Timing.DataLatency = 34;
Timing.AccessMode = FMC_ACCESS_MODE_A;
ExtTiming.AddressSetupTime = 1;
ExtTiming.AddressHoldTime = 1;
ExtTiming.DataSetupTime = 1;
ExtTiming.BusTurnAroundDuration = 1; // not needed
ExtTiming.CLKDivision = 1; // not needed
ExtTiming.DataLatency = 34;
ExtTiming.AccessMode = FMC_ACCESS_MODE_A;
和
Timing.AddressSetupTime = 0;
Timing.AddressHoldTime = 0;
Timing.DataSetupTime = 0;
Timing.BusTurnAroundDuration = 0; // not needed
Timing.CLKDivision = 1; // not needed
Timing.DataLatency = 0;
Timing.AccessMode = FMC_ACCESS_MODE_A;
ExtTiming.AddressSetupTime = 0;
ExtTiming.AddressHoldTime = 0;
ExtTiming.DataSetupTime = 0;
ExtTiming.BusTurnAroundDuration = 0; // not needed
ExtTiming.CLKDivision = 1; // not needed
ExtTiming.DataLatency = 34;
ExtTiming.AccessMode = FMC_ACCESS_MODE_A;
(Cube-MX 生成的)时钟设置为:
/**
* @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();
}
当使用 480MHz 时钟驱动时,如何使 STM32H743 上的 FMC 传输半字快于 1.6MHz?