cancel
Showing results for 
Search instead for 
Did you mean: 

QSPI read and write timing

sarun
Associate III

Hello 

I have been trying to test the QSPI flash on the STM32H747, Based on the BSP test code. 

 

clock speed - 66Mhz prescaler-3

Write operation 

Data size (KB) 

1 

4 

10 

50 

75 

100 

Time taken(us) 

618 

2406 

5337 

16956 

24233 

31427 

Read operation 

Data size (KB) 

1 

4 

10 

50 

75 

100 

Time taken(us) 

213 

864 

2155 

10513 

15767 

21023 

Read in Memory mapped mode 

Data size (KB) 

1 

4 

10 

50 

75 

100 

Time taken(us) 

12 

42 

102 

502 

753 

1002 

 

by leaving the prescaler -1 

Read in Memory mapped mode 

Data size (KB) 

1 

4 

10 

50 

75 

100 

Time taken(us) 

6 

23 

58 

284 

426 

564 

1. I wanted to know are these performance matrices normal for QSPI memory?

2. When I left prescaler to 1 the QSPI clock effectively became 200Mhz and the onboard flash only supports till 133Mhz, how it is working at this clock

6 REPLIES 6
LCE
Principal

What is "the STM32H747 board"? Which flash component? 

Reading memory mapped 100 kB in 1000 µs => ~100 MB / s

=> pretty amazing at 66 MHz !

So it is a DDR flash ? Or some measurement fault ?

sarun
Associate III

Hello @LCE 

I meant to say STM32H747-DISC0 Evaluation board, the part number is MT25TL01G. I am also little confused at the result, this test is based on the BSP example code, AND it is a NOR flash

LCE
Principal

Okay, it is a DTR (that's what I meant above, not DDR...) flash, with quad IO.

At 66 MHz the maximum data rate can only be 66M * 2 (DTR) * 4 bit = 528 Mbit/s = 66 MByte/s

There's definitely something wrong with this measurement!

I would check all the test functions and timers.

sarun
Associate III

Initially I had some doubts regarding the timer but cross verified it by blinking some LED (I don't have access to oscilloscope at the moment).below i have added the QSPI init function, this prescaler is directly going to QSPI prescaler of HAL QSPI init function. I tried modifying the first index for manipulating the clock, HCLK3 (QSPI clock source) is at 200 MHZ. 

1. is my assumption of clock modification is correct ?

int32_t BSP_QSPI_Init(uint32_t Instance, BSP_QSPI_Init_t *Init)
{
int32_t ret = BSP_ERROR_NONE;
BSP_QSPI_Info_t pInfo;
MX_QSPI_Init_t qspi_init;
/* Table to handle clock prescalers:
1: For STR mode to reach max 108Mhz/**************/
3: For DTR mode to reach max 54Mhz/**************/
*/
// static const uint32_t PrescalerTab[2] = {1, 3};/**************/
static const uint32_t PrescalerTab[2] = {1, 1};//this is where i tried to edit prescaler

/* Check if the instance is supported */
if(Instance >= QSPI_INSTANCES_NUMBER)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
/* Check if instance is already initialized */
if(QSPI_Ctx[Instance].IsInitialized == QSPI_ACCESS_NONE)
{
#if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1)
/* Register the QSPI MSP Callbacks */
if(QSPI_Ctx[Instance].IsMspCallbacksValid == 0UL)
{
if(BSP_QSPI_RegisterDefaultMspCallbacks(Instance) != BSP_ERROR_NONE)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
#else
/* Msp QSPI initialization */
QSPI_MspInit(&hqspi);
#endif /* USE_HAL_QSPI_REGISTER_CALLBACKS */

if(ret == BSP_ERROR_NONE)
{
/* STM32 QSPI interface initialization */
(void)MT25TL01G_GetFlashInfo(&pInfo);
qspi_init.ClockPrescaler = PrescalerTab[Init->TransferRate];
qspi_init.DualFlashMode = QSPI_DUALFLASH_ENABLE;
qspi_init.FlashSize = (uint32_t)POSITION_VAL((uint32_t)pInfo.FlashSize) - 1U;
qspi_init.SampleShifting = (Init->TransferRate == BSP_QSPI_STR_TRANSFER) ? QSPI_SAMPLE_SHIFTING_HALFCYCLE : QSPI_SAMPLE_SHIFTING_NONE;

if(MX_QSPI_Init(&hqspi, &qspi_init) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}/* QSPI memory reset */
else if(QSPI_ResetMemory(Instance) != BSP_ERROR_NONE)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}/* Force Flash enter 4 Byte address mode */
else if(MT25TL01G_AutoPollingMemReady(&hqspi, QSPI_Ctx[Instance].InterfaceMode) != MT25TL01G_OK)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else if(MT25TL01G_Enter4BytesAddressMode(&hqspi, QSPI_Ctx[Instance].InterfaceMode) != MT25TL01G_OK)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}/* Configuration of the dummy cycles on QSPI memory side */
else if(QSPI_DummyCyclesCfg(Instance) != BSP_ERROR_NONE)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else
{
/* Configure Flash to desired mode */
if(BSP_QSPI_ConfigFlash(Instance, Init->InterfaceMode, Init->TransferRate) != BSP_ERROR_NONE)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
}
}
}
}

/* Return BSP status */
return ret;
}

