Skip to main content
HPham.1590
Associate III
September 16, 2020
Solved

[TouchGFX] Can not write to External flash using QuasSPI while running with TouchGFX

  • September 16, 2020
  • 19 replies
  • 3803 views

Hello, I'm using STM32F746NG Discovery Kit.

I'm trying to Write/Read data to/from External Flash using QuadSPI with BSP driver.

Below is my simple function, I don't know why It's can not write to the memory.

I really don't know exactly how to determine the block address and the Read/Write Address, can anyone help me to correct it?

Many thanks,

Hieu

 uint8_t * pData = "Hello World";
 int i;
 if (BSP_QSPI_Erase_Block(0x90000000) == QSPI_OK)
 {
	 if(BSP_QSPI_Write(pData, 0x90000000, 12) == QSPI_OK)
	 {
		i = 1;
	 }
 }
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 */
}

This topic has been closed for replies.
Best answer by Tesla DeLorean

But are you writing it a lot? If it is configuration data perhaps manage it before bring it up in Memory Mapped Mode

Direct Mode is where you interact with the QSPI at a command/peripheral level rather than mapped into the ARM's address space.

STM32Cube_FW_F7_V1.16.0\Drivers\BSP\STM32746G-Discovery\stm32746g_discovery_qspi.c

/**

 * @brief Reads an amount of data from the QSPI memory.

 * @param pData: Pointer to data to be read

 * @param ReadAddr: Read start address

 * @param Size: Size of data to read

 * @retval QSPI memory status

 */

uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size)

{

 QSPI_CommandTypeDef s_command;

 /* Initialize the read command */

 s_command.InstructionMode  = QSPI_INSTRUCTION_1_LINE;

 s_command.Instruction      = QUAD_INOUT_FAST_READ_CMD;

 s_command.AddressMode      = QSPI_ADDRESS_4_LINES;

 s_command.AddressSize      = QSPI_ADDRESS_24_BITS;

 s_command.Address          = ReadAddr;

 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

 s_command.DataMode         = QSPI_DATA_4_LINES;

 s_command.DummyCycles      = N25Q128A_DUMMY_CYCLES_READ_QUAD;

 s_command.NbData           = Size;

 s_command.DdrMode          = QSPI_DDR_MODE_DISABLE;

 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;

 s_command.SIOOMode         = QSPI_SIOO_INST_EVERY_CMD;

 /* Configure the command */

 if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)

 {

   return QSPI_ERROR;

 }

 /* Set S# timing for Read command */

 MODIFY_REG(QSPIHandle.Instance->DCR, QUADSPI_DCR_CSHT, QSPI_CS_HIGH_TIME_3_CYCLE);

 /* Reception of the data */

 if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)

 {

   return QSPI_ERROR;

 }

 /* Restore S# timing for nonRead commands */

 MODIFY_REG(QSPIHandle.Instance->DCR, QUADSPI_DCR_CSHT, QSPI_CS_HIGH_TIME_6_CYCLE);

 return QSPI_OK;

}

19 replies

Alexandre RENOUX
Visitor II
September 18, 2020

Hello,

Your Flash is in Memory Mapped Mode, therefore it is read only. You have to leave the Memory Mapped Mode to be able to write in your external Flash.

/Alexandre

HPham.1590
Associate III
September 18, 2020

Many thanks for your Reply, Alexandre.

I tried to remove BSP_QSPI_MemoryMappedMode(); line but my program jump to hardfault.

So have any way available to Disable this mode to read/write and Enable it after that?

Hieu

Tesla DeLorean
Guru
September 18, 2020

Execute-In-Place uses the Memory Mapped Mode, as does bus level data access, if turned off, and you're dependent on it, the system will Hard Fault.

You CANNOT use Write/Erase and Memory Mapped mode CONCURRENTLY

You could Read and Write concurrently in Direct Mode, here you'd need manage access to the QSPI like you would a mass storage device (Hard Drive)

Why and how much data do you need to write into memory?

eMMC or SD Cards are better solutions to data storage, for example data logging.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
MM..1
Super User
September 20, 2020

Go back to how store 1kB data? You plan use QSPI, but better is store in internal flash , then Clive ask have you free sector in internal flash?

How big is code?

HPham.1590
Associate III
September 23, 2020

yeb, I changed the plan to internal flash and it's working seem OK, but now i have to erase 1 sector 256KB (Sector 7), I don't know how to erase only some page in this sector. Can you give me some solution?

Many thanks

Hieu

MM..1
Super User
September 23, 2020

Use EEPROM emulation code and use last sector with 256kB , code it incrementaly write , and when is full writed erase it.

Second way when you need more space for code is use first sector for bootloader second for EEPROM emulator and code start from third.

First sectors is smaler.

KShim.1738
Associate III
December 28, 2020

I found a solution for writing external flash while TouchGFX app is running. Speaking clearly TouchGFX app must be paused to write the external flash. And I think it should be done voluntarily by TouchGFX app itself. That will be the safest way I reckon.

Below is the example. I used a flag instead of IPC provided by RTOS. Note that how the flag is set by both sides. And I have read HAL_QSPI_Abort() is enough to go back to indirect mode from memory mapped mode somewhere else on this forum.

