2020-12-10 10:33 AM - edited 2023-10-04 03:23 AM
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.
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
or use the external ST-LINK app with this set
2020-12-10 12:40 PM
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.
2020-12-10 01:09 PM
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 ?
2020-12-10 01:15 PM
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
2020-12-10 01:58 PM
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
2020-12-10 10:47 PM
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
2020-12-10 11:07 PM
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 ?
2020-12-10 11:07 PM
I am developping STM32 apps on Winwdos system.