/*******************Clock config*****************/

/**
* @brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSE)
* SYSCLK(Hz) = 400000000 (Cortex-M7 CPU Clock)
* HCLK(Hz) = 200000000 (Cortex-M4 CPU, Bus matrix Clocks)
* AHB Prescaler = 2
* D1 APB3 Prescaler = 2 (APB3 Clock 100MHz)
* D2 APB1 Prescaler = 2 (APB1 Clock 100MHz)
* D2 APB2 Prescaler = 2 (APB2 Clock 100MHz)
* D3 APB4 Prescaler = 2 (APB4 Clock 100MHz)
* HSE Frequency(Hz) = 25000000
* PLL_M = 5
* PLL_N = 160
* PLL_P = 2
* PLL_Q = 4
* PLL_R = 2
* VDD(V) = 3.3
* Flash Latency(WS) = 4
* @PAram None
* @retval None
*/
static void SystemClock_Config(void) {
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
HAL_StatusTypeDef ret = HAL_OK;

/*!< Supply configuration update enable */
HAL_PWREx_ConfigSupply(PWR_DIRECT_SMPS_SUPPLY);

/* The voltage scaling allows optimizing the power consumption when the device is
clocked below the maximum system frequency, to update the voltage scaling value
regarding system frequency refer to product datasheet. */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {
}

/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
RCC_OscInitStruct.CSIState = RCC_CSI_OFF;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;

RCC_OscInitStruct.PLL.PLLM = 5;
RCC_OscInitStruct.PLL.PLLN = 160;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLQ = 4;

RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
if (ret != HAL_OK) {
Error_Handler();
}

/* Select PLL as system clock source and configure bus clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 |
RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D3PCLK1);

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;
ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
if (ret != HAL_OK) {
Error_Handler();
}

/*
Note : The activation of the I/O Compensation Cell is recommended with communication interfaces
(GPIO, SPI, FMC, QSPI ...) when operating at high frequencies(please refer to product datasheet)
The I/O Compensation Cell activation procedure requires :
- The activation of the CSI clock
- The activation of the SYSCFG clock
- Enabling the I/O Compensation Cell : setting bit[0] of register SYSCFG_CCCSR
*/

/*activate CSI clock mondatory for I/O Compensation Cell*/
__HAL_RCC_CSI_ENABLE();

/* Enable SYSCFG clock mondatory for I/O Compensation Cell */
__HAL_RCC_SYSCFG_CLK_ENABLE()
;

/* Enables the I/O Compensation Cell */
HAL_EnableCompensationCell();

}

 

LCE
Principal

Unreadable... please use this button to show source code:

</>

sarun
Associate III

I am sharing the source files