‎2019-12-07 08:23 PM
I have setup the board using CUBEMX 5.4.0 and firmware 7.15 for the board. I have followed the steps indicated in this post below.
https://touchgfx.zendesk.com/hc/en-us/articles/360020208091-Configuring-STM32F769I-DISCO
I have no idea on how to add QSPI support to the linker as indicated in the post. The post has instructions for KEIL but I am using CUBEIDE. All I get is snow on the LCD screen of the discovery board. Could the linker file be my problem in this case? If so, can someone point me to instrucitons on how to add QSPI support in the linker for this board?
Thanks
‎2019-12-11 05:30 AM
If you were to simply add a box to your initial screen then it would not require QSPI - Can you display something as simple as that?
‎2019-12-12 07:48 AM
I have copied one of the demonstration linker files for Flash and made the changes to my file. The display improved but not yet ok. The touchgfx screen ( a simple colored box and a button) does not display. The display is garbled somewhat. The code goes into an infinite loop apparently from a watchdog interrupt. I have not traced the calling event for it.
‎2019-12-12 01:53 PM
Displaying stuff is not a problem when QSPI is not required. For example, displaying simple boxes, lines and text on the screen is fine with BSP drivers.
‎2019-12-12 02:07 PM
I totally did not thank you in the first place for taking the time to responding to my note. Thanks again and apologies. As to clarifying my previous reply: I can use the board with no problem using only BSP drivers. I have not tested that extensively (e.g. making lots of graphics) but seems to work well. I want to be able to use TGFX to create a GUI using this processor but at the same time, I only use cubeide or sw4stm32. Cubemx does not provide support for QSPI when the project is created. The link above shows how to add this support and change the hw config files to use it. Most of it is ok except the part of the linker file :-). I copied the differences between my cubeIDE flash file and the flash file from one of the demonstrations and the image on the display improved but still very garbled and seemingly misoriented. Anyways, if you have more insight, it will be appreciated if you could share it. @Martin KJELDSEN​ Thanks in advance and keep up the good work.
‎2019-12-13 02:48 AM
No need to apologize =)
CubeMX has no knowledge of the QSPI chip you're using so you need to write some additional code to set it up and put it into memory mapped mode. We use a section reference in our code called ExtFlashSection. You also need to map your QSPI region and place the ExtFlashSection in this region.
Example gcc linker script:
MEMORY
{
QUADSPI (r) : ORIGIN = 0x90000000, LENGTH = 16M
}
...
SECTIONS
{
....
ExtFlashSection :
{
*(ExtFlashSection ExtFlashSection.*)
*(.gnu.linkonce.r.*)
. = ALIGN(0x4);
} >QUADSPI
}
And here's the QSPI init code for F746G-DISCO as example - Notice the user code section:
/**
* @brief QUADSPI Initialization Function
* @param None
* @retval None
*/
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;
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);
/* USER CODE END QUADSPI_Init 2 */
}
‎2019-12-13 04:39 AM
Once again, thank you very much. I am definitely missing the QSP user code in my project. My linker project, albeit a bit different, is close to what you have posted. It seems I have failed to provide for it in the code. I will try this tonight and see how it goes. I placed a copy of my linker script file below for reference. Thanks again
/*
*****************************************************************************
**
** File : LinkerScript.ld
**
** Abstract : Linker script for STM32F769NIHx Device with
** 2048KByte FLASH, 512KByte RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
** (c)Copyright Ac6.
** You may use this file as-is or modify it according to the needs of your
** project. Distribution of this file (unmodified or modified) is not
** permitted. Ac6 permit registered System Workbench for MCU users the
** rights to distribute the assembled, compiled & linked contents of this
** file as part of an application binary file, provided that it is built
** using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20080000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0xFA0; /* required amount of heap */
_Min_Stack_Size = 0x2000; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K
RAM (xrw) : ORIGIN = 0x20020000, LENGTH = 384K
CCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
QSPI (rx) : ORIGIN = 0x90000000, LENGTH = 64M
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
_siccmram = LOADADDR(.ccmram);
/* CCM-RAM section
*
* IMPORTANT NOTE!
* If initialized variables will be placed in this section,
* the startup code needs to be modified to copy the init-values.
*/
.ccmram :
{
. = ALIGN(4);
_sccmram = .; /* create a global symbol at ccmram start */
*(.ccmram)
*(.ccmram*)
. = ALIGN(4);
_eccmram = .; /* create a global symbol at ccmram end */
} >CCMRAM AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
ExtFlashSection : { *(ExtFlashSection) } >QSPI
}
‎2019-12-13 04:43 AM
Okay, let me know how it goes. Good luck!
/Martin
‎2019-12-24 03:54 PM
Hello again Martin, Merry Christmas. I finally got the board running. I started a new project and slowly discovered that the touchgfx init function in the BoardConfiguration.cpp file erroneously lists 400 as the width of the display. Similarly, the command size in the DSI_Init function in one of those files, also lists erroneously 400 as its setting. Now I have the screen fully displaying without any issues. Also, note that I have made no provisions for QSPI in this new method (i.e., there is no code for QSPI in my main.cpp file as you have shown for the 746 disco. That said, my animations are very weird. I have a fade effect attached to a widget and whenever I activate it, the screen gets fragmented until the animation is finished. I wonder if this is due to the QSPI code missing in my main file. I do have the tear effect settings set up. For now I am glad that I have a display that works. Thanks in advance for any help and if you dont get this before then, Merry Christmas and Happy New Year.