cancel
Showing results for 
Search instead for 
Did you mean: 

QSPI Quad Read Commands Only Receiving 16 Bytes and Low Read Frequencies

Jaboop
Associate II

We are creating a driver for a W25Q128JV Winbond Nor Flash chip. We are working with a STM32 H743ZI2 board and communicating on the QSPI peripheral with the help of the HAL libraries. Currently the driver can successfully Write to the chip using standard Page Program (0x02h) and the Quad Page Program (0x32h). We are also successfully doing a Fast Read (0x0Bh) up to speeds of 72MHz and a Fast Read Dual Output (0x3Bh) up to speeds of 36MHz before they start to fail. Currently we are using a 3.3V power bus, so based on the AC Electrical Characteristics seen in the datasheet we expect these commands to work up to speeds of 133MHz.0693W00000FBEtWQAX.pngBelow is the CubeMX setup we are using for the QSPI peripheral:

0693W00000FBEyCQAX.png*Scaled clock down to 12MHz for logic analyzer testing

If you prefer the generated code that is also provided below.

QSPI_HandleTypeDef hqspi;
 
/* QUADSPI init function */
void MX_QUADSPI_Init(void)
{
 
  /* USER CODE BEGIN QUADSPI_Init 0 */
 
  /* USER CODE END QUADSPI_Init 0 */
 
  /* USER CODE BEGIN QUADSPI_Init 1 */
 
  /* USER CODE END QUADSPI_Init 1 */
  hqspi.Instance = QUADSPI;
  hqspi.Init.ClockPrescaler = 12 - 1;
  hqspi.Init.FifoThreshold = 4;
  hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;
  hqspi.Init.FlashSize = 23;
  hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE;
  hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
  hqspi.Init.FlashID = QSPI_FLASH_ID_1;
  hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
  if (HAL_QSPI_Init(&hqspi) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN QUADSPI_Init 2 */
 
  /* USER CODE END QUADSPI_Init 2 */
 
}
 
void HAL_QSPI_MspInit(QSPI_HandleTypeDef* qspiHandle)
{
 
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
  if(qspiHandle->Instance==QUADSPI)
  {
  /* USER CODE BEGIN QUADSPI_MspInit 0 */
 
  /* USER CODE END QUADSPI_MspInit 0 */
  /** Initializes the peripherals clock
  */
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_QSPI;
    PeriphClkInitStruct.PLL2.PLL2M = 32;
    PeriphClkInitStruct.PLL2.PLL2N = 144;
    PeriphClkInitStruct.PLL2.PLL2P = 2;
    PeriphClkInitStruct.PLL2.PLL2Q = 2;
    PeriphClkInitStruct.PLL2.PLL2R = 2;
    PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_1;
    PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
    PeriphClkInitStruct.PLL2.PLL2FRACN = 0;
    PeriphClkInitStruct.QspiClockSelection = RCC_QSPICLKSOURCE_PLL2;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
    {
      Error_Handler();
    }
 
    /* QUADSPI clock enable */
    __HAL_RCC_QSPI_CLK_ENABLE();
 
    __HAL_RCC_GPIOF_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**QUADSPI GPIO Configuration
    PF6     ------> QUADSPI_BK1_IO3
    PF7     ------> QUADSPI_BK1_IO2
    PF8     ------> QUADSPI_BK1_IO0
    PF9     ------> QUADSPI_BK1_IO1
    PF10     ------> QUADSPI_CLK
    PB10     ------> QUADSPI_BK1_NCS
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI;
    HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
 
    GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;
    HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
 
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
    /* QUADSPI interrupt Init */
    HAL_NVIC_SetPriority(QUADSPI_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(QUADSPI_IRQn);
  /* USER CODE BEGIN QUADSPI_MspInit 1 */
 
  /* USER CODE END QUADSPI_MspInit 1 */
  }
}

Here are the functions we are working with to drive the flash chip and the instruction description from the datasheet.

0693W00000FBEyMQAX.png 

0693W00000FBEyRQAX.png0693W00000FBEyWQAX.png0693W00000FBEybQAH.pngInitial thoughts on seeing 16bytes from the Fast Read Quad I/O was that the Wrap Bits were not actually defaulting correctly so we included a manual setting of the Wrap Bits using the Set Burst with Wrap (77h) to guarantee we had the right configuration there. The function that does this is as follows.

uint8_t QSPI_SetBurstWrap_77h(uint8_t mode) {
	if (mode < 0 || mode > 7) {
		mode = 1;
	}
 
	mode = mode<<4;
	QSPI_CommandTypeDef sCommand;
 
	/* Burst Wrap Sequence --------------------------------- */
	sCommand.Instruction = SET_BURST_WRAP_CMD;
	sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
	sCommand.AddressMode = QSPI_ADDRESS_NONE;
	sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
	sCommand.Address = 0;
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
	sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
	sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
	sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
	sCommand.DataMode = QSPI_DATA_4_LINES;
	sCommand.NbData = 1;
	sCommand.DummyCycles = 6; //24 Dummy Cycles across 4 Lines 24/4=6
 
	if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)!= HAL_OK) {
		return HAL_ERROR;
	}
 
	/* Transmission of Wrap Bits */
	if (HAL_QSPI_Transmit(&hqspi, &mode, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		return HAL_ERROR;
	}
 
	return HAL_OK;
}

Finally, the main we are using for our tests is below. 

/* USER CODE BEGIN 0 */
uint32_t Size = 4096; //4KBytes
uint32_t ReadAddress, WriteAddr, BlockAddress = 0;
uint8_t sData[4096];
uint8_t rData[4096];
uint8_t s1Data[4096];
uint8_t checkReg;
/* USER CODE END 0 */
int main(void)
{
  /* Enable I-Cache---------------------------------------------------------*/
  SCB_EnableICache();
  /* Enable D-Cache---------------------------------------------------------*/
  SCB_EnableDCache();
  /* MCU Configuration--------------------------------------------------------*/¬
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
  int i=0;
  uint8_t val= 0x00;
 
  while(i < Size){
	  sData[i] = val;
	  if ((i+1) % 1 == 0) {
		  val+=1;
	  }
	  i++;
  }
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_QUADSPI_Init();
 
  /* USER CODE BEGIN 2 */
  /*Enable Quad*/
  QSPI_EnableQuad(); //Set the QE, DRV0, DRV1 bits
 
  /*Erase Functions*/
  if (QSPI_EraseSector_20h(BlockAddress) != HAL_OK) {
	  Error_Handler();
  }
  /*Read Single Data Lines*/
  if (QSPI_FastReadData_0Bh(rData, ReadAddress, Size) != HAL_OK) {
	  Error_Handler();
  }
  /*Read Quad Data Lines*/
  if (QSPI_FastReadQuadOutput_6Bh(s1Data, ReadAddress, Size) != HAL_OK) {
	  Error_Handler();
  }
 
  while (1)
  {
 
  }
  /* USER CODE END 3 */
}

Before we do any read or write operations we write to and check the values in our status registers to ensure the QE bit is set to 1 and that DRV1 and DRV0 are set to 0 making the Driver strength 100%.

Here are the register values we read out after doing our setup for Default Driver Strength 25%:

0693W00000FBEylQAH.pngHere are the register values we read out after doing our setup for Maximum Driver Strength:

0693W00000FBEyqQAH.pngHere is the Logic analysis we are seeing for both the Fast Read Quad Output and Fast Read Quad I/O commands. They both receive the first 16 bytes of good data and then get the same bad data later down the line, random bytes but consistent random bytes. Note: for all reads we are reading the first sector of the Winbond chip (4KB) which contains 16 pages (256Bytes) each populated with values 0-255. This data is known good as we successfully read the data out using the Fast Read command before trying the Quad Read Commands.

Logic Analyzer of Fast Read Quad Output

0693W00000FBEyvQAH.pngLogic Analyzer of Fast Read Quad I/O

0693W00000FBEz0QAH.pngThe two things we are trying to find out here is 1) Why are the Quad Read Functions only returning the first 16 bytes of data instead of a whole sector and 2) What could be preventing Read commands from working at higher frequencies than 72MHz?

I attached the .h file that contains the masking of the hex instructions just in case

12 REPLIES 12

You've made a circular reference to this thread, not sure if that was your intent, or if you wanted to post to your own thread, with detail of your implementation and connectivity?

I probably wouldn't jack the drive levels to maximum on short traces, you're like to get all kinds of reflections and ringing. To get stable signals you might want to review carefully the wiring and use 27R or 33R series resistors.

Wiring some contraption to the NUCLEO boards is probably not going to function well above 33 or 50 MHz. I'm not even sure these are the pins I used on the NUCLEO-H743ZI2 board, and that thing has a lot of stub traces and wiring to multiple peripherals/pins to contend with.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
hieukmt
Associate

hi friend, i can buy source w25q ?

hieukmt
Associate

hi friend, Can you shared source code  ?
I hope you respond soon !!!