cancel
Showing results for 
Search instead for 
Did you mean: 

[QuadSPI] [TouchGFX] Can not Write and Read data from External Flash on STM32F746 Discovery

HPham.1590
Senior

Hello, I'm using STM32F746 Discovery Kit with Touch GFX.

I want to Write and Read data from N25Q512A External Flash using QSPI.

I have tried the ST's Example on Github but it's not working for me (https://github.com/STMicroelectronics/STM32CubeF7),

I found that my program has a bit different from the example.

The different come from TouchGFX. When using TouchGFX, QuadSPI has been enabled and using for this library and the hqspi.Init.ClockPrescaler = 1 ( the ST's example is 2).

(I think the different clock is not affected)

Below is my functions, anyone can tell me what is wrong?

Many thanhs,

Hieu.

static 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 */
  /* QUADSPI parameter configuration*/
  hqspi.Instance = QUADSPI;
//  HAL_QSPI_DeInit(&QSPIHandle); //User Code
  hqspi.Init.ClockPrescaler = 1;
//  hqspi.Init.ClockPrescaler = 2;//User Code
  hqspi.Init.FifoThreshold = 4;
  hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
  hqspi.Init.FlashSize = 24;
//  QSPIHandle.Init.FlashSize = POSITION_VAL(0x1000000) - 1; //User Code
  hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE;
//  QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE; //User Code
  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 */
  BSP_QSPI_Init();
 
  BSP_QSPI_MemoryMappedMode();
  // This line below is disabled to test Write to external flash function
//  HAL_NVIC_DisableIRQ(QUADSPI_IRQn);
 
  /* USER CODE END QUADSPI_Init 2 */
}
HAL_StatusTypeDef WriteDataToQuadSPI(QSPI_HandleTypeDef QSPIHandle, uint32_t address, uint8_t * aTxBuffer)
{
	QSPI_CommandTypeDef sCommand;
	sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
	sCommand.AddressSize       = QSPI_ADDRESS_24_BITS;
	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;
	/* Enable write operations ------------------------------------------- */
	QSPI_WriteEnable(&QSPIHandle);
	/* Erasing Sequence -------------------------------------------------- */
	sCommand.Instruction = SECTOR_ERASE_CMD;
	sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
	sCommand.Address     = address;
	sCommand.DataMode    = QSPI_DATA_NONE;
	sCommand.DummyCycles = 0;
	if (HAL_QSPI_Command(&QSPIHandle, &sCommand,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		return HAL_ERROR;
	}
	/* Configure automatic polling mode to wait for end of erase ------- */
	QSPI_AutoPollingMemReady(&QSPIHandle);
	/* Enable write operations ----------------------------------------- */
	QSPI_WriteEnable(&QSPIHandle);
    /* Writing Sequence ------------------------------------------------ */
    sCommand.Instruction = QUAD_IN_FAST_PROG_CMD;
    sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
    sCommand.DataMode    = QSPI_DATA_4_LINES;
    sCommand.NbData      = BUFFERSIZE;
 
    if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    {
    	return HAL_ERROR;
    }
 
    if (HAL_QSPI_Transmit(&QSPIHandle, aTxBuffer,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    {
    	return HAL_ERROR;
    }
    /* Configure automatic polling mode to wait for end of program ----- */
    QSPI_AutoPollingMemReady(&QSPIHandle);
    return HAL_OK;
}
uint8_t * ReadDataFromQuadSPI(QSPI_HandleTypeDef QSPIHandle, uint32_t address)
{
	uint8_t * aRxBuffer;
	QSPI_CommandTypeDef sCommand;
	sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
	sCommand.AddressSize       = QSPI_ADDRESS_24_BITS;
	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;
    /* Configure Volatile Configuration register (with new dummy cycles) */
    QSPI_DummyCyclesCfg(&QSPIHandle);
 
    /* Reading Sequence ------------------------------------------------ */
    sCommand.Instruction = QUAD_OUT_FAST_READ_CMD;
    sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD;
    if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    {
    	aRxBuffer[0] = 1;
    }
 
    if (HAL_QSPI_Receive_IT(&QSPIHandle, aRxBuffer) != HAL_OK)
    {
    	aRxBuffer[0] = 1;
    }
    return aRxBuffer;
}
static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
{
  QSPI_CommandTypeDef     sCommand;
  QSPI_AutoPollingTypeDef sConfig;
 
  /* Enable write operations ------------------------------------------ */
  sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
  sCommand.Instruction       = WRITE_ENABLE_CMD;
  sCommand.AddressMode       = QSPI_ADDRESS_NONE;
  sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
  sCommand.DataMode          = QSPI_DATA_NONE;
  sCommand.DummyCycles       = 0;
  sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;
  sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
  sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;
 
  if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
 
  /* Configure automatic polling mode to wait for write enabling ---- */
  sConfig.Match           = 0x02;
  sConfig.Mask            = 0x02;
  sConfig.MatchMode       = QSPI_MATCH_MODE_AND;
  sConfig.StatusBytesSize = 1;
  sConfig.Interval        = 0x10;
  sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;
 
  sCommand.Instruction    = READ_STATUS_REG_CMD;
  sCommand.DataMode       = QSPI_DATA_1_LINE;
 
  if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
}
 
/**
  * @brief  This function reads the SR of the memory and awaits the EOP.
  * @param  hqspi: QSPI handle
  * @retval None
  */
static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi)
{
  QSPI_CommandTypeDef     sCommand;
  QSPI_AutoPollingTypeDef sConfig;
 
  /* Configure automatic polling mode to wait for memory ready ------ */
  sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
  sCommand.Instruction       = READ_STATUS_REG_CMD;
  sCommand.AddressMode       = QSPI_ADDRESS_NONE;
  sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
  sCommand.DataMode          = QSPI_DATA_1_LINE;
  sCommand.DummyCycles       = 0;
  sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;
  sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
  sCommand.SIOOMode         = QSPI_SIOO_INST_EVERY_CMD;
 
  sConfig.Match           = 0x00;
  sConfig.Mask            = 0x01;
  sConfig.MatchMode       = QSPI_MATCH_MODE_AND;
  sConfig.StatusBytesSize = 1;
  sConfig.Interval        = 0x10;
  sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;
 
  if (HAL_QSPI_AutoPolling_IT(&QSPIHandle, &sCommand, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}
 
/**
  * @brief  This function configures the dummy cycles on memory side.
  * @param  hqspi: QSPI handle
  * @retval None
  */
static void QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi)
{
  QSPI_CommandTypeDef sCommand;
  uint8_t reg;
 
  /* Read Volatile Configuration register --------------------------- */
  sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
  sCommand.Instruction       = READ_VOL_CFG_REG_CMD;
  sCommand.AddressMode       = QSPI_ADDRESS_NONE;
  sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
  sCommand.DataMode          = QSPI_DATA_1_LINE;
  sCommand.DummyCycles       = 0;
  sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;
  sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
  sCommand.SIOOMode         = QSPI_SIOO_INST_EVERY_CMD;
  sCommand.NbData            = 1;
 
  if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
 
  if (HAL_QSPI_Receive(&QSPIHandle, &reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
 
  /* Enable write operations ---------------------------------------- */
  QSPI_WriteEnable(&QSPIHandle);
 
  /* Write Volatile Configuration register (with new dummy cycles) -- */
  sCommand.Instruction = WRITE_VOL_CFG_REG_CMD;
  MODIFY_REG(reg, 0xF0, (DUMMY_CLOCK_CYCLES_READ_QUAD << POSITION_VAL(0xF0)));
 
  if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
 
  if (HAL_QSPI_Transmit(&QSPIHandle, &reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
}

4 REPLIES 4
Martin KJELDSEN
Chief III

For TouchGFX applications we require the flash chip to be memory mapped so we can simply point to a position in the chips memory range. When you read and write using the BSP functions you cannot have the chip in memory mapped mode. Try removing:

BSP_QSPI_MemoryMappedMode();

24-bit addressing isn't going to be sufficient for a 64MB memory​

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

Many thanks for your reply,

As your suggestion, I tried to remove this line, but my program ran into HardFault_Handler.

So may I make some mistake in any step?

Hello Clive,

I have tried to replace 24-bit addressing by 32-bit address, but it's still not working.

I think it's not the root cause because in the ST's Example what I referred, 24-bit address is still used.