cancel
Showing results for 
Search instead for 
Did you mean: 

Examples of usage of copyFBRegionToMemory()

scottSD
Senior III

Does anyone know if there is there an example somewhere of usage of the method copyFBRegionToMemory()?

The documentation says that the buffer can be a dynamic bitmap and I am having issues getting my code to compile.

1 ACCEPTED SOLUTION

Accepted Solutions

Hi Scott,

simulator/main.cpp:

uint32_t dynamicBitmapBuffer[1000];
 
...
int main(int argc, char** argv)
{
  ...
  HAL& hal = touchgfx_generic_init<HALSDL2>(dma, lcd, tc, SIM_WIDTH, SIM_HEIGHT, 
  (uint16_t*)dynamicBitmapBuffer, sizeof(dynamicBitmapBuffer), 10);
..

View solution in original post

19 REPLIES 19
Martin KJELDSEN
Chief III

Hi @scottSD​,

Let's start with the documentation:

/**
     * @fn virtual uint16_t* HAL::copyFBRegionToMemory(Rect meAbs);
     *
     * @brief Copies a region of the currently displayed frame buffer to memory.
     *
     *        Copies a region of the currently displayed frame buffer to memory. Used for e.g.
     *        SlideTransition and for displaying pre-rendered drawables
     *        e.g. in animations where redrawing the drawable is not necessary.
     *
     * @note Requires animation storage to be present.
     *
     * @param meAbs The frame buffer region to copy.
     *
     * @return A pointer to the memory address containing the copy of the frame buffer.
     */
    virtual uint16_t* copyFBRegionToMemory(Rect meAbs);
 
    /**
     * @fn virtual uint16_t* HAL::copyFBRegionToMemory(Rect meAbs, uint16_t* dst, uint32_t stride);
     *
     * @brief Copies a region of the currently displayed frame buffer to memory.
     *
     *        Copies a region of the currently displayed frame buffer
     *        to a buffer. Used for e.g.  SlideTransition and for
     *        displaying pre-rendered drawables e.g. in animations
     *        where redrawing the drawable is not necessary. The
     *        buffer can e.g. be a dynamic bitmap.
     *
     * @note Requires animation storage to be present.
     *
     * @param meAbs  The frame buffer region to copy.
     * @param dst    Address of the buffer to store the copy in.
     * @param stride The width of the target buffer (row length).
     *
     * @return A pointer to the memory address containing the copy of the frame buffer.
     */
    virtual uint16_t* copyFBRegionToMemory(Rect meAbs, uint16_t* dst, uint32_t stride);

What these methods can do is copy an area of the currently displayed framebuffer and into a different area of your memory, using DMA2D.

If you use the first option that takes just a Rect as argument, then the "animation storage" will be used. This buffer is allocated after the regular framebuffers and is used for things like animated transitions and SnapShotWidget (which also uses copyFBRegionToMemory).

/**
     * @fn virtual void HAL::setFrameBufferStartAddress(void* adr, uint16_t depth = 16, bool useDoubleBuffering = true, bool useAnimationStorage = true)
     *
     * @brief Sets the address used for frame buffers, usually located in external memory.
     *
     *        Sets the address used for frame buffers, usually located in external memory. Will
     *        reserve memory for one or two frame buffers based on display size. Will optionally
     *        also reserve memory for a third frame buffer used for animationStorage.
     *
     * @param [in] adr                 Starting address to use for frame buffers.
     * @param      depth               (Optional) Depth of each pixel in bits, default is 16.
     * @param      useDoubleBuffering  (Optional) If true, reserve memory for an extra frame buffer.
     * @param      useAnimationStorage (Optional) If true, reserve memory for animation storage.
     *
     * @deprecated Use the setFramaBufferStartAddress with 'format' parameter instead of 'depth'
     */
    virtual void setFrameBufferStartAddress(void* adr, uint16_t depth = 16, bool useDoubleBuffering = true, bool useAnimationStorage = true)

If you use the second version of copyFBRegionToMemory, you can decide where in memory to copy the data to. You could then feed this memory area to a DynamicBitmap to create an image based on the current contents of the framebuffer.

So the uses are generally:

  • SnapShotWidget (built in)
  • Screen Transitions (built in)
  • If you want to copy part of (using Rect) the current frame and wish to story this in memory. Use with DynamicBitmap to turn this into an actual image that can do everything a normal image can (drag, etc).

  

Best regards,

/Martin

Thanks for your reply Martin.

I have seen this documentation (reason I was wondering if there was an example).

Also, I did see the utilization of the copyFBRegionToMemory() in the file PreRenderable.hpp.

I have tried both methods and both appear to crash the simulator. I setup a very simple project for the STM32H750-Discovery board. All it has on it is one screen with a black box.

I placed the following code in the screen's setupScreen() method:

void Screen1View::setupScreen()
{
  Screen1ViewBase::setupScreen();
  touchgfx::Rect r(0, 0, 10, 10);
  uint16_t* adr;
  touchgfx_printf("before copyFBRegionToMemory()\n");
  adr = HAL::getInstance()->copyFBRegionToMemory(r);
  touchgfx_printf("after copyFBRegionToMemory() adr: %0x\n", adr);
}
 

The console output never prints before "copyFBRegionToMemory()" but appears to crash because the simulator screen remains white and the console window never prints "after copyFBRegionToMemory()".

0690X00000AAIZkQAP.png

Am I doing something wrong?

Hi, you can't actually use the method directly like that in the simulator because it bypasses the check for whether or not the DMA has the capability (Simulator uses NoDMA), and still tries to add blitops to the DMA queue, so it's basically just busy waiting when you call that method. You should be able to see the effects on target, though.

/Martin

Oh, and copyFBRegionToMemory() taking a Rect as argument will simply return the address of the animation storage.

And...

uint16_t* HAL::copyFBRegionToMemory(Rect r, uint16_t* dst, uint32_t dst_stride);

Will simply return dst;

/Martin

Take a look at how SnapShotWidget works. You'll see that it actually creates a dynamic bitmap for you based on the memory region you provided as argument (By going through the LCD class associated with HAL). and returns a pointer to the data for the dynamic bitmap.

I think this is more along the lines of what you want. The LCD class calls the functions located in HAL for you.

/Martin

Thanks Martin.

I really appreciate the feedback. I will get this figured out eventually :smirking_face:

SnapShotWidget is just the example I was looking for. I found the source code for it. FYI, I did notice that the following link says to "See this article for further information on using SnapShotWidget" but there is no actual link there:

https://touchgfx.zendesk.com/hc/en-us/articles/205452611-Animation-storage?mobile_site=true

Regardless, I was able to get a copy from a region of the frame buffer to a dynamic bmp and place the contents of that dynamic bmp into an image widget at another location of the screen.

This works on the simulator but does not on my STM32H750-Discovery board.

I added a couple of buttons to the screen. One that copies a region of the frame buffer to the dynamic bmp and places this in an image on the screen. The other button sets the image's bitmap to a "red" bitmap from the bitmap data base. Both of these operations work fine on the simulator, but only the setting of the image to the red bitmap works on the Discovery board. I have included a portion of my code below.

void Screen1View::setupScreen()
{
    Screen1ViewBase::setupScreen();
    image.setBitmap(Bitmap(BITMAP_GREENAREA_100X100_ID));
    image.setXY(210, 0);
    add(image);
    image.invalidate();
}
 
void Screen1View::tearDownScreen()
{
    Screen1ViewBase::tearDownScreen();
}
 
void Screen1View::CopyFB()
{
   touchgfx_printf("CopyFB\n");
 
   if (bmpId != BITMAP_INVALID)
   {
      Bitmap::dynamicBitmapDelete(bmpId);
   }
   bmpId = Bitmap::dynamicBitmapCreate(100, 100, Bitmap::RGB888);
   if (bmpId != BITMAP_INVALID)
   {
      touchgfx::Rect rect(0, 0, 100, 100);
 
      HAL::lcd().copyFrameBufferRegionToMemory(rect, bmpId);
      image.setBitmap(Bitmap(bmpId));
      image.invalidate();
   }
}
 
void Screen1View::UseRedImg()
{
   touchgfx_printf("UseRedImg\n");
   image.setBitmap(Bitmap(BITMAP_REDAREA_100X100_ID));
   image.invalidate();
}

I verified that when on the discovery board, dynamicBitmapCreate() is returning a bmp ID of BITMAP_INVALID. The documentation for dynamicBitmapCreate() states:

"BitmapId of the new bitmap or BITMAP_INVALID if memory full."

Is the amount of memory used on the simulator setup differently than that used on the Discovery board (note that I started with a Blank UI template)?

I found the following TouchGFX article which explains that memory needs to be configured for dynamic bitmaps. This would explain why I was getting a BITMAP_INVALID.

https://touchgfx.zendesk.com/hc/en-us/articles/207460605

The article sets up bmpCache, but this is for a different board than I am using.

Yeah, i forgot to mention that you need to allocate a bitmap cache.

What's different for you?

/Martin

uint8_t cache[w*h*(bpp/2)];
 
...
 
 HAL& hal = touchgfx_generic_init<MyHal>(dma, lcd, tc, SIM_WIDTH, SIM_HEIGHT, (uint16_t*)cache, sizeof(cache), 1);