Skip to main content
HP_it
Senior II
September 5, 2019
Solved

External vs. internal flash memory for touchGFX assets

  • September 5, 2019
  • 40 replies
  • 12999 views

When developing touchGFX applications you tend to get a pretty high memory need.

I'm working with the CubeIDE integration of TouchGFX and tried to add a third screen (with a third background image). I got an error saying that the application would not fit in my FLASH.

After a bit of digging it seems that the linker files don't mention the QSPI at all.

I can add that to the linker files but I would like to know if there is an official way of doing this?

I found some documentation on this but I'm not sure if this is the right way to go about it.

What goes where in the memory and how do I control it? if at all?

Thanks!

This topic has been closed for replies.
Best answer by HP_it

Just to close this one up I have made a video guide on how to configure the F746 DISCO board for external memory use.

You can find it here:

https://youtu.be/237lPdMsDZs

40 replies

kjtl
Associate
September 18, 2019

Hi,

I have tried to follow your video tutorial. I'm also on a disco-F746G board. At the point where you acheive 0 errors after excluding all the simulator folders/files, and setting up the include paths, I'm still receiving this error.

In file included from ../Src/main.cpp:23:0:
../Src/main.cpp: In function 'int main()':
../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.h:470:54: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
 { #name, (thread), (priority), (instances), (stacksz)}
 ^
../Src/main.cpp:193:3: note: in expansion of macro 'osThreadDef'
 osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 4096);
 ^~~~~~~~~~~
 
 C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.cpp:18: multiple definition of `touchgfx::OSWrappers::initialize()'
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.o:C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.cpp:18: first defined here
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.o: In function `touchgfx::OSWrappers::takeFrameBufferSemaphore()':
C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.cpp:30: multiple definition of `touchgfx::OSWrappers::takeFrameBufferSemaphore()'
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.o:C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.cpp:25: first defined here
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.o: In function `touchgfx::OSWrappers::giveFrameBufferSemaphore()':
C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.cpp:36: multiple definition of `touchgfx::OSWrappers::giveFrameBufferSemaphore()'
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.o:C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.cpp:29: first defined here
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.o: In function `touchgfx::OSWrappers::tryTakeFrameBufferSemaphore()':
C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.cpp:42: multiple definition of `touchgfx::OSWrappers::tryTakeFrameBufferSemaphore()'
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.o:C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.cpp:34: first defined here
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.o: In function `touchgfx::OSWrappers::giveFrameBufferSemaphoreFromISR()':
C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.cpp:48: multiple definition of `touchgfx::OSWrappers::giveFrameBufferSemaphoreFromISR()'
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.o:C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.cpp:39: first defined here
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.o: In function `touchgfx::OSWrappers::signalVSync()':
C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.cpp:54: multiple definition of `touchgfx::OSWrappers::signalVSync()'
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.o:C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.cpp:48: first defined here
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.o: In function `touchgfx::OSWrappers::waitForVSync()':
C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.cpp:62: multiple definition of `touchgfx::OSWrappers::waitForVSync()'
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.o:C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.cpp:60: first defined here
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.o: In function `touchgfx::OSWrappers::taskDelay(unsigned short)':
C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.cpp:74: multiple definition of `touchgfx::OSWrappers::taskDelay(unsigned short)'
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.o:C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.cpp:69: first defined here
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.o: In function `vApplicationStackOverflowHook':
C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.cpp:104: multiple definition of `vApplicationStackOverflowHook'
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.o:C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.cpp:91: first defined here
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.o: In function `vApplicationMallocFailedHook':
C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.cpp:110: multiple definition of `vApplicationMallocFailedHook'
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.o:C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.cpp:97: first defined here
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.o: In function `vApplicationIdleHook':
C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers_cmsis.cpp:115: multiple definition of `vApplicationIdleHook'
Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.o:C:/Cube_Project/Elevator_new/Debug/../Middlewares/ST/TouchGFX/touchgfx/os/OSWrappers.cpp:102: first defined here
c:\st\stm32cubeide_1.0.2\stm32cubeide\plugins\com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.7-2018-q2-update.win32_1.0.0.201904181610\tools\arm-none-eabi\bin\ld.exe: Elevator_new.elf section `ExtFlashSection' will not fit in region `FLASH'
c:\st\stm32cubeide_1.0.2\stm32cubeide\plugins\com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.7-2018-q2-update.win32_1.0.0.201904181610\tools\arm-none-eabi\bin\ld.exe: region `FLASH' overflowed by 146048 bytes
collect2.exe: error: ld returned 1 exit status

Any suggestions as to how I can fix this?

Many thanks,

K

HP_it
HP_itAuthor
Senior II
September 18, 2019

you'll have to look at you linker script again. the error says that the ExtFlashSection will not fit in the region 'FLASH' which means that you're still pointing it at the internal memory and not the QSPI as you intended.

kjtl
Associate
September 18, 2019

Apologies, I may have posted this in the wrong thread.

I am unable to compile the project after following the tutorial posted byMartin on TGFX and CubeIDE integration. I am also a noob and have no idea how to edit the linker script. What might be the reason he is able to compile without doing so? Is it due to the size of my TGFX project?

Thanks for bearing with me.

HP_it
HP_itAuthor
Senior II
September 18, 2019

yes, that's exactly the reason. if you use a full background image from the designer, they take up 255kB each. combine that with buttons and other fun stuff you quickly run out of memory!

i've made a couple of videos on the process of integrating TouchGFX into CubeIDE - maybe they can be of some help? look for the selected answer in this very thread :)

kjtl
Associate
September 18, 2019

I will definately go through the videos and follow your suggestions. However, you mention one of the prerequisites are to have a working project in Cube IDE, which I don't. If you look at my error log, there are a number of "multiple definition" errors. Do you think these will be resolved by enabling QSPI?

Update: Editing the linker script solved the flash issue, but all the other osWrapper issues remain.

Oscar_Niño
Associate II
October 16, 2019

Hi everyone

I'm new on ST boards, I have followed all steps on this video https://www.youtube.com/watch?v=VOs2LYO7wSA&feature=youtu.be and this video to use quadspi https://www.youtube.com/watch?v=237lPdMsDZs&feature=youtu.be. When build my project it doesn't have problems but at debugging my board gets just a black screen. Any idea which I could doing wrong?

HP_it
HP_itAuthor
Senior II
October 16, 2019

at the very least - you should have a white screen. If not, that could imply that you haven't configured the LCD_DISP pin properly in the MX configuration.

Oscar_Niño
Associate II
October 16, 2019

Thanks for Reply. Following the first video mentioned I created a new projet with default pin configuration as showed in video. I have tried with project in first video and it works fine (just two screen with a button each one). I copied MX_QUADSPI_Init code posted here to configure it. When enters in debug mode the screen is white but after run it get black. I checked Pins configuration with .ioc file and tried changing display type from RGB888 to RGB565 but still have back screen

Oscar_Niño
Associate II
October 21, 2019

I still have the problem, to give more details, I created a template project using TouchGFX copied code from .ld file about QUADSPI section as show you below and code in MX_QUADSPI_Init function.

MEMORY

{

RAM (xrw)   : ORIGIN = 0x20000000, LENGTH = 320K

FLASH (rx)   : ORIGIN = 0x8000000, LENGTH = 1024K

QUADSPI (r)  : ORIGIN = 0x90000000, LENGTH = 16M

}

and this

...

  libgcc.a ( * )

 }

 .ARM.attributes 0 : { *(.ARM.attributes) }

ExtFlashSection :

{

*(ExtFlashSection ExtFlashSection.*)

*(.gnu.linkonce.r.*)

    . = ALIGN(0x4);

} >QUADSPI

/* Un comment this section to place fonts and text in external flash*/

 FontFlashSection :

{

*(FontFlashSection FontFlashSection.*)

*(.gnu.linkonce.r.*)

    . = ALIGN(0x4);

} >QUADSPI

 TextFlashSection :

{

*(TextFlashSection TextFlashSection.*)

*(.gnu.linkonce.r.*)

    . = ALIGN(0x4);

} >QUADSPI

}

and

hqspi.Instance = QUADSPI;

hqspi.Init.ClockPrescaler = 1;

hqspi.Init.FifoThreshold = 4;

hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;

hqspi.Init.FlashSize = 24;

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 */

BSP_QSPI_Init();

BSP_QSPI_MemoryMappedMode();

HAL_NVIC_DisableIRQ(QUADSPI_IRQn);

MPU_Region_InitTypeDef MPU_InitStruct;

MPU_InitStruct.Enable = MPU_REGION_ENABLE;

MPU_InitStruct.BaseAddress = 0x90000000;

MPU_InitStruct.Size = MPU_REGION_SIZE_256MB;

MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;

MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;

MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;

MPU_InitStruct.Number = MPU_REGION_NUMBER2;

MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;

MPU_InitStruct.SubRegionDisable = 0x00;

MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);

/* Configure the MPU attributes as WT for QSPI (used 16Mbytes) */

MPU_InitStruct.Enable = MPU_REGION_ENABLE;

MPU_InitStruct.BaseAddress = 0x90000000;

MPU_InitStruct.Size = MPU_REGION_SIZE_16MB; /* NOTE! Change this if you change QSPI flash size! */

MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;

MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;

MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;

MPU_InitStruct.Number = MPU_REGION_NUMBER3;

MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;

MPU_InitStruct.SubRegionDisable = 0x00;

MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);

HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

But checking memory on "Memory details", FontFlashSection and TextFlashSection are still on internal flash.

This is my pin configuration

0690X00000AqeX9QAJ.png

And the pin mentioned on video "PI12"

And Still having black screen on debug.

A pair of things I have saw

* debug gets stuck for a long time on 93% after gets to main waiting for press button run.

* If something is modified and then genereded code; the first lines of configuration on QUADSPI init function are showed.

I hope this information give you a clue of what is wrong with my example project.

Finally I use four images as background some animated images buttons and texts

Oscar_Niño
Associate II
October 24, 2019

Hi everyone

Thanks for support, I have a working project. I did everything again and know my prototype is working. The only thing I could think is "some days ago my ide was updated and my project was been created by old version" so maybe this could be the error.

Yugenthar
Associate III
May 10, 2023

Hai bro Still I am working in QSPI concept in stm32f746 disco board

I tried to write the data for QSPI flash memory but I can't able to write and read the QSPI flash memory i need your help bro i have attached my code and snap pls find and give any sollution are example code
_legacyfs_online_stmicro_images_0693W00000bjmI1QAI.png

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "quadspi.h"
#include "gpio.h"
 
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
 
/* USER CODE END Includes */
 
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
uint8_t *writebuf = "Hello world from QSPI !";
 
uint8_t readbuf[100];
 
uint16_t number = 1234;
uint8_t buf[5];
/* USER CODE END PTD */
 
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
 
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
typedef void (*pFunction)(void);
pFunction JumpToApplication;
 
#define APPLICATION_ADDRESS 0x90000000
/* USER CODE END PM */
 
/* Private variables ---------------------------------------------------------*/
 
/* USER CODE BEGIN PV */
 
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
 
/* USER CODE END 0 */
 
/**
 * @brief The application entry point.
 * @retval int
 */
int main(void)
{
 /* USER CODE BEGIN 1 */
 
 /* USER CODE END 1 */
 
 /* 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 */
 
 /* USER CODE END Init */
 
 /* Configure the system clock */
 SystemClock_Config();
 
 /* USER CODE BEGIN SysInit */
 
 /* USER CODE END SysInit */
 
 /* Initialize all configured peripherals */
 MX_GPIO_Init();
 MX_QUADSPI_Init();
 /* USER CODE BEGIN 2 */
 
 if (CSP_QUADSPI_Init() != HAL_OK)
 {
 	 Error_Handler();
 }
 
 
 /****************** FOR SIMPLE WRITE READ ********************/
 	// Comment out these if you are using the EXT MEM BOOT
 
 if (CSP_QSPI_Erase_Chip() != HAL_OK)
 {
 	 Error_Handler();
 }
 
 
 sprintf (buf, "%u", number);
 if (CSP_QSPI_Write(buf, 0, strlen (buf)) != HAL_OK)
 {
 	 Error_Handler();
 }
 
 
 if (CSP_QSPI_Read(readbuf, 0, 100) != HAL_OK)
 {
 	 Error_Handler();
 }
 
 /*************************************************/
 
 
 /*********************** FOR EXT MEM BOOT *************************/
 	// Comment out these if you are using the simple Read Write
 
 if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK)
 {
 	 Error_Handler();
 }
 
 
 // Disable the cache
 SCB_DisableDCache();
 SCB_DisableICache();
 
 
 // Disable the systick interrupt
 SysTick->CTRL = 0;
 
 
 /* Initialize user application's Stack Pointer & Jump to user application */
 JumpToApplication = (pFunction) (*(__IO uint32_t*) (APPLICATION_ADDRESS + 4)); // Reset Handler
 __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS); // stack pointer
 JumpToApplication();	 // make the jump

HP_it
HP_itAuthor
Senior II
May 10, 2023

did you follow the video guide?

you should add the QSPI memory area to your linker script and configure the QSPI using the CUBE view - be aware that the default settings does not work - you need to adjust the timings for your specific chip.

if you are on the disco board you can just copy all the settings from a default tGFX demo but if you have made your own board you will need to find the timings in the appropriate datasheet.

Furthermore you need to include the memory mapped read/write functions - I took them from the discovery board codebase.

It should be in the video almost all of it.