cancel
Showing results for 
Search instead for 
Did you mean: 

Asking for help with drawing custom image from data that is generated during runtime

TeaForJoy
Associate

Hello, I am new to the touchgfx GUI generation. I am working on a simple touchscreen based thermal camera using an MLX sensor. I would like to draw the thermal image on to the screen of my STM32H750B-dk board.

I thought of doing it via an dynamic bitmap by running an rtos task for comunication with the sensor, taking the measured temperature data and converting it to RGB565 equivalent bitmap, by simply scaling the measured data from min to max in a 0-255 scale which then goes to a color pallet lookup table.

This way I get an RGB565 pixel color for each sensor pixel. I am sending the addres of the first pixel since the pixels are stored in an array which I am then storing in vector since the Touchgfx sreenView is code in cpp.

Now comes the problem I can not get the Bitmap::dynamicBitmapcreate(w,h,Bitmap::format); to return a valid BitmapId. I tried following many tutorials and solutions to similar problems with creating the required cache but whenever I try to assaign the cacheAddress to anywhre other than 0x0...0 the screen crashes and remains white. The program is running (I have some status LED for the sensor comunication) but the screen remains blank. if I use the 0x0...0 address screen get drawn but the BitmapId returned from the dynamicBitmapcreate(..) is invalid.

I tried creating the cache via an "global" array, forced address in both ram, flash and SDRAM in touchGFXHAL.cpp to no avail.

I am truly getting desperate so I apreciate any and all responses.

 

1 ACCEPTED SOLUTION

Accepted Solutions
JTP1
Lead

Hello

You probably have allready check this documentation

https://support.touchgfx.com/docs/development/ui-development/touchgfx-engine-features/dynamic-bitmaps

I made some simple test with STM32F769I-DISCO board, it worked pretty much straight away (in simulator and in target board).

Screen1 contains normal image widget called image1 and then button1. Button1 fills the dynamic bitmap with some random color.

FrontendApplication.cpp:

#include <gui/common/FrontendApplication.hpp>
#include <touchgfx/Bitmap.hpp>

FrontendApplication::FrontendApplication(Model& m, FrontendHeap& heap)
    : FrontendApplicationBase(m, heap)
{
#ifdef SIMULATOR
    const uint32_t cacheSize = 0x100000; //1 MB, as example
    uint16_t* const cacheStartAddr = (uint16_t*)malloc(cacheSize);
    Bitmap::setCache(cacheStartAddr, cacheSize, 4);
#else
    // Place cache start address in SDRAM at address 0xC0200000;
    uint16_t* const cacheStartAddr = (uint16_t*)0xC0200000;
    const uint32_t cacheSize = 0x100000; //1 MB, as example
    Bitmap::setCache(cacheStartAddr, cacheSize, 4);
#endif
}

In STM32H750 SDRAM seems to start at 0xD0000000 so your cache address must be for example 0xD0700000 (last 1 Megabyte block, 8Mbyte total)

 

Screen1view.hpp

#ifndef SCREEN1VIEW_HPP
#define SCREEN1VIEW_HPP

#include <gui_generated/screen1_screen/Screen1ViewBase.hpp>
#include <gui/screen1_screen/Screen1Presenter.hpp>
#include <touchgfx/Bitmap.hpp>

class Screen1View : public Screen1ViewBase
{
public:
    Screen1View();
    virtual ~Screen1View() {}
    virtual void setupScreen();
    virtual void tearDownScreen();
	virtual void button1Clicked();

	BitmapId bmpId;
	//Set dynamic bitmap of size 
    const uint32_t dynamicBitmapWidth = 100;
    const uint32_t dynamicBitmapHeight = 150;
protected:
};

#endif // SCREEN1VIEW_HPP

Screen1View.cpp

#include <gui/screen1_screen/Screen1View.hpp>
#include <string.h> // memset
#include <stdlib.h> // rand

Screen1View::Screen1View()
{

}

void Screen1View::setupScreen()
{
    uint16_t *cache_ptr;
    uint32_t i;
    Screen1ViewBase::setupScreen();
	
    bmpId = Bitmap::dynamicBitmapCreate(dynamicBitmapWidth, dynamicBitmapHeight, Bitmap::RGB565);
    
	// some random color pattern
	cache_ptr=(uint16_t *)Bitmap::dynamicBitmapGetAddress(bmpId);
	for(i=0;i<dynamicBitmapWidth*dynamicBitmapHeight;i++)
	{
		*cache_ptr=i>>3;
		cache_ptr++;
	}
	
	/*
	//or set all pixels some color
    if (bmpId != BITMAP_INVALID)
    {
       memset((uint16_t *) Bitmap::dynamicBitmapGetAddress(bmpId), 0x0F, width*height*2);
    }
	*/

    //Make Image widget show the dynamic bitmap
    image1.setBitmap(Bitmap(bmpId));

    //Position image and add to View
    image1.setXY(20, 20);
}

void Screen1View::tearDownScreen()
{
    Screen1ViewBase::tearDownScreen();
}

