Snapshot with STM32

Unable to Save Snapshot

I’ve been working with LVGL for a few months now and I’ve got to say it’s extremely well documented which has made my life really easy.
In the project I’m working on, I’m supposed to take a snapshot of the screen when we press a particular button. I read the blog by @beibean.
But i’m unable to get a screenshot. I’m sure it’s something on my end. I don’t have any experience with Binary files and am kinda new to this, so might have made some stupid mistake.
It’d be great if you could help me figure out how the functions get called and how it gets saved.

What MCU/Processor/Board and compiler are you using?

STM32L4R5 and STM32CubeIDE

What LVGL version are you using?

v7.2.0

What do you want to achieve?

Save the snapshot of the screen as a image file.

What have you tried so far?

I’ve created a callback function that is called whenever we want to take a snapshot. I’ve also created a function that writes every pixel received form VDB to file and one that converts the pixel to the required format, as mentioned in the blog.

Thanks in Advance.

Anny

What TFT are you using?
This is how I achieve screen capture with F429ZI, IL9341, Arduino and MCUFRIEND_kbv library:

void sd_screen_capture() {
	char filename[14];
	unsigned int index = 0;
	do  {
		sprintf(filename, "%08d.data", ++index);
	} while (fat.exists(filename));
	Serial.print("Save ");
	Serial.print(filename);
	uint16_t* pixels = (uint16_t*)malloc(sizeof(uint16_t) * tft.width());
	if (pixels) {
		SdFile file;
		if (file.open(filename, O_CREAT | O_RDWR)) {
			for (int y = 0; y < tft.height(); ++y) {
				tft.readGRAM(0, y, pixels, tft.width(), 1);
				file.write(pixels, sizeof(uint16_t) * tft.width());
			}
		}
		file.close();
	} else {
		Serial.println(" failed");
	}
	free(pixels);
	Serial.println(" done");
}

I read directly from TFT memory.
Then I use GIMP to convert image from RGB565 to PNG.

I have based my screenshot code upon that blog post too. What I ended up doing is:

  1. Open a stream for writing
  2. Write a 122 bytes BMP fileheader, describing the pixelformat
  3. Temporarily swap the flush_cb
  4. Invalidate the screen
  5. Capture the refreshes to the file also and also update the TFT
  6. Set back the original flush_cb
  7. Close the file
/** Take Screenshot.
 * Flush buffer into a binary file.
 * @note: data pixel should be formated to uint16_t RGB as set by Bitmap header.
 * @param[in] pFileName   Output binary file name.
 **/
void guiTakeScreenshot(const char * pFileName)
{
    uint8_t header[128];
    gui_get_bitmap_header(header, sizeof(header));

    pFileOut = HASP_FS.open(pFileName, "w"); // 1. Open a stream for writing
    if(pFileOut) {

        size_t len = pFileOut.write(header, 122);
        if(len == 122) {
            // 2. Write a 122 bytes BMP fileheader, describing the pixelformat
            Log.verbose(TAG_GUI, F("Bitmap header written"));

            // 3. Temporarily swap the flush_cb
            /* Get current callback */
            lv_disp_t * disp = lv_disp_get_default();
            void (*flush_cb)(struct _disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
            flush_cb              = disp->driver.flush_cb; /* store callback */
            /* Set the screenshot callback */
            disp->driver.flush_cb = gui_screenshot_to_file;

            /* 4. Refresh screen to call the screenshot callback */
            lv_obj_invalidate(lv_scr_act());
            /* 5. Captures the refreshes to the stream, also also update the tft */
            lv_refr_now(NULL);

            /* 6. Restore callback */
            disp->driver.flush_cb = flush_cb; /* restore callback */

            Log.verbose(TAG_GUI, F("Bitmap data flushed to %s"), pFileName);

        } else {
            Log.error(TAG_GUI, F("Data written does not match header size"));
        }
        pFileOut.close(); // 7. Close file

    } else {
        Log.warning(TAG_GUI, F("%s cannot be opened"), pFileName);
    }
}

This is the outline of the code, the actual implementation for gui_get_bitmap_header and gui_screenshot_to_file can be found on my github.

This can also be used with a httpClient, so the screenshot can be sent to a web browser as .bmp without converting any pixels. The BMP header describes the pixel format, so any application should be able to read it.

I have used this method to output the screen on STM32F407 to a webclient over ethernet.

Thanks a lot

It’s a 240 x 320. This one to be precise - NHD-2.4-240320SF-CTXI#-F1. I’m unable to attach the link. idk why.

Is this a part of every ST library? I’m using an STM32L4R5.

Your code seems pretty clear to me but I can’t try it out on the board until Monday. Sorry for that, I’ll get back to you as soon as I do it.

Thanks a lot. :slight_smile:

Hey,
Thanks a lot for this solution.

I went through your Github Repo and implemented something similar on Codeblocks. Everything seems fine but I’m getting an error when I try and convert the Binary file to JPG using any online convertor. Any idea why? If it seems stupid, please spare with me, I’m extremely new to all this.

Thank You :slight_smile:

From this datasheet it seems to be an IL9341.
readGRAM function is part of the MCUFRIEND_kbv library for Arduino.
I am pretty sure that you have the same function with the driver from ST library.