2020-09-14 04:25 AM
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, ®, 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, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
}
2020-09-14 05:29 AM
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();
2020-09-14 06:37 AM
24-bit addressing isn't going to be sufficient for a 64MB memory
2020-09-14 07:33 PM
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?
2020-09-14 07:41 PM
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.