void Screen1View::button1Clicked()
{
	uint16_t *cache_ptr;
	uint32_t i;
	uint16_t value;
	
	// put some random color if button is pressed:
	// rand give 32767 max so its needed to do 2 times 8 bit
	value=rand()%256;
	value<<=8;
	value|=rand()%256;
	
	cache_ptr=(uint16_t *)Bitmap::dynamicBitmapGetAddress(bmpId);
	for(i=0;i<dynamicBitmapWidth*dynamicBitmapHeight;i++)
	{
		*cache_ptr=value;
		cache_ptr++;
	}
	// once the bitmap is set, only invalidate of image is needed.
	image1.invalidate();
}

 Hope this helps you :thumbs_up:

Br JTP

View solution in original post

3 REPLIES 3
JTP1
Lead

Hello

You probably have allready check this documentation

https://support.touchgfx.com/docs/development/ui-development/touchgfx-engine-features/dynamic-bitmaps

I made some simple test with STM32F769I-DISCO board, it worked pretty much straight away (in simulator and in target board).

Screen1 contains normal image widget called image1 and then button1. Button1 fills the dynamic bitmap with some random color.

FrontendApplication.cpp:

#include <gui/common/FrontendApplication.hpp>
#include <touchgfx/Bitmap.hpp>

FrontendApplication::FrontendApplication(Model& m, FrontendHeap& heap)
    : FrontendApplicationBase(m, heap)
{
#ifdef SIMULATOR
    const uint32_t cacheSize = 0x100000; //1 MB, as example
    uint16_t* const cacheStartAddr = (uint16_t*)malloc(cacheSize);
    Bitmap::setCache(cacheStartAddr, cacheSize, 4);
#else
    // Place cache start address in SDRAM at address 0xC0200000;
    uint16_t* const cacheStartAddr = (uint16_t*)0xC0200000;
    const uint32_t cacheSize = 0x100000; //1 MB, as example
    Bitmap::setCache(cacheStartAddr, cacheSize, 4);
#endif
}

In STM32H750 SDRAM seems to start at 0xD0000000 so your cache address must be for example 0xD0700000 (last 1 Megabyte block, 8Mbyte total)

 

Screen1view.hpp

#ifndef SCREEN1VIEW_HPP
#define SCREEN1VIEW_HPP

#include <gui_generated/screen1_screen/Screen1ViewBase.hpp>
#include <gui/screen1_screen/Screen1Presenter.hpp>
#include <touchgfx/Bitmap.hpp>

class Screen1View : public Screen1ViewBase
{
public:
    Screen1View();
    virtual ~Screen1View() {}
    virtual void setupScreen();
    virtual void tearDownScreen();
	virtual void button1Clicked();

	BitmapId bmpId;
	//Set dynamic bitmap of size 
    const uint32_t dynamicBitmapWidth = 100;
    const uint32_t dynamicBitmapHeight = 150;
protected:
};

#endif // SCREEN1VIEW_HPP

Screen1View.cpp

#include <gui/screen1_screen/Screen1View.hpp>
#include <string.h> // memset
#include <stdlib.h> // rand

Screen1View::Screen1View()
{

}

void Screen1View::setupScreen()
{
    uint16_t *cache_ptr;
    uint32_t i;
    Screen1ViewBase::setupScreen();
	
    bmpId = Bitmap::dynamicBitmapCreate(dynamicBitmapWidth, dynamicBitmapHeight, Bitmap::RGB565);
    
	// some random color pattern
	cache_ptr=(uint16_t *)Bitmap::dynamicBitmapGetAddress(bmpId);
	for(i=0;i<dynamicBitmapWidth*dynamicBitmapHeight;i++)
	{
		*cache_ptr=i>>3;
		cache_ptr++;
	}
	
	/*
	//or set all pixels some color
    if (bmpId != BITMAP_INVALID)
    {
       memset((uint16_t *) Bitmap::dynamicBitmapGetAddress(bmpId), 0x0F, width*height*2);
    }
	*/

    //Make Image widget show the dynamic bitmap
    image1.setBitmap(Bitmap(bmpId));

    //Position image and add to View
    image1.setXY(20, 20);
}

void Screen1View::tearDownScreen()
{
    Screen1ViewBase::tearDownScreen();
}

void Screen1View::button1Clicked()
{
	uint16_t *cache_ptr;
	uint32_t i;
	uint16_t value;
	
	// put some random color if button is pressed:
	// rand give 32767 max so its needed to do 2 times 8 bit
	value=rand()%256;
	value<<=8;
	value|=rand()%256;
	
	cache_ptr=(uint16_t *)Bitmap::dynamicBitmapGetAddress(bmpId);
	for(i=0;i<dynamicBitmapWidth*dynamicBitmapHeight;i++)
	{
		*cache_ptr=value;
		cache_ptr++;
	}
	// once the bitmap is set, only invalidate of image is needed.
	image1.invalidate();
}

 Hope this helps you :thumbs_up:

Br JTP

Wow it works now thank you very much looks like I forgot to call Bitmap(bmpId) for image.setBitmap(...) and instead I was just passing the bmpId *facepalm* I spent so much time looking for faults. Also it looks like my aproach of allocating the cache from touchGFXHAL.cpp was the wrong way to do this.

Again thank you very much for your time and help with this problem.

Good to hear. There certainly can be more sophisticated way to allocate cache-area, i was just following the documentation example :grinning_face_with_sweat: