Skip to main content
MFOWE
Associate
October 2, 2019
Question

Saving data in QSPI Flash | STM32F469i-DISCO

  • October 2, 2019
  • 15 replies
  • 6076 views

Hello,

I'm a total beginner and I'm looking to store some user data in the QSPI Flash,, but I don't really know how to proceed can you help me ?

First, I changed the flash memory size in the .ld file from 16M to 12M so that TouchGFX won't overwrite my data. But from now, I don't know what to do...

How can I write and read to this 'allocated' space ?

Thanks

This topic has been closed for replies.

15 replies

waclawek.jan
Super User
October 2, 2019

Maybe start with reading the QSPI chapter in the 'F469's Reference Manual, and also reading the DS of the QSPI FLASH chip.

JW

Martin KJELDSEN
Principal III
October 2, 2019

Hi @MFOWE​,

As an example, if you're working with the STM32F469i-DISCO board you'll have the following BSP file that can help you interact with the QSPI: bsp\include\vendor\STM32469I-Discovery\stm32469i_discovery_qspi.h - It defines the methods:

uint8_t BSP_QSPI_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size)
 
HAL_StatusTypeDef HAL_QSPI_MemoryMapped(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_MemoryMappedTypeDef *cfg)

Use BSP_QSPI_Write to write to a specific address and HAL_QSPI_MemoryMapped to take the QSPI in and out of memory mapped mode.

/Martin

Tesla DeLorean
Guru
October 2, 2019

https://www.st.com/content/ccc/resource/technical/document/application_note/group0/b0/7e/46/a8/5e/c1/48/01/DM00227538/files/DM00227538.pdf/jcr:content/translations/en.DM00227538.pdf

In memory mapped mode it accesses like normal memory, ie pointers / structures, etc.

In the linker script you could split it into two or more distinct regions, and then direct code/data to those sections via attribute directives or #pragma

You could also leave it as one region, and let the linker deal with the placement and interleaving with other data.

The QSPI is written using an External Loader (tailored to board/chip) via ST-LINK Utilities or STM32 Cube Programmer, or equivalent in your chosen tool-chain.

Perhaps review chapters for compiler/linker related to linker scripts, or scatter files. Not sure the underlying technicalities are STM32 or QSPI specific.

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

I did not believe that here on ST forum is anyone who really helps. I would like to thank you for this, hope more people will answer like you!

MFOWE
MFOWEAuthor
Associate
October 2, 2019

Thank you guys for your different propositions, I had checked the documentation beforehand but it didn't help me...

I have a view in my application where the user can move a slider and the value of this slider is sent to the model so that it is saved when the user leaves the view.

How can I use BSP_QSPI_Write, BSP_QSPI_Read and HAL_QSPI_MemoryMapped ? Do I have to implement them in model.h or in my view ?

Would you happen to have a really basic example of an application programming data in the QSPI flash that would help me understand ?

Tesla DeLorean
Guru
October 2, 2019

STM32Cube_FW_F4_V1.24.1\Projects\STM32469I-Discovery\Examples\QSPI\QSPI_ExecuteInPlace\Src\main.c

STM32Cube_FW_F4_V1.24.1\Projects\STM32469I-Discovery\Examples\BSP\Src\qspi.c

STM32Cube_FW_F4_V1.24.1\Drivers\BSP\STM32469I-Discovery\stm32469i_discovery_qspi.c

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

I would implement another task to handle the information coming from the model.

if you have another task update the state variables of the model you can divide the program into two parts

  1. the graphics where the model can get and set the state variables
  2. the hardware interaction where you can store or load the state variables.

If you create a state variable struct you could pass that object back and forth through a RTOS queue and assign a static storage space in the QSPI memory space.

MFOWE
MFOWEAuthor
Associate
October 4, 2019

Hello,

It's me again, I read every single piece of documentation that I could lay my hands on and I tried to implement your ideas but I am lacking of skill, so I am coming back with the hope of resolving my issues.

So, to start from the beginning :

  • I modified the linker file to allow some non-overwritable space for the user data :
application.ld
.
.
.
MEMORY
{
 CODE (rx) : ORIGIN = 0x08000000, LENGTH = 2048K
 RAM (rw) : ORIGIN = 0x20000000, LENGTH = 320K
 CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
	/* QSPI reduced from 16M (16384KB) to 12M (12288KB) */
	/* Using 192 sectors out of 256*/
	/* 64 sectors free for the user data starting at 0x90000000 */
	/* ORIGIN moved from 0x90000000 to 903FFFFF + 1 */
	/* See memory map (p.22) datasheet (MT25Q_QLHS) */
 QUADSPI (r) : ORIGIN = 0x90400000, LENGTH = 12M
}
.
.
.
  • I then included 'stm32469i_discovery_qspi.h' to my 'Model.hpp' and here comes the issues :

