My program takes images from SD one by one and shows it in GUI.
For reading SD I use FAT FS library. SD connected to controller by SDIO.
I tried two approaches - with WM and without it.
My LCD glass has size 320x240, and I show BMP images that have size 300x225 and 16bpp.
So, one line of such image requires 600B.
Everything works fine, (images loads, and displays on LCD) except emWin's memory management.
Every time program changes picture it consumes irreversible 612B of allocated for GUI memory (checked by GUI_ALLOC_GetNumFreeBytes()).
Nothing can restore memory - I tried GUI_Clear, GUI_ClearRect. In case of WM: WM_InvalidateWindow, WM_DeleteWindow, WM_Deactivate, WM_SetCallback(dialog, 0).
I tried this program under RTOS and without it with the same result.
My code for get data function:
static int _GetData(void * p, const U8 ** ppData, unsigned NumBytesReq, U32 Offset) {
unsigned int NumBytesRead;
// if (NumBytesReq > sizeof(_acBuffer)) //Check buffer size in case of static buffer
// NumBytesReq = sizeof(_acBuffer);
taskENTER_CRITICAL(); //Prevent the possibility to break SD read process
// osThreadSetPriority(ImgCyclerHandle, osPriorityRealtime); //Prevent the possibility to break SD read process - other approach
f_lseek((FIL *) p, Offset); //Set file pointer to the required position
f_read((FIL *) p, (void *) _acBuffer, NumBytesReq, &NumBytesRead); //Read data into buffer
// osThreadSetPriority(ImgCyclerHandle, osPriorityNormal); //Restore GUI thread priority
taskEXIT_CRITICAL();
*ppData = (const U8 *) _acBuffer; //Set pointer to the buffer
return NumBytesRead;
}
Function that demonstrate images:
void Show_img_from_SD(TCHAR const* img_name) {
_acBuffer = (U8*) calloc(BYTES_IN_LINE, sizeof(U8));
/*Register the file system object to the FatFs module*/
/*
* param 1 Pointer to the file system object (NULL:unmount)
* param 2 Logical drive number to be mounted/unmounted
* param 3 0:Do not mount (delayed mount), 1:Mount immediately
*/
if (f_mount(&fileSystem, (TCHAR const*) SD_Path, 0) == FR_OK) {
/*Open file image with read access*/
/*
* param 1 Pointer to the blank file object
* param 2 Pointer to the file name
* param 3 Access mode and file open mode flags
*/
res = f_open(&ImgFile, img_name, FA_OPEN_EXISTING | FA_READ);
if (res == FR_OK)
GUI_BMP_DrawEx(_GetData, &ImgFile, 0, 0);
f_close(&ImgFile);
}
f_mount(NULL, (TCHAR const*) SD_Path, 0);
free(_acBuffer);
}
RTOS thread looks like:
void Img_cycler_thread(void const * argument) {
uint8_t img_counter = 0;
GUI_DispStringAt("Free GUI mem.:", 0, 225);
GUI_DispStringAt("Img. num.:", 230, 225);
for (;;) {
GUI_Clear();
GUI_ClearRect(0,0, XSIZE_PHYS, YSIZE_PHYS);
Show_img_from_SD("10_300x225_16bpp.bmp");
GUI_DispDecAt((I32) GUI_ALLOC_GetNumFreeBytes(), 90, 225, 6);
img_counter++;
GUI_DispDecAt((I32) img_counter, 300, 225, 3);
osDelay(500); //let other threads to work
GUI_Clear();
GUI_ClearRect(0,0, XSIZE_PHYS, YSIZE_PHYS);
Show_img_from_SD("9_300x225_16bpp.bmp");
GUI_DispDecAt((I32) GUI_ALLOC_GetNumFreeBytes(), 90, 225, 6);
img_counter++;
GUI_DispDecAt((I32) img_counter, 300, 225, 3);
osDelay(500); //let other threads to work
}
}
Memory allocated for emWin:
#define GUI_NUMBYTES (20*1024)
--
After 23-th cycle, GUI runs out of memory and ceases to show images, but touch still working. GUI not halts.
Full projects (version with RTOS and whithout) you can take here:
yadi.sk/d/yuOcpdoAvnNZ9
In case of WM my key functions looks like:
void Load_image_WM(WM_HWIN image, TCHAR const* img_name) {
_acBuffer = (U8*) calloc(BYTES_IN_LINE, sizeof(U8));
if (f_mount(&fileSystem, (TCHAR const*) SD_Path, 1) == FR_OK) { //mount drive
res = f_open(&ImgFile, img_name, FA_OPEN_EXISTING | FA_READ); //open file
if (res == FR_OK)
IMAGE_SetBMPEx(image, _GetData, &ImgFile); //pump file to LCD
// f_close(&ImgFile);
}
// f_mount(NULL, (TCHAR const*) SD_Path, 0);
free(_acBuffer);
}
static const GUI_WIDGET_CREATE_INFO Main_Window_DialogCreate[] = {
{ WINDOW_CreateIndirect, "Window", 0x1000,
0, 0,
WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0x0, 0 },
{ IMAGE_CreateIndirect, "Image", GUI_ID_IMAGE0,
0, 0,
IMAGE_WIDTH, IMAGE_HEIGHT,
0, 0, 0 } };
void WIDGETS_Callback(WM_MESSAGE * pMsg) { //Custom callback function
switch (pMsg->MsgId) {
case WM_INIT_DIALOG:
image = WM_GetDialogItem(pMsg->hWin, GUI_ID_IMAGE0);
Load_image_WM(image, img_name);
break;
case WM_DELETE:
WM_Invalidate(image);
//... there was many other functions, I tried different approaches
break;
default:
WM_DefaultProc(pMsg);
}
}
WM_HWIN Create_img_dialog(TCHAR const* img_name_input) {
GUI_Clear(); //clear screen for the beginning
#if GUI_SUPPORT_MEMDEV
WM_SetCreateFlags(WM_CF_MEMDEV);
#endif
img_name = img_name_input;
WM_HWIN dialog = GUI_CreateDialogBox(Main_Window_DialogCreate, GUI_COUNTOF(Main_Window_DialogCreate), WIDGETS_Callback, WM_HBKWIN, 0, 0);
return dialog;
}
Implementation in thread:
void Img_cycler_thread_WM(void const * argument) {
WM_HWIN dialog;
dialog = Create_img_dialog("9_300x225_16bpp.bmp");
for (;;)
{
GUI_ClearRect(0,0, XSIZE_PHYS, YSIZE_PHYS);
Load_image_WM(image, "7_300x225_16bpp.bmp");
osDelay(500); //let other threads to work
WM_Update(dialog);
GUI_ClearRect(0,0, XSIZE_PHYS, YSIZE_PHYS);
Load_image_WM(image, "8_300x225_16bpp.bmp");
osDelay(500); //let other threads to work
WM_Update(dialog);
// dialog = Create_img_dialog("9_300x225_16bpp.bmp");
// osDelay(500); //let other threads to work
// WM_SetCallback(dialog, 0);
// WM_InvalidateWindow(dialog);
// WM_DeleteWindow(dialog);
// WM_Deactivate();
// GUI_Clear();
//
// GUI_DispDecAt((I32) GUI_ALLOC_GetNumFreeBytes(), 0, 225, 6);
// GUI_DispDecAt((I32) GUI_ALLOC_GetNumUsedBytes(), 60, 225, 6);
//
// dialog = Create_img_dialog("10_300x225_16bpp.bmp");
// osDelay(500); //let other threads to work
// WM_SetCallback(dialog, 0);
// WM_InvalidateWindow(dialog);
// WM_DeleteWindow(dialog);
// WM_Deactivate();
// GUI_Clear();
//
// GUI_DispDecAt((I32) GUI_ALLOC_GetNumFreeBytes(), 0, 225, 6);
// GUI_DispDecAt((I32) GUI_ALLOC_GetNumUsedBytes(), 60, 225, 6);
}
}
Implementation without RTOS:
WM_HWIN dialog;
dialog = Create_img_dialog("9_300x225_16bpp.bmp");
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
GUI_Exec();
GUI_TOUCH_Exec();
Load_image_WM(image, "7_300x225_16bpp.bmp");
HAL_Delay(500);
WM_Update(dialog);
Load_image_WM(image, "8_300x225_16bpp.bmp");
HAL_Delay(500);
WM_Update(dialog);
}
/* USER CODE END 3 */
}
----
I have pretty little hope for help, writing this post.
Last time I appealed to this forum, support engineer Til, just tried to pick me on some details in my code and makes demagogy about commercial relationships.
For reading SD I use FAT FS library. SD connected to controller by SDIO.
I tried two approaches - with WM and without it.
My LCD glass has size 320x240, and I show BMP images that have size 300x225 and 16bpp.
So, one line of such image requires 600B.
Everything works fine, (images loads, and displays on LCD) except emWin's memory management.
Every time program changes picture it consumes irreversible 612B of allocated for GUI memory (checked by GUI_ALLOC_GetNumFreeBytes()).
Nothing can restore memory - I tried GUI_Clear, GUI_ClearRect. In case of WM: WM_InvalidateWindow, WM_DeleteWindow, WM_Deactivate, WM_SetCallback(dialog, 0).
I tried this program under RTOS and without it with the same result.
My code for get data function:
static int _GetData(void * p, const U8 ** ppData, unsigned NumBytesReq, U32 Offset) {
unsigned int NumBytesRead;
// if (NumBytesReq > sizeof(_acBuffer)) //Check buffer size in case of static buffer
// NumBytesReq = sizeof(_acBuffer);
taskENTER_CRITICAL(); //Prevent the possibility to break SD read process
// osThreadSetPriority(ImgCyclerHandle, osPriorityRealtime); //Prevent the possibility to break SD read process - other approach
f_lseek((FIL *) p, Offset); //Set file pointer to the required position
f_read((FIL *) p, (void *) _acBuffer, NumBytesReq, &NumBytesRead); //Read data into buffer
// osThreadSetPriority(ImgCyclerHandle, osPriorityNormal); //Restore GUI thread priority
taskEXIT_CRITICAL();
*ppData = (const U8 *) _acBuffer; //Set pointer to the buffer
return NumBytesRead;
}
Function that demonstrate images:
void Show_img_from_SD(TCHAR const* img_name) {
_acBuffer = (U8*) calloc(BYTES_IN_LINE, sizeof(U8));
/*Register the file system object to the FatFs module*/
/*
* param 1 Pointer to the file system object (NULL:unmount)
* param 2 Logical drive number to be mounted/unmounted
* param 3 0:Do not mount (delayed mount), 1:Mount immediately
*/
if (f_mount(&fileSystem, (TCHAR const*) SD_Path, 0) == FR_OK) {
/*Open file image with read access*/
/*
* param 1 Pointer to the blank file object
* param 2 Pointer to the file name
* param 3 Access mode and file open mode flags
*/
res = f_open(&ImgFile, img_name, FA_OPEN_EXISTING | FA_READ);
if (res == FR_OK)
GUI_BMP_DrawEx(_GetData, &ImgFile, 0, 0);
f_close(&ImgFile);
}
f_mount(NULL, (TCHAR const*) SD_Path, 0);
free(_acBuffer);
}
RTOS thread looks like:
void Img_cycler_thread(void const * argument) {
uint8_t img_counter = 0;
GUI_DispStringAt("Free GUI mem.:", 0, 225);
GUI_DispStringAt("Img. num.:", 230, 225);
for (;;) {
GUI_Clear();
GUI_ClearRect(0,0, XSIZE_PHYS, YSIZE_PHYS);
Show_img_from_SD("10_300x225_16bpp.bmp");
GUI_DispDecAt((I32) GUI_ALLOC_GetNumFreeBytes(), 90, 225, 6);
img_counter++;
GUI_DispDecAt((I32) img_counter, 300, 225, 3);
osDelay(500); //let other threads to work
GUI_Clear();
GUI_ClearRect(0,0, XSIZE_PHYS, YSIZE_PHYS);
Show_img_from_SD("9_300x225_16bpp.bmp");
GUI_DispDecAt((I32) GUI_ALLOC_GetNumFreeBytes(), 90, 225, 6);
img_counter++;
GUI_DispDecAt((I32) img_counter, 300, 225, 3);
osDelay(500); //let other threads to work
}
}
Memory allocated for emWin:
#define GUI_NUMBYTES (20*1024)
--
After 23-th cycle, GUI runs out of memory and ceases to show images, but touch still working. GUI not halts.
Full projects (version with RTOS and whithout) you can take here:
yadi.sk/d/yuOcpdoAvnNZ9
In case of WM my key functions looks like:
void Load_image_WM(WM_HWIN image, TCHAR const* img_name) {
_acBuffer = (U8*) calloc(BYTES_IN_LINE, sizeof(U8));
if (f_mount(&fileSystem, (TCHAR const*) SD_Path, 1) == FR_OK) { //mount drive
res = f_open(&ImgFile, img_name, FA_OPEN_EXISTING | FA_READ); //open file
if (res == FR_OK)
IMAGE_SetBMPEx(image, _GetData, &ImgFile); //pump file to LCD
// f_close(&ImgFile);
}
// f_mount(NULL, (TCHAR const*) SD_Path, 0);
free(_acBuffer);
}
static const GUI_WIDGET_CREATE_INFO Main_Window_DialogCreate[] = {
{ WINDOW_CreateIndirect, "Window", 0x1000,
0, 0,
WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0x0, 0 },
{ IMAGE_CreateIndirect, "Image", GUI_ID_IMAGE0,
0, 0,
IMAGE_WIDTH, IMAGE_HEIGHT,
0, 0, 0 } };
void WIDGETS_Callback(WM_MESSAGE * pMsg) { //Custom callback function
switch (pMsg->MsgId) {
case WM_INIT_DIALOG:
image = WM_GetDialogItem(pMsg->hWin, GUI_ID_IMAGE0);
Load_image_WM(image, img_name);
break;
case WM_DELETE:
WM_Invalidate(image);
//... there was many other functions, I tried different approaches
break;
default:
WM_DefaultProc(pMsg);
}
}
WM_HWIN Create_img_dialog(TCHAR const* img_name_input) {
GUI_Clear(); //clear screen for the beginning
#if GUI_SUPPORT_MEMDEV
WM_SetCreateFlags(WM_CF_MEMDEV);
#endif
img_name = img_name_input;
WM_HWIN dialog = GUI_CreateDialogBox(Main_Window_DialogCreate, GUI_COUNTOF(Main_Window_DialogCreate), WIDGETS_Callback, WM_HBKWIN, 0, 0);
return dialog;
}
Implementation in thread:
void Img_cycler_thread_WM(void const * argument) {
WM_HWIN dialog;
dialog = Create_img_dialog("9_300x225_16bpp.bmp");
for (;;)
{
GUI_ClearRect(0,0, XSIZE_PHYS, YSIZE_PHYS);
Load_image_WM(image, "7_300x225_16bpp.bmp");
osDelay(500); //let other threads to work
WM_Update(dialog);
GUI_ClearRect(0,0, XSIZE_PHYS, YSIZE_PHYS);
Load_image_WM(image, "8_300x225_16bpp.bmp");
osDelay(500); //let other threads to work
WM_Update(dialog);
// dialog = Create_img_dialog("9_300x225_16bpp.bmp");
// osDelay(500); //let other threads to work
// WM_SetCallback(dialog, 0);
// WM_InvalidateWindow(dialog);
// WM_DeleteWindow(dialog);
// WM_Deactivate();
// GUI_Clear();
//
// GUI_DispDecAt((I32) GUI_ALLOC_GetNumFreeBytes(), 0, 225, 6);
// GUI_DispDecAt((I32) GUI_ALLOC_GetNumUsedBytes(), 60, 225, 6);
//
// dialog = Create_img_dialog("10_300x225_16bpp.bmp");
// osDelay(500); //let other threads to work
// WM_SetCallback(dialog, 0);
// WM_InvalidateWindow(dialog);
// WM_DeleteWindow(dialog);
// WM_Deactivate();
// GUI_Clear();
//
// GUI_DispDecAt((I32) GUI_ALLOC_GetNumFreeBytes(), 0, 225, 6);
// GUI_DispDecAt((I32) GUI_ALLOC_GetNumUsedBytes(), 60, 225, 6);
}
}
Implementation without RTOS:
WM_HWIN dialog;
dialog = Create_img_dialog("9_300x225_16bpp.bmp");
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
GUI_Exec();
GUI_TOUCH_Exec();
Load_image_WM(image, "7_300x225_16bpp.bmp");
HAL_Delay(500);
WM_Update(dialog);
Load_image_WM(image, "8_300x225_16bpp.bmp");
HAL_Delay(500);
WM_Update(dialog);
}
/* USER CODE END 3 */
}
----
I have pretty little hope for help, writing this post.
Last time I appealed to this forum, support engineer Til, just tried to pick me on some details in my code and makes demagogy about commercial relationships.