Skip to main content
Ciuffoly
Senior
December 10, 2020
Question

[SOLVED] Very simple method to use the QSPI N25Q128A to store the application bitmaps

  • December 10, 2020
  • 4 replies
  • 2722 views

At this time I am developing a graphic touch screen application on STN32F746-DISCO.

This is a very simple method to store the bitmaps on QSPI N25Q128A in order to save flash space.

I have used the lcd-image-converter.exe to convert the bitmap files to a bitmap structure to pass to BSP_LCD_DrawBitmap().

Here the settings used for cd-image-converter.exe.

 

0693W000006FZaIQAW.png0693W000006FZaNQAW.png0693W000006FZaSQAW.png0693W000006FZaXQAW.png 

Here the logo.h file generated 

#ifndef logo_H_
#define logo_H_
 
#include <stdint.h>
 
// struct packing, pragma for GCC !!!
#pragma pack(push, 1)
 
typedef struct logo_tagBITMAPFILEHEADER {
 uint16_t bfType;
 uint32_t bfSize;
 uint16_t bfReserved1;
 uint16_t bfReserved2;
 uint32_t bfOffBits;
} logo_BITMAPFILEHEADER; // size is 14 bytes
 
typedef struct logo_tagBITMAPINFOHEADER {
 uint32_t biSize;
 uint32_t biWidth;
 uint32_t biHeight;
 uint16_t biPlanes;
 uint16_t biBitCount;
 uint32_t biCompression;
 uint32_t biSizeImage;
 uint32_t biXPelsPerMeter;
 uint32_t biYPelsPerMeter;
 uint32_t biClrUsed;
 uint32_t biClrImportant;
} logo_BITMAPINFOHEADER; // size is 40 bytes
 
typedef struct logo_tag_Struct {
 // offset 0, size 14
 logo_BITMAPFILEHEADER fileHeader;
 // offset 14, size 40
 logo_BITMAPINFOHEADER infoHeader;
 // offset 54, size 51600 words
 uint16_t data[51600];
} logo_Struct;
 
const logo_Struct logo = {
 {
 0x4d42u,
 sizeof(logo_BITMAPINFOHEADER) + sizeof(logo_BITMAPFILEHEADER) + (51600 * 2),
 0x0000u,
 0x0000u,
 sizeof(logo_BITMAPINFOHEADER) + sizeof(logo_BITMAPFILEHEADER)
 },
 {
 sizeof(logo_BITMAPINFOHEADER),
 400,
 129,
 1u,
 16,
 0x00000003u,
 (51600 * 2),
 0x00000000ul,
 0x00000000ul,
 0x00000000ul,
 0x00000000ul
 },
 {
 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, .....
}
};
 
 
 
// struct packing, pragma for GCC !!!
#pragma pack (pop)
 
#endif /* settings1_H_ */

Here the logo.h file modified by hand to use the QSPI

 

#include <stdint.h>
 
// struct packing, pragma for GCC !!!
#pragma pack(push, 1)
 
typedef struct logo_tagBITMAPFILEHEADER {
 uint16_t bfType;
 uint32_t bfSize;
 uint16_t bfReserved1;
 uint16_t bfReserved2;
 uint32_t bfOffBits;
} logo_BITMAPFILEHEADER; // size is 14 bytes
 
typedef struct logo_tagBITMAPINFOHEADER {
 uint32_t biSize;
 uint32_t biWidth;
 uint32_t biHeight;
 uint16_t biPlanes;
 uint16_t biBitCount;
 uint32_t biCompression;
 uint32_t biSizeImage;
 uint32_t biXPelsPerMeter;
 uint32_t biYPelsPerMeter;
 uint32_t biClrUsed;
 uint32_t biClrImportant;
} logo_BITMAPINFOHEADER; // size is 40 bytes
 
typedef struct logo_tag_Struct {
 // offset 0, size 14
 logo_BITMAPFILEHEADER fileHeader;
 // offset 14, size 40
 logo_BITMAPINFOHEADER infoHeader;
 // offset 54, size 51600 words
 uint16_t data[51600];
} logo_Struct;
 
 
#ifndef IMG_NO_DATA
#if defined ( __ICCARM__ )
#pragma location = ".textqspi"
#else
__attribute__((section(".textqspi")))
#endif
 
