cancel
Showing results for 
Search instead for 
Did you mean: 

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

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 

 

 

7 REPLIES 7

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

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 ?

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

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

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

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 ?

I am developping STM32 apps on Winwdos system.