at first I tried to implement BSP_QSPI_Write, BSP_QSPI_Read and HAL_QSPI_MemoryMapped to write, read and allow flash memory modification but I couldn't get it to work. I may have succeded to read something programmed in the flash memory but that's it.

Here is an extract of my Model.hpp :

Model.hpp
.
.
.
#include <stm32469i_discovery_qspi.h>
...
class Model
{
public:
 Model();
...
	// Saving pH values for alert setting
	void saveValAlert_pH_High(uint8_t save_pH_H)
	{
		valAlert_pH_Haut = save_pH_H; // Saves it locally in the volatile memory
 
	}
...
	// Returns the values of pH stored for the alert settings
	uint8_t getValAlert_pH_Haut()
	{
 BSP_QSPI_Read(&valAlert_pH_Haut, 0x90000000, 8);
		return valAlert_pH_Haut; // Returns it from the non-volatile memory ( QSPI Flash )
 
	}
...
 
protected:
	// Variables pour l'alerte PH
	uint8_t valAlert_pH_H;
...
};
.
.
.

So now I have multiple questions :

Am I really reading what I want to read ? ( 8 bits of data stored, starting at 0x90000000 )

How can I write to this adress ?

I read that the data has first to be erased, then the flash has to be passed from memory mapped mode to indirect mode, then written, then back to memory mapped.

You gave me all the bricks but I don't know how to use them..

Also, final noob question for now :

I coudn't manage to get the simulator to run because I had to manually change too many files paths ( for the different #include, one leads to another one which leads to another one, and another one...) but still it compiled OK on the MCU. And I think that the reading was done because accessing the data reducing the frame refresh rate (but then again I could be mistaking and the change of refresh rate has nothing to do with the acess to the QSPI Flash memory).

So, is there a way to have it to work on the simulator without having to manually change paths ?

Thank you sincerely again guys for you efforts.

Tesla DeLorean
Guru
October 5, 2019

>>BSP_QSPI_Read(&valAlert_pH_Haut, 0x90000000, 8);

You've selected 8 bytes, not 8 bits

The address in this context is zero, as you're talking to the memory device directly, rather than mapped into the address space of the STM32

BSP_QSPI_Read(&valAlert_pH_Haut, 0, 1); // One byte at the beginning of the device.

To write data, you can write up to 256 in a page, so if you are 128 bytes into the page you can write the next 128 bytes.

The memory can be written once, technically it can be written until all the bits are zero. You can erase larger sectors, and this gets all the bit to a high state (one)

BSP_QSPI_Erase_Block(0); // Sub-Sector on the F469-DISCO 4KB ie 0x000000..0x000FFF

BSP_QSPI_Write(&valAlert_pH_Haut, 0, 1); // One byte at the beginning of the device.

One might consider putting all your data into a structure, and read/write a copy of that.

If you want it to appear in the memory space at 0x90000000 use

BSP_QSPI_EnableMemoryMappedMode();

printf("%02X BYTE\n", *((uint8_t *)0x90000000) ); // print the byte for valAlert_pH_Haut you wrote, or 0xFF erased

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

I cannot run the simulation when including 'stm32469i_discovery_qspi.h' in my Model.hpp. Is there a solution to that ?

and @Community member​ , you told me about 'BSP_QSPI_EnableMemoryMappedMode()' but if I am not mistaking, the QSPI is already in the Memory Mapped Mode because it is used by touchGFX to load images. So in order to write, I would have to deactivate the memory mapped mode in order to write at 0x90000000 or ( at 0), right ?

HP_it
Senior II
October 6, 2019

I'm not sure it will help but I did a video on how to include the QSPI into cubeIDE while running TouchGFX: https://www.youtube.com/watch?v=237lPdMsDZs

also, you might want to have a look at how the framebuffer is created. it's located at the start of the SDRAM memory space which should be available in the same way as the QSPI memory:

static uint32_t frameBuf0 = (uint32_t)(0xc0000000);

then you have the address of the memory and you could use that as a pointer to your data.. I hope :)

L4Y
Associate II
October 12, 2019

Hi, @MFOWE​ ,

Since you are using the TouchGFX application Template, the QSPI flash is initialized in memory-mapped mode, so in your model class, you have to do the following to save data to QSPI flash.

  1. Deinit QSPI interface. I'm not sure if it has BSP interface to disable memory-mapped mode, but in my experience, it doesn't have.
  2. Init QSPI interface. Now you are in indirect mode.
  3. Call BSP interfaces to write data to flash, like BSP_QSPI_erase(); BSP_QSPI_write().
  4. After you saving data, you have to enable memory-mapped mode again to ensure TouchGFX works.

But actually I don't recommend to save date in QSPI flash when using TouchGFX. It should work fine when you write to the flash in TouchGFX task. But when you write data to the flash in other tasks, you have to do some tricky to avoid system crash.

Best Regards.