const logo_Struct logo = {
 {
 0x4d42u,
 sizeof(logo_BITMAPINFOHEADER) + sizeof(logo_BITMAPFILEHEADER) + (51600 * 2),
 0x0000u,
 0x0000u,
 sizeof(logo_BITMAPINFOHEADER) + sizeof(logo_BITMAPFILEHEADER)
 },
 {
 sizeof(logo_BITMAPINFOHEADER),
 400,
 129,
 1u,
 16,
 0x00000003u,
 (51600 * 2),
 0x00000000ul,
 0x00000000ul,
 0x00000000ul,
 0x00000000ul
 },
 {
 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, .....
}
};
 
#else
 
extern const logo_Struct logo;
 
#endif
 
 // struct packing, pragma for GCC !!!
#pragma pack (pop)
 

create in the project a main_image.c file with only these lines

 

 
#include "logo.h"
 
void dummy_init (void);
 
void dummy_init (void)
{
 
 
 
}

in your main.c use these lines

 



#define IMG_NO_DATA
#include "logo.h"


QSPI_HandleTypeDef hqspi;   hqspi.Instance = QUADSPI; hqspi.Init.ClockPrescaler = 255; hqspi.Init.FifoThreshold = 1; hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE; hqspi.Init.FlashSize = 1; hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_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(); }   int status = BSP_QSPI_Init();   if (status == QSPI_NOT_SUPPORTED) { BSP_LCD_DisplayStringAt(20, 10, (uint8_t*)"QSPI Initialization : FAILED.", LEFT_MODE); } else if (status == QSPI_ERROR) { BSP_LCD_DisplayStringAt(20, 10, (uint8_t*)"QSPI Initialization : FAILED.", LEFT_MODE); } else { BSP_LCD_DisplayStringAt(20, 10, (uint8_t*)"QSPI Initialization : OK.", LEFT_MODE); }   BSP_QSPI_MemoryMappedMode();


to display image use:

  BSP_LCD_DrawBitmap(1, 1, (uint8_t *)(&logo));

 

modify the file STM32F746NGHx_FLASH.ld in the CubeWorkspace

 

MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 307K
QSPI (xrw) : ORIGIN = 0x90000000, LENGTH = 16M <<<<<<<< add this
Memory_B1(xrw) : ORIGIN = 0x2004C000, LENGTH = 0x80
Memory_B2(xrw) : ORIGIN = 0x2004C080, LENGTH = 0x80
Memory_B3(xrw) : ORIGIN = 0x2004C100, LENGTH = 0x17d0 
Memory_B4(xrw) : ORIGIN = 0x2004D8D0, LENGTH = 0x17d0
}
 
/* Define output sections */
SECTIONS
{
 /* The startup code goes first into FLASH */
 .isr_vector :
 {
 . = ALIGN(4);
 KEEP(*(.isr_vector)) /* Startup code */
 . = ALIGN(4);
 } >FLASH
 
 .textqspi : <<<<<<<<<<<<<<<<<<<<< add this section
 {
 . = ALIGN(4);
 _qspi_start = .; /* create a global symbol at qspi start */
 *(.textqspi) /* .textqspi sections */
 *(.textqspi*) /* .textqspi* sections */
 . = ALIGN(4);
 _qspi_end = .; /* define a global symbols at end of textqspi */
 
 } >QSPI 
 
 ...................
 
 
 .ARM.attributes 0 : { *(.ARM.attributes) }
 .textqspi : { *(.textqspi) } >QSPI <<<<<<<<<<<<<<<< add this
 .RxDecripSection : { *(.RxDescripSection) } >Memory_B1
 .TxDescripSection : { *(.TxDescripSection) } >Memory_B2
 .RxarraySection : { *(.RxBUF) } >Memory_B3
 .TxarraySection : { *(.TxBUF) } >Memory_B4 
}
 

Install ST-Link Server and set these options in Project/Properties/Run-Debug section

 

0693W000006FZbLQAW.pngor use the external ST-LINK app with this set

 

0693W000006FZbaQAG.png 

 

 