Pausing ToughGFX app is enough to me because it's for updating some images in the external flash. I am afraid that this might not be the one for others if they don't want to pause it.

But I believe that Pausing TouchGFX is the only solution to write the external flash. Because TouchGFX will cause hard fault if it continues to run as soon as QSPI interface goes into indirect mode.

//------------------------------- sync functions -----------------------------
volatile uint8_t guSync;
 
#define TGFX_STATE_NOT_STARTED 0x00
#define TGFX_STATE_RUNNING 0x04
#define TGFX_STOP_REQUESTED 0x01
#define TGFX_STATE_STOPPED 0x80
 
void gusync_init(void) {
 guSync = TGFX_STATE_NOT_STARTED;
}
 
void pause_touchgfx_if_requested(void) {
 while(guSync & TGFX_STOP_REQUESTED) {
 guSync |= TGFX_STATE_STOPPED;
 DBG_PRINT(DBG_INFO, "==== tgfx waits ==== \r\n");
 vTaskDelay(100);
 }
 guSync &= ~TGFX_STATE_STOPPED;
 DBG_PRINT(DBG_INFO, "==== tgfx woke up==== \r\n");
}
 
void wait_for_touchgfx_to_stop(void) {
 guSync |= TGFX_STOP_REQUESTED;
 while(!(guSync & TGFX_STATE_STOPPED))
 {
 DBG_PRINT(DBG_INFO, "==== update waiting ==== \r\n");
 vTaskDelay(1000);
 }
}
 
void let_touchgfx_continue(void) {
 guSync &= ~TGFX_STOP_REQUESTED;
 DBG_PRINT(DBG_INFO, "==== tfgfx released ==== \r\n");
}
 
 
void set_indrect_mode(void) {
 BSP_QSPI_DeInit();
 BSP_QSPI_Init();
 HAL_NVIC_DisableIRQ(QUADSPI_IRQn);
}
 
void set_memory_mapped_mode(void) {
 BSP_QSPI_DeInit();
 BSP_QSPI_Init();
 BSP_QSPI_MemoryMappedMode();
 HAL_NVIC_DisableIRQ(QUADSPI_IRQn);
}
 
 
 
//------------------------------- TouchGFX -----------------------------
void MainView::Screen_Saver()
{
 if(1){
 if(pre_value != sec_cnt){
 if(++mIdleTime >= (10) && !AD_Container.isVisible()) // 10�
 //if(++mIdleTime >= (10*60) && !AD_Container.isVisible()) // 10*60 : 10��
 {
 mIdleTime = 0;
 ChangeContainer(CONTAINER_AD);
 }
 else if(AD_Container.isVisible())
 {
 if(++mADChangeTime == AD_CHANGE_TIME){ // x� ����
 /* Kyle 20201020 */
 pause_touchgfx_if_requested();
 
 mADChangeTime = 0;
 UpdateADImage();
 }
 }
 }
 
//------------------------------- update -----------------------------
 while(1) {
 wait_for_touchgfx_to_stop();
 
 set_indrect_mode();
 BSP_QSPI_Erase_Block(TEST_READ_WRITE_ADDRESS);
 BSP_QSPI_Write(teststr, TEST_READ_WRITE_ADDRESS, strlen(teststr));
 BSP_QSPI_Read(buffer, TEST_READ_WRITE_ADDRESS, 20);
 DBG_PRINT_ARRAY_BYTE(DBG_INFO, buffer, 20);
 set_memory_mapped_mode();
 
 let_touchgfx_continue();
 vTaskDelay(5000);
}

awiernie
Associate III
March 10, 2023

I experienced the problem with hardfault and found your solution. Has anybody used it?

I use the following but there I get sometimes hardfaults if the osDelays are too short. The solution below works however.

Maybe my hardfaults with lower osDelay() occured only with debugger. I also don't know which osDelay I can ommit. 100 ms between suspend of touchgfx and handleFlashOperations were too short.

Is there an other way to know if the delay is already active?

Is there a delay needed after writing to the flash before reactivation the touchgfx?

			(void) osDelay(100);
			(void) osThreadSuspend( Task_TouchGFXHandle );
			(void) osDelay(100);
			(void) HAL_NVIC_DisableIRQ(LTDC_IRQn);
			(void) HAL_NVIC_DisableIRQ(DMA2D_IRQn);
			(void) osDelay(500);
 
			handleFlashOperations();
 
			(void) osDelay(500);
			HAL_NVIC_EnableIRQ(LTDC_IRQn);
			HAL_NVIC_EnableIRQ(DMA2D_IRQn);
			(void) osDelay(100);
			(void) osThreadResume( Task_TouchGFXHandle );

Tesla DeLorean
Guru
March 10, 2023

>>Is there an other way to know if the delay is already active?

Have some mutex or semaphore

>>Is there a delay needed after writing to the flash before reactivation the touchgfx?

The erase / write should inherently wait for the QSPI device to come ready.

If cached, watch for coherency issues, ie what's cached vs what you changed.

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