cancel
Showing results for 
Search instead for 
Did you mean: 

Saving data in QSPI Flash | STM32F469i-DISCO

MFOWE
Associate II

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

15 REPLIES 15

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
Chief III

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

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
Up vote any posts that you find helpful, it shows what's working..
MFOWE
Associate II

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 ?

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
Up vote any posts that you find helpful, it shows what's working..
HP
Senior III

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
Associate II

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.

>>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
Up vote any posts that you find helpful, it shows what's working..
MFOWE
Associate II

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 ?