This topic has been closed for replies.

4 replies

Tesla DeLorean
Guru
December 10, 2020

The underlying concepts aren't that complicated.

You are responsible for bringing up the pins and the interface, and then mapping the memory into the STM32's memory space.

The code to achieve this is in the BSP code. For different hardware you'd have to build support.

On the tools side you need to tell the linker about the QSPI memory space in the linker script (.LD)

On the source side you'd need to direct content into the QSPI sections using the __attribute__() directive.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Ciuffoly
CiuffolyAuthor
Senior
December 10, 2020

Yes, but which is the menu option on CubeWorkspace IDE ?

and can I store directly the my struct eam_lab_logo2 (my image bmp) or I need to convert this in unsigned char ?

Tesla DeLorean
Guru
December 10, 2020

Anything that can be placed in FLASH currently can be migrated to QSPI.

You need to initialize the QSPI before you use any code that touches those arrays/structures.

Sorry not using CubeIDE, use GNU/GCC here from the command line with make

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Ciuffoly
CiuffolyAuthor
Senior
December 11, 2020

clive1, I don't like this complex interface like the CubeWorkspace and I am using command line gcc on linux system without problems but what I need to download to use command line gcc to create STM32 binary ?

Could you share a simple makefile to see which options to use ?

Ciuffoly
CiuffolyAuthor
Senior
December 10, 2020

This run on the QSPI example but only for simple array

#ifndef IMG_NO_DATA
 
#if defined ( __ICCARM__ )
#pragma location = ".textqspi"
#else
__attribute__((section(".textqspi")))
#endif
 
const unsigned char img2[100000] = "PIPPO";
 
#else
 
extern const unsigned char img2[];
 
#endif

Ciuffoly
CiuffolyAuthor
Senior
December 11, 2020

Is this correct to initialize the QSPI ? I see an increment of QSPI space only for the unsigned char array and not for the data in the structure.

#ifndef IMG_NO_DATA
 
#if defined ( __ICCARM__ )
 
#pragma location = ".textqspi"
#else
__attribute__((section(".textqspi")))
#endif
 
const unsigned char img2[120000] = "PIPPO";
 
typedef struct logo_tagBITMAPFILEHEADER {
 uint16_t bfType;
 uint32_t bfSize;
 uint16_t bfReserved1;
 uint16_t bfReserved2;
 uint32_t bfOffBits;
} logo_BITMAPFILEHEADER; // size is 14 bytes
 
typedef struct logo_tagBITMAPINFOHEADER {
 uint32_t biSize;
 uint32_t biWidth;
 uint32_t biHeight;
 uint16_t biPlanes;
 uint16_t biBitCount;
 uint32_t biCompression;
 uint32_t biSizeImage;
 uint32_t biXPelsPerMeter;
 uint32_t biYPelsPerMeter;
 uint32_t biClrUsed;
 uint32_t biClrImportant;
} logo_BITMAPINFOHEADER; // size is 40 bytes
 
typedef struct logo_tag_Struct {
 // offset 0, size 14
 logo_BITMAPFILEHEADER fileHeader;
 // offset 14, size 40
 logo_BITMAPINFOHEADER infoHeader;
 // offset 54, size 51600 words
 uint16_t data[51600];
} logo_Struct;
 
const logo_Struct logo = {
 {
 0x4d42u,
 sizeof(logo_BITMAPINFOHEADER) + sizeof(eam_lab_logo2_BITMAPFILEHEADER) + (51600 * 2),
 0x0000u,
 0x0000u,
 sizeof(logo_BITMAPINFOHEADER) + sizeof(eam_lab_logo2_BITMAPFILEHEADER)
 },
 {
 sizeof(logo_BITMAPINFOHEADER),
 400,
 129,
 1u,
 16,
 0x00000003u,
 (51600 * 2),
 0x00000000ul,
 0x00000000ul,
 0x00000000ul,
 0x00000000ul
 },
 {
 0xffff, 0xffff, 0xffff, 0xffff, 0xfff, .......
}
};
 
#else
 
#pragma pack(push, 1)
 
extern const logo_Struct logo;
 
extern const unsigned char img2[];
 
#pragma pack (pop)
